@@ -229,7 +229,7 @@ static int prepend_unreachable(char **buffer, int *buflen)
return prepend(buffer, buflen, "(unreachable)", 13);
}
-static void get_fs_root_rcu(struct fs_struct *fs, struct path *root)
+void get_fs_root_rcu(struct fs_struct *fs, struct path *root)
{
unsigned seq;
@@ -252,6 +252,13 @@ static int fsinfo_generic_seq_read(struct path *path, struct fsinfo_context *ctx
ret = sb->s_op->show_options(&m, path->mnt->mnt_root);
break;
+ case FSINFO_ATTR_MOUNT_PATH:
+ if (sb->s_op->show_path)
+ ret = sb->s_op->show_path(&m, path->mnt->mnt_root);
+ else
+ seq_dentry(&m, path->mnt->mnt_root, " \t\n\\");
+ break;
+
case FSINFO_ATTR_FS_STATISTICS:
if (sb->s_op->show_stats)
ret = sb->s_op->show_stats(&m, path->mnt->mnt_root);
@@ -282,6 +289,11 @@ static const struct fsinfo_attribute fsinfo_common_attributes[] = {
FSINFO_LIST (FSINFO_ATTR_FSINFO_ATTRIBUTES, (void *)123UL),
FSINFO_VSTRUCT_N(FSINFO_ATTR_FSINFO_ATTRIBUTE_INFO, (void *)123UL),
+
+ FSINFO_VSTRUCT (FSINFO_ATTR_MOUNT_INFO, fsinfo_generic_mount_info),
+ FSINFO_STRING (FSINFO_ATTR_MOUNT_PATH, fsinfo_generic_seq_read),
+ FSINFO_STRING (FSINFO_ATTR_MOUNT_POINT, fsinfo_generic_mount_point),
+ FSINFO_STRING (FSINFO_ATTR_MOUNT_POINT_FULL, fsinfo_generic_mount_point_full),
{}
};
@@ -15,6 +15,7 @@ struct mount;
struct shrink_control;
struct fs_context;
struct user_namespace;
+struct fsinfo_context;
/*
* block_dev.c
@@ -46,6 +47,11 @@ extern int __block_write_begin_int(struct page *page, loff_t pos, unsigned len,
*/
extern void __init chrdev_init(void);
+/*
+ * d_path.c
+ */
+extern void get_fs_root_rcu(struct fs_struct *fs, struct path *root);
+
/*
* fs_context.c
*/
@@ -91,6 +97,9 @@ extern void __mnt_drop_write_file(struct file *);
extern void dissolve_on_fput(struct vfsmount *);
extern int lookup_mount_object(struct path *, unsigned int, struct path *);
extern int fsinfo_generic_mount_source(struct path *, struct fsinfo_context *);
+extern int fsinfo_generic_mount_info(struct path *, struct fsinfo_context *);
+extern int fsinfo_generic_mount_point(struct path *, struct fsinfo_context *);
+extern int fsinfo_generic_mount_point_full(struct path *, struct fsinfo_context *);
/*
* fs_struct.c
@@ -4265,4 +4265,118 @@ int lookup_mount_object(struct path *root, unsigned int mnt_id, struct path *_mn
goto out_unlock;
}
+/*
+ * Retrieve information about the nominated mount.
+ */
+int fsinfo_generic_mount_info(struct path *path, struct fsinfo_context *ctx)
+{
+ struct fsinfo_mount_info *p = ctx->buffer;
+ struct super_block *sb;
+ struct mount *m;
+ unsigned int flags;
+
+ m = real_mount(path->mnt);
+ sb = m->mnt.mnt_sb;
+
+ p->sb_unique_id = sb->s_unique_id;
+ p->mnt_unique_id = m->mnt_unique_id;
+ p->mnt_id = m->mnt_id;
+
+ flags = READ_ONCE(m->mnt.mnt_flags);
+ if (flags & MNT_READONLY)
+ p->attr |= MOUNT_ATTR_RDONLY;
+ if (flags & MNT_NOSUID)
+ p->attr |= MOUNT_ATTR_NOSUID;
+ if (flags & MNT_NODEV)
+ p->attr |= MOUNT_ATTR_NODEV;
+ if (flags & MNT_NOEXEC)
+ p->attr |= MOUNT_ATTR_NOEXEC;
+ if (flags & MNT_NODIRATIME)
+ p->attr |= MOUNT_ATTR_NODIRATIME;
+
+ if (flags & MNT_NOATIME)
+ p->attr |= MOUNT_ATTR_NOATIME;
+ else if (flags & MNT_RELATIME)
+ p->attr |= MOUNT_ATTR_RELATIME;
+ else
+ p->attr |= MOUNT_ATTR_STRICTATIME;
+ return sizeof(*p);
+}
+
+/*
+ * Return the path of this mount relative to its parent and clipped to
+ * the current chroot.
+ */
+int fsinfo_generic_mount_point(struct path *path, struct fsinfo_context *ctx)
+{
+ struct mountpoint *mp;
+ struct mount *m, *parent;
+ struct path mountpoint, root;
+ void *p;
+
+ rcu_read_lock();
+
+ m = real_mount(path->mnt);
+ parent = m->mnt_parent;
+ if (parent == m)
+ goto skip;
+ mp = READ_ONCE(m->mnt_mp);
+ if (mp)
+ goto found;
+skip:
+ rcu_read_unlock();
+ return -ENODATA;
+
+found:
+ mountpoint.mnt = &parent->mnt;
+ mountpoint.dentry = READ_ONCE(mp->m_dentry);
+
+ get_fs_root_rcu(current->fs, &root);
+ if (path->mnt == root.mnt) {
+ rcu_read_unlock();
+ return fsinfo_string("/", ctx);
+ }
+
+ if (root.mnt != &parent->mnt) {
+ root.mnt = &parent->mnt;
+ root.dentry = parent->mnt.mnt_root;
+ }
+
+ ((char *)ctx->buffer)[ctx->buf_size - 1] = 0;
+ p = __d_path(&mountpoint, &root, ctx->buffer, ctx->buf_size - 1);
+ rcu_read_unlock();
+
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+ if (!p)
+ return -EPERM;
+
+ ctx->skip = p - ctx->buffer;
+ return (ctx->buffer + ctx->buf_size) - p;
+}
+
+/*
+ * Return the path of this mount from the current chroot.
+ */
+int fsinfo_generic_mount_point_full(struct path *path, struct fsinfo_context *ctx)
+{
+ struct path root;
+ void *p;
+
+ ((char *)ctx->buffer)[ctx->buf_size - 1] = 0;
+
+ rcu_read_lock();
+ get_fs_root_rcu(current->fs, &root);
+ p = __d_path(path, &root, ctx->buffer, ctx->buf_size - 1);
+ rcu_read_unlock();
+
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+ if (!p)
+ return -EPERM;
+
+ ctx->skip = p - ctx->buffer;
+ return (ctx->buffer + ctx->buf_size) - p;
+}
+
#endif /* CONFIG_FSINFO */
@@ -31,6 +31,11 @@
#define FSINFO_ATTR_FSINFO_ATTRIBUTE_INFO 0x100 /* Information about attr N (for path) */
#define FSINFO_ATTR_FSINFO_ATTRIBUTES 0x101 /* List of supported attrs (for path) */
+#define FSINFO_ATTR_MOUNT_INFO 0x200 /* Mount object information */
+#define FSINFO_ATTR_MOUNT_PATH 0x201 /* Bind mount/superblock path (string) */
+#define FSINFO_ATTR_MOUNT_POINT 0x202 /* Relative path of mount in parent (string) */
+#define FSINFO_ATTR_MOUNT_POINT_FULL 0x203 /* Absolute path of mount (string) */
+
/*
* Optional fsinfo() parameter structure.
*
@@ -85,6 +90,18 @@ struct fsinfo_u128 {
#endif
};
+/*
+ * Information struct for fsinfo(FSINFO_ATTR_MOUNT_INFO).
+ */
+struct fsinfo_mount_info {
+ __u64 sb_unique_id; /* Kernel-lifetime unique superblock ID */
+ __u64 mnt_unique_id; /* Kernel-lifetime unique mount ID */
+ __u32 mnt_id; /* Mount identifier (use with AT_FSINFO_MOUNTID_PATH) */
+ __u32 attr; /* MOUNT_ATTR_* flags */
+};
+
+#define FSINFO_ATTR_MOUNT_INFO__STRUCT struct fsinfo_mount_info
+
/*
* Information struct for fsinfo(FSINFO_ATTR_STATFS).
* - This gives extended filesystem information.
@@ -294,6 +294,17 @@ static void dump_fsinfo_generic_volume_uuid(void *reply, unsigned int size)
f->uuid[14], f->uuid[15]);
}
+static void dump_fsinfo_generic_mount_info(void *reply, unsigned int size)
+{
+ struct fsinfo_mount_info *r = reply;
+
+ printf("\n");
+ printf("\tsb_uniq : %llx\n", (unsigned long long)r->sb_unique_id);
+ printf("\tmnt_uniq: %llx\n", (unsigned long long)r->mnt_unique_id);
+ printf("\tmnt_id : %x\n", r->mnt_id);
+ printf("\tattr : %x\n", r->attr);
+}
+
static void dump_string(void *reply, unsigned int size)
{
char *s = reply, *p;
@@ -370,6 +381,11 @@ static const struct fsinfo_attribute fsinfo_attributes[] = {
FSINFO_VSTRUCT_N(FSINFO_ATTR_FSINFO_ATTRIBUTE_INFO, fsinfo_meta_attribute_info),
FSINFO_LIST (FSINFO_ATTR_FSINFO_ATTRIBUTES, fsinfo_meta_attributes),
+
+ FSINFO_VSTRUCT (FSINFO_ATTR_MOUNT_INFO, fsinfo_generic_mount_info),
+ FSINFO_STRING (FSINFO_ATTR_MOUNT_PATH, string),
+ FSINFO_STRING_N (FSINFO_ATTR_MOUNT_POINT, string),
+ FSINFO_STRING_N (FSINFO_ATTR_MOUNT_POINT_FULL, string),
{}
};
Allow mount information, including information about a mount object to be queried with the fsinfo() system call. Setting FSINFO_FLAGS_QUERY_MOUNT allows overlapping mounts to be queried by indicating that the syscall should interpret the pathname as a number indicating the mount ID. To this end, a number of fsinfo() attributes are provided: (1) FSINFO_ATTR_MOUNT_INFO. This is a structure providing information about a mount, including: - Mount ID (can be used with FSINFO_FLAGS_QUERY_MOUNT). - Mount uniquifier ID. - Mount attributes (eg. R/O, NOEXEC). - Mount change/notification counters. - Superblock ID. - Superblock change/notification counters. (2) FSINFO_ATTR_MOUNT_PATH. This a string providing information about a bind mount relative the the root that was bound off, though it may get overridden by the filesystem (NFS unconditionally sets it to "/", for example). (3) FSINFO_ATTR_MOUNT_POINT. This is a string indicating the name of the mountpoint within the parent mount, limited to the parent's mounted root and the chroot. (4) FSINFO_ATTR_MOUNT_POINT_FULL. This is a string indicating the full path of the mountpoint, limited to the chroot. Signed-off-by: David Howells <dhowells@redhat.com> --- fs/d_path.c | 2 - fs/fsinfo.c | 12 +++++ fs/internal.h | 9 +++ fs/namespace.c | 114 +++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/fsinfo.h | 17 ++++++ samples/vfs/test-fsinfo.c | 16 ++++++ 6 files changed, 169 insertions(+), 1 deletion(-)