Provide an fsinfo attribute to query the superblock unique ID and notification counter. The unique ID is placed in notification events and the counted it provided so that the changed superblock can be determined in the event of a notification buffer overrun. This is accessed with: struct fsinfo_params params = { .request = FSINFO_ATTR_SB_NOTIFICATIONS, }; and returns a structure that looks like: struct fsinfo_sb_notifications { __u64 watch_id; __u32 notify_counter; __u32 __reserved[1]; }; Where watch_id is a number uniquely identifying the superblock in notification records and notify_counter is incremented for each superblock notification posted. Signed-off-by: David Howells <dhowells@xxxxxxxxxx> --- fs/fsinfo.c | 11 +++++++++++ include/uapi/linux/fsinfo.h | 12 ++++++++++++ include/uapi/linux/watch_queue.h | 2 +- samples/vfs/test-fsinfo.c | 10 ++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/fs/fsinfo.c b/fs/fsinfo.c index e3377842a2c1..4334249339f9 100644 --- a/fs/fsinfo.c +++ b/fs/fsinfo.c @@ -217,6 +217,16 @@ static int fsinfo_generic_volume_id(struct path *path, struct fsinfo_context *ct return fsinfo_string(path->dentry->d_sb->s_id, ctx); } +static int fsinfo_generic_sb_notifications(struct path *path, struct fsinfo_context *ctx) +{ + struct fsinfo_sb_notifications *p = ctx->buffer; + struct super_block *sb = path->dentry->d_sb; + + p->watch_id = sb->s_unique_id; + p->notify_counter = atomic_read(&sb->s_notify_counter); + return sizeof(*p); +} + static const struct fsinfo_attribute fsinfo_common_attributes[] = { FSINFO_VSTRUCT (FSINFO_ATTR_STATFS, fsinfo_generic_statfs), FSINFO_VSTRUCT (FSINFO_ATTR_IDS, fsinfo_generic_ids), @@ -226,6 +236,7 @@ static const struct fsinfo_attribute fsinfo_common_attributes[] = { FSINFO_STRING (FSINFO_ATTR_VOLUME_ID, fsinfo_generic_volume_id), FSINFO_VSTRUCT (FSINFO_ATTR_VOLUME_UUID, fsinfo_generic_volume_uuid), FSINFO_VSTRUCT (FSINFO_ATTR_FEATURES, fsinfo_generic_features), + FSINFO_VSTRUCT (FSINFO_ATTR_SB_NOTIFICATIONS, fsinfo_generic_sb_notifications), FSINFO_LIST (FSINFO_ATTR_FSINFO_ATTRIBUTES, (void *)123UL), FSINFO_VSTRUCT_N(FSINFO_ATTR_FSINFO_ATTRIBUTE_INFO, (void *)123UL), diff --git a/include/uapi/linux/fsinfo.h b/include/uapi/linux/fsinfo.h index 119c371697be..2f9280d16293 100644 --- a/include/uapi/linux/fsinfo.h +++ b/include/uapi/linux/fsinfo.h @@ -23,6 +23,7 @@ #define FSINFO_ATTR_VOLUME_UUID 0x06 /* Volume UUID (LE uuid) */ #define FSINFO_ATTR_VOLUME_NAME 0x07 /* Volume name (string) */ #define FSINFO_ATTR_FEATURES 0x08 /* Filesystem features (bits) */ +#define FSINFO_ATTR_SB_NOTIFICATIONS 0x09 /* sb_notify() information */ #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) */ @@ -286,4 +287,15 @@ struct fsinfo_volume_uuid { #define FSINFO_ATTR_VOLUME_UUID__STRUCT struct fsinfo_volume_uuid +/* + * Information struct for fsinfo(FSINFO_ATTR_SB_NOTIFICATIONS). + */ +struct fsinfo_sb_notifications { + __u64 watch_id; /* Watch ID for superblock. */ + __u32 notify_counter; /* Number of notifications. */ + __u32 __reserved[1]; +}; + +#define FSINFO_ATTR_SB_NOTIFICATIONS__STRUCT struct fsinfo_sb_notifications + #endif /* _UAPI_LINUX_FSINFO_H */ diff --git a/include/uapi/linux/watch_queue.h b/include/uapi/linux/watch_queue.h index e9c37b1ae68d..9ac2ea6f4a75 100644 --- a/include/uapi/linux/watch_queue.h +++ b/include/uapi/linux/watch_queue.h @@ -151,7 +151,7 @@ enum superblock_notification_type { */ struct superblock_notification { struct watch_notification watch; /* WATCH_TYPE_SB_NOTIFY */ - __u64 sb_id; /* 64-bit superblock ID */ + __u64 sb_id; /* 64-bit superblock ID [FSINFO_ATTR_SB_NOTIFICATIONS] */ }; struct superblock_error_notification { diff --git a/samples/vfs/test-fsinfo.c b/samples/vfs/test-fsinfo.c index 6a61f3426982..247fae5bbb74 100644 --- a/samples/vfs/test-fsinfo.c +++ b/samples/vfs/test-fsinfo.c @@ -303,6 +303,15 @@ static void dump_fsinfo_generic_mount_child(void *reply, unsigned int size) printf("%8x %8x\n", f->mnt_id, f->change_counter); } +static void dump_fsinfo_generic_sb_notifications(void *reply, unsigned int size) +{ + struct fsinfo_sb_notifications *f = reply; + + printf("\n"); + printf("\twatch_id: %llx\n", (unsigned long long)f->watch_id); + printf("\tnotifs : %llx\n", (unsigned long long)f->notify_counter); +} + static void dump_string(void *reply, unsigned int size) { char *s = reply, *p; @@ -367,6 +376,7 @@ static const struct fsinfo_attribute fsinfo_attributes[] = { FSINFO_STRING (FSINFO_ATTR_VOLUME_ID, fsinfo_generic_volume_id), FSINFO_VSTRUCT (FSINFO_ATTR_VOLUME_UUID, fsinfo_generic_volume_uuid), FSINFO_STRING (FSINFO_ATTR_VOLUME_NAME, fsinfo_generic_volume_name), + FSINFO_VSTRUCT (FSINFO_ATTR_SB_NOTIFICATIONS, fsinfo_generic_sb_notifications), FSINFO_VSTRUCT (FSINFO_ATTR_MOUNT_INFO, fsinfo_generic_mount_info), FSINFO_STRING (FSINFO_ATTR_MOUNT_DEVNAME, fsinfo_generic_mount_devname),