#include "libfrog/getparents.h"
#include "libfrog/paths.h"
#include "libfrog/systemd.h"
+#include "libfrog/statmount.h"
#include "xfs_healer.h"
struct weakhandle {
/* Shared reference to the getmntent fsname for reconnecting */
const char *fsname;
+ /* Mount id for faster reconnecting */
+ uint64_t mnt_id;
+
/* handle to root dir */
void *hanp;
size_t hlen;
weakhandle_alloc(
int fd,
const char *mountpoint,
+ uint64_t mnt_id,
const char *fsname,
struct weakhandle **whp)
{
return -1;
wh->mntpoint = mountpoint;
+ wh->mnt_id = mnt_id;
wh->fsname = fsname;
ret = fd_to_handle(fd, &wh->hanp, &wh->hlen);
struct weakhandle *wh,
int *fd)
{
+ const size_t smbuf_size =
+ libfrog_statmount_sizeof(PATH_MAX);
+ struct statmount *smbuf = alloca(smbuf_size);
FILE *mtab;
struct mntent *mnt;
int ret;
if (!ret)
return 0;
+ /*
+ * The original mountpoint didn't work, which means the mount might
+ * have been moved. Look up the mountpoint for the mount id that we
+ * captured earlier, which is a quick lookup if there are many mounts.
+ * Note that @ret is nonzero here.
+ */
+ ret = libfrog_statmount(wh->mnt_id, DEFAULT_MOUNTNS_FD,
+ STATMOUNT_MNT_POINT, smbuf, smbuf_size);
+ if (ret || !(smbuf->mask & STATMOUNT_MNT_POINT))
+ goto fallback;
+ ret = weakhandle_reopen_from(wh, smbuf->str + smbuf->mnt_point, fd);
+ if (!ret)
+ return 0;
+
+fallback:
/*
* That didn't work, so now walk /proc/mounts to find a mount with the
* same fsname (aka xfs data device path) as when we started.
#include "libfrog/workqueue.h"
#include "libfrog/systemd.h"
#include "libfrog/fsproperties.h"
+#include "libfrog/statmount.h"
#include "xfs_healer.h"
/* Program name; needed for libfrog error reports. */
{
struct mntent *mnt;
FILE *mtp;
- char rpath[PATH_MAX], rmnt_dir[PATH_MAX];
+ const size_t smbuf_size =
+ libfrog_statmount_sizeof(PATH_MAX + 128);
+ struct statmount *smbuf = alloca(smbuf_size);
+ char *rmnt_dir = smbuf->str;
+ char rpath[PATH_MAX];
+ int ret;
if (!realpath(ctx->mntpoint, rpath))
return -1;
+ /*
+ * In Linux 7.0 we can do statmount on an open file, which means that
+ * we can capture the mnt_id, mount point, and fsname, which can help
+ * us find a mount --move'd elsewhere in the directory tree.
+ */
+ ret = libfrog_fstatmount(ctx->mnt.fd, STATMOUNT_MNT_POINT, smbuf,
+ smbuf_size);
+ if (ret || !(smbuf->mask & STATMOUNT_MNT_POINT))
+ goto fallback;
+ if (strcmp(rpath, smbuf->str + smbuf->mnt_point))
+ goto fallback;
+
+ ret = libfrog_fstatmount(ctx->mnt.fd,
+ STATMOUNT_SB_SOURCE | STATMOUNT_MNT_BASIC,
+ smbuf, smbuf_size);
+ if (ret || !(smbuf->mask & STATMOUNT_SB_SOURCE))
+ goto fallback;
+
+ ctx->fsname = strdup(smbuf->str + smbuf->sb_source);
+ if (!ctx->fsname)
+ return -1;
+ ctx->mnt_id = smbuf->mnt_id;
+ return 0;
+
+fallback:
+ /*
+ * If statmount isn't available for whatever reason, fall back to
+ * walking the mount table via getmntent.
+ */
mtp = setmntent(_PATH_PROC_MOUNTS, "r");
if (mtp == NULL)
return -1;
* paths for logging.
*/
if (ctx->want_repair || healer_has_parent(ctx)) {
- ret = weakhandle_alloc(ctx->mnt.fd, ctx->mntpoint,
+ ret = weakhandle_alloc(ctx->mnt.fd, ctx->mntpoint, ctx->mnt_id,
ctx->fsname, &ctx->wh);
if (ret) {
fprintf(stderr, "%s: %s: %s\n", ctx->mntpoint,
/* Shared reference to the getmntent fsname for reconnecting */
const char *fsname;
+ /* Mount id for faster reconnecting */
+ uint64_t mnt_id;
+
/* weak file handle so we can reattach to filesystem */
struct weakhandle *wh;
void run_full_repair(struct healer_ctx *ctx);
/* weakhandle.c */
-int weakhandle_alloc(int fd, const char *mountpoint, const char *fsname,
- struct weakhandle **whp);
+int weakhandle_alloc(int fd, const char *mountpoint, uint64_t mnt_id,
+ const char *fsname, struct weakhandle **whp);
int weakhandle_reopen(struct weakhandle *wh, int *fd);
void weakhandle_free(struct weakhandle **whp);
int weakhandle_getpath_for(struct weakhandle *wh, uint64_t ino, uint32_t gen,