summaryrefslogtreecommitdiffstats
path: root/fs/notify
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2019-01-10 12:04:37 -0500
committerJan Kara <jack@suse.cz>2019-02-07 10:38:35 -0500
commit77115225acc67d9ac4b15f04dd138006b9cd1ef2 (patch)
tree6f5bce4240d6975c10ffee2d447035b1783b0e38 /fs/notify
parenta8b13aa20afb69161b5123b4f1acc7ea0a03d360 (diff)
fanotify: cache fsid in fsnotify_mark_connector
For FAN_REPORT_FID, we need to encode fid with fsid of the filesystem on every event. To avoid having to call vfs_statfs() on every event to get fsid, we store the fsid in fsnotify_mark_connector on the first time we add a mark and on handle event we use the cached fsid. Subsequent calls to add mark on the same object are expected to pass the same fsid, so the call will fail on cached fsid mismatch. If an event is reported on several mark types (inode, mount, filesystem), all connectors should already have the same fsid, so we use the cached fsid from the first connector. [JK: Simplify code flow around fanotify_get_fid() make fsid argument of fsnotify_add_mark_locked() unconditional] Suggested-by: Jan Kara <jack@suse.cz> Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/notify')
-rw-r--r--fs/notify/fanotify/fanotify.c59
-rw-r--r--fs/notify/fanotify/fanotify.h5
-rw-r--r--fs/notify/fanotify/fanotify_user.c62
-rw-r--r--fs/notify/mark.c42
4 files changed, 115 insertions, 53 deletions
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index dd33227e518a..555831603637 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -153,26 +153,20 @@ static u32 fanotify_group_event_mask(struct fsnotify_iter_info *iter_info,
153} 153}
154 154
155static int fanotify_encode_fid(struct fanotify_event *event, 155static int fanotify_encode_fid(struct fanotify_event *event,
156 const struct path *path, gfp_t gfp) 156 struct inode *inode, gfp_t gfp,
157 __kernel_fsid_t *fsid)
157{ 158{
158 struct fanotify_fid *fid = &event->fid; 159 struct fanotify_fid *fid = &event->fid;
159 int dwords, bytes = 0; 160 int dwords, bytes = 0;
160 struct kstatfs stat;
161 int err, type; 161 int err, type;
162 162
163 stat.f_fsid.val[0] = stat.f_fsid.val[1] = 0;
164 fid->ext_fh = NULL; 163 fid->ext_fh = NULL;
165 dwords = 0; 164 dwords = 0;
166 err = -ENOENT; 165 err = -ENOENT;
167 type = exportfs_encode_inode_fh(d_inode(path->dentry), NULL, &dwords, 166 type = exportfs_encode_inode_fh(inode, NULL, &dwords, NULL);
168 NULL);
169 if (!dwords) 167 if (!dwords)
170 goto out_err; 168 goto out_err;
171 169
172 err = vfs_statfs(path, &stat);
173 if (err)
174 goto out_err;
175
176 bytes = dwords << 2; 170 bytes = dwords << 2;
177 if (bytes > FANOTIFY_INLINE_FH_LEN) { 171 if (bytes > FANOTIFY_INLINE_FH_LEN) {
178 /* Treat failure to allocate fh as failure to allocate event */ 172 /* Treat failure to allocate fh as failure to allocate event */
@@ -182,14 +176,13 @@ static int fanotify_encode_fid(struct fanotify_event *event,
182 goto out_err; 176 goto out_err;
183 } 177 }
184 178
185 type = exportfs_encode_inode_fh(d_inode(path->dentry), 179 type = exportfs_encode_inode_fh(inode, fanotify_fid_fh(fid, bytes),
186 fanotify_fid_fh(fid, bytes), &dwords, 180 &dwords, NULL);
187 NULL);
188 err = -EINVAL; 181 err = -EINVAL;
189 if (!type || type == FILEID_INVALID || bytes != dwords << 2) 182 if (!type || type == FILEID_INVALID || bytes != dwords << 2)
190 goto out_err; 183 goto out_err;
191 184
192 fid->fsid = stat.f_fsid; 185 fid->fsid = *fsid;
193 event->fh_len = bytes; 186 event->fh_len = bytes;
194 187
195 return type; 188 return type;
@@ -197,8 +190,7 @@ static int fanotify_encode_fid(struct fanotify_event *event,
197out_err: 190out_err:
198 pr_warn_ratelimited("fanotify: failed to encode fid (fsid=%x.%x, " 191 pr_warn_ratelimited("fanotify: failed to encode fid (fsid=%x.%x, "
199 "type=%d, bytes=%d, err=%i)\n", 192 "type=%d, bytes=%d, err=%i)\n",
200 stat.f_fsid.val[0], stat.f_fsid.val[1], 193 fsid->val[0], fsid->val[1], type, bytes, err);
201 type, bytes, err);
202 kfree(fid->ext_fh); 194 kfree(fid->ext_fh);
203 fid->ext_fh = NULL; 195 fid->ext_fh = NULL;
204 event->fh_len = 0; 196 event->fh_len = 0;
@@ -207,8 +199,9 @@ out_err:
207} 199}
208 200
209struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, 201struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
210 struct inode *inode, u32 mask, 202 struct inode *inode, u32 mask,
211 const struct path *path) 203 const struct path *path,
204 __kernel_fsid_t *fsid)
212{ 205{
213 struct fanotify_event *event = NULL; 206 struct fanotify_event *event = NULL;
214 gfp_t gfp = GFP_KERNEL_ACCOUNT; 207 gfp_t gfp = GFP_KERNEL_ACCOUNT;
@@ -247,7 +240,8 @@ init: __maybe_unused
247 event->fh_len = 0; 240 event->fh_len = 0;
248 if (path && FAN_GROUP_FLAG(group, FAN_REPORT_FID)) { 241 if (path && FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
249 /* Report the event without a file identifier on encode error */ 242 /* Report the event without a file identifier on encode error */
250 event->fh_type = fanotify_encode_fid(event, path, gfp); 243 event->fh_type = fanotify_encode_fid(event,
244 d_inode(path->dentry), gfp, fsid);
251 } else if (path) { 245 } else if (path) {
252 event->fh_type = FILEID_ROOT; 246 event->fh_type = FILEID_ROOT;
253 event->path = *path; 247 event->path = *path;
@@ -262,6 +256,29 @@ out:
262 return event; 256 return event;
263} 257}
264 258
259/*
260 * Get cached fsid of the filesystem containing the object from any connector.
261 * All connectors are supposed to have the same fsid, but we do not verify that
262 * here.
263 */
264static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
265{
266 int type;
267 __kernel_fsid_t fsid = {};
268
269 fsnotify_foreach_obj_type(type) {
270 if (!fsnotify_iter_should_report_type(iter_info, type))
271 continue;
272
273 fsid = iter_info->marks[type]->connector->fsid;
274 if (WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1]))
275 continue;
276 return fsid;
277 }
278
279 return fsid;
280}
281
265static int fanotify_handle_event(struct fsnotify_group *group, 282static int fanotify_handle_event(struct fsnotify_group *group,
266 struct inode *inode, 283 struct inode *inode,
267 u32 mask, const void *data, int data_type, 284 u32 mask, const void *data, int data_type,
@@ -271,6 +288,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
271 int ret = 0; 288 int ret = 0;
272 struct fanotify_event *event; 289 struct fanotify_event *event;
273 struct fsnotify_event *fsn_event; 290 struct fsnotify_event *fsn_event;
291 __kernel_fsid_t fsid = {};
274 292
275 BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS); 293 BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS);
276 BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY); 294 BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY);
@@ -303,7 +321,10 @@ static int fanotify_handle_event(struct fsnotify_group *group,
303 return 0; 321 return 0;
304 } 322 }
305 323
306 event = fanotify_alloc_event(group, inode, mask, data); 324 if (FAN_GROUP_FLAG(group, FAN_REPORT_FID))
325 fsid = fanotify_get_fsid(iter_info);
326
327 event = fanotify_alloc_event(group, inode, mask, data, &fsid);
307 ret = -ENOMEM; 328 ret = -ENOMEM;
308 if (unlikely(!event)) { 329 if (unlikely(!event)) {
309 /* 330 /*
diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h
index 4aafc7144c3d..5b072afa4e19 100644
--- a/fs/notify/fanotify/fanotify.h
+++ b/fs/notify/fanotify/fanotify.h
@@ -131,5 +131,6 @@ static inline struct fanotify_event *FANOTIFY_E(struct fsnotify_event *fse)
131} 131}
132 132
133struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, 133struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
134 struct inode *inode, u32 mask, 134 struct inode *inode, u32 mask,
135 const struct path *path); 135 const struct path *path,
136 __kernel_fsid_t *fsid);
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 1638c171ca82..603419ce096f 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -653,7 +653,8 @@ static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
653 653
654static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, 654static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
655 fsnotify_connp_t *connp, 655 fsnotify_connp_t *connp,
656 unsigned int type) 656 unsigned int type,
657 __kernel_fsid_t *fsid)
657{ 658{
658 struct fsnotify_mark *mark; 659 struct fsnotify_mark *mark;
659 int ret; 660 int ret;
@@ -666,7 +667,7 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
666 return ERR_PTR(-ENOMEM); 667 return ERR_PTR(-ENOMEM);
667 668
668 fsnotify_init_mark(mark, group); 669 fsnotify_init_mark(mark, group);
669 ret = fsnotify_add_mark_locked(mark, connp, type, 0); 670 ret = fsnotify_add_mark_locked(mark, connp, type, 0, fsid);
670 if (ret) { 671 if (ret) {
671 fsnotify_put_mark(mark); 672 fsnotify_put_mark(mark);
672 return ERR_PTR(ret); 673 return ERR_PTR(ret);
@@ -678,7 +679,8 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
678 679
679static int fanotify_add_mark(struct fsnotify_group *group, 680static int fanotify_add_mark(struct fsnotify_group *group,
680 fsnotify_connp_t *connp, unsigned int type, 681 fsnotify_connp_t *connp, unsigned int type,
681 __u32 mask, unsigned int flags) 682 __u32 mask, unsigned int flags,
683 __kernel_fsid_t *fsid)
682{ 684{
683 struct fsnotify_mark *fsn_mark; 685 struct fsnotify_mark *fsn_mark;
684 __u32 added; 686 __u32 added;
@@ -686,7 +688,7 @@ static int fanotify_add_mark(struct fsnotify_group *group,
686 mutex_lock(&group->mark_mutex); 688 mutex_lock(&group->mark_mutex);
687 fsn_mark = fsnotify_find_mark(connp, group); 689 fsn_mark = fsnotify_find_mark(connp, group);
688 if (!fsn_mark) { 690 if (!fsn_mark) {
689 fsn_mark = fanotify_add_new_mark(group, connp, type); 691 fsn_mark = fanotify_add_new_mark(group, connp, type, fsid);
690 if (IS_ERR(fsn_mark)) { 692 if (IS_ERR(fsn_mark)) {
691 mutex_unlock(&group->mark_mutex); 693 mutex_unlock(&group->mark_mutex);
692 return PTR_ERR(fsn_mark); 694 return PTR_ERR(fsn_mark);
@@ -703,23 +705,23 @@ static int fanotify_add_mark(struct fsnotify_group *group,
703 705
704static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, 706static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,
705 struct vfsmount *mnt, __u32 mask, 707 struct vfsmount *mnt, __u32 mask,
706 unsigned int flags) 708 unsigned int flags, __kernel_fsid_t *fsid)
707{ 709{
708 return fanotify_add_mark(group, &real_mount(mnt)->mnt_fsnotify_marks, 710 return fanotify_add_mark(group, &real_mount(mnt)->mnt_fsnotify_marks,
709 FSNOTIFY_OBJ_TYPE_VFSMOUNT, mask, flags); 711 FSNOTIFY_OBJ_TYPE_VFSMOUNT, mask, flags, fsid);
710} 712}
711 713
712static int fanotify_add_sb_mark(struct fsnotify_group *group, 714static int fanotify_add_sb_mark(struct fsnotify_group *group,
713 struct super_block *sb, __u32 mask, 715 struct super_block *sb, __u32 mask,
714 unsigned int flags) 716 unsigned int flags, __kernel_fsid_t *fsid)
715{ 717{
716 return fanotify_add_mark(group, &sb->s_fsnotify_marks, 718 return fanotify_add_mark(group, &sb->s_fsnotify_marks,
717 FSNOTIFY_OBJ_TYPE_SB, mask, flags); 719 FSNOTIFY_OBJ_TYPE_SB, mask, flags, fsid);
718} 720}
719 721
720static int fanotify_add_inode_mark(struct fsnotify_group *group, 722static int fanotify_add_inode_mark(struct fsnotify_group *group,
721 struct inode *inode, __u32 mask, 723 struct inode *inode, __u32 mask,
722 unsigned int flags) 724 unsigned int flags, __kernel_fsid_t *fsid)
723{ 725{
724 pr_debug("%s: group=%p inode=%p\n", __func__, group, inode); 726 pr_debug("%s: group=%p inode=%p\n", __func__, group, inode);
725 727
@@ -734,7 +736,7 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group,
734 return 0; 736 return 0;
735 737
736 return fanotify_add_mark(group, &inode->i_fsnotify_marks, 738 return fanotify_add_mark(group, &inode->i_fsnotify_marks,
737 FSNOTIFY_OBJ_TYPE_INODE, mask, flags); 739 FSNOTIFY_OBJ_TYPE_INODE, mask, flags, fsid);
738} 740}
739 741
740/* fanotify syscalls */ 742/* fanotify syscalls */
@@ -798,7 +800,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
798 atomic_inc(&user->fanotify_listeners); 800 atomic_inc(&user->fanotify_listeners);
799 group->memcg = get_mem_cgroup_from_mm(current->mm); 801 group->memcg = get_mem_cgroup_from_mm(current->mm);
800 802
801 oevent = fanotify_alloc_event(group, NULL, FS_Q_OVERFLOW, NULL); 803 oevent = fanotify_alloc_event(group, NULL, FS_Q_OVERFLOW, NULL, NULL);
802 if (unlikely(!oevent)) { 804 if (unlikely(!oevent)) {
803 fd = -ENOMEM; 805 fd = -ENOMEM;
804 goto out_destroy_group; 806 goto out_destroy_group;
@@ -861,9 +863,9 @@ out_destroy_group:
861} 863}
862 864
863/* Check if filesystem can encode a unique fid */ 865/* Check if filesystem can encode a unique fid */
864static int fanotify_test_fid(struct path *path) 866static int fanotify_test_fid(struct path *path, struct kstatfs *stat)
865{ 867{
866 struct kstatfs stat, root_stat; 868 struct kstatfs root_stat;
867 struct path root = { 869 struct path root = {
868 .mnt = path->mnt, 870 .mnt = path->mnt,
869 .dentry = path->dentry->d_sb->s_root, 871 .dentry = path->dentry->d_sb->s_root,
@@ -873,11 +875,11 @@ static int fanotify_test_fid(struct path *path)
873 /* 875 /*
874 * Make sure path is not in filesystem with zero fsid (e.g. tmpfs). 876 * Make sure path is not in filesystem with zero fsid (e.g. tmpfs).
875 */ 877 */
876 err = vfs_statfs(path, &stat); 878 err = vfs_statfs(path, stat);
877 if (err) 879 if (err)
878 return err; 880 return err;
879 881
880 if (!stat.f_fsid.val[0] && !stat.f_fsid.val[1]) 882 if (!stat->f_fsid.val[0] && !stat->f_fsid.val[1])
881 return -ENODEV; 883 return -ENODEV;
882 884
883 /* 885 /*
@@ -888,8 +890,8 @@ static int fanotify_test_fid(struct path *path)
888 if (err) 890 if (err)
889 return err; 891 return err;
890 892
891 if (root_stat.f_fsid.val[0] != stat.f_fsid.val[0] || 893 if (root_stat.f_fsid.val[0] != stat->f_fsid.val[0] ||
892 root_stat.f_fsid.val[1] != stat.f_fsid.val[1]) 894 root_stat.f_fsid.val[1] != stat->f_fsid.val[1])
893 return -EXDEV; 895 return -EXDEV;
894 896
895 /* 897 /*
@@ -914,6 +916,8 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
914 struct fsnotify_group *group; 916 struct fsnotify_group *group;
915 struct fd f; 917 struct fd f;
916 struct path path; 918 struct path path;
919 struct kstatfs stat;
920 __kernel_fsid_t *fsid = NULL;
917 u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS; 921 u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS;
918 unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; 922 unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
919 int ret; 923 int ret;
@@ -992,9 +996,11 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
992 goto fput_and_out; 996 goto fput_and_out;
993 997
994 if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) { 998 if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
995 ret = fanotify_test_fid(&path); 999 ret = fanotify_test_fid(&path, &stat);
996 if (ret) 1000 if (ret)
997 goto path_put_and_out; 1001 goto path_put_and_out;
1002
1003 fsid = &stat.f_fsid;
998 } 1004 }
999 1005
1000 /* inode held in place by reference to path; group by fget on fd */ 1006 /* inode held in place by reference to path; group by fget on fd */
@@ -1007,19 +1013,25 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
1007 switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) { 1013 switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) {
1008 case FAN_MARK_ADD: 1014 case FAN_MARK_ADD:
1009 if (mark_type == FAN_MARK_MOUNT) 1015 if (mark_type == FAN_MARK_MOUNT)
1010 ret = fanotify_add_vfsmount_mark(group, mnt, mask, flags); 1016 ret = fanotify_add_vfsmount_mark(group, mnt, mask,
1017 flags, fsid);
1011 else if (mark_type == FAN_MARK_FILESYSTEM) 1018 else if (mark_type == FAN_MARK_FILESYSTEM)
1012 ret = fanotify_add_sb_mark(group, mnt->mnt_sb, mask, flags); 1019 ret = fanotify_add_sb_mark(group, mnt->mnt_sb, mask,
1020 flags, fsid);
1013 else 1021 else
1014 ret = fanotify_add_inode_mark(group, inode, mask, flags); 1022 ret = fanotify_add_inode_mark(group, inode, mask,
1023 flags, fsid);
1015 break; 1024 break;
1016 case FAN_MARK_REMOVE: 1025 case FAN_MARK_REMOVE:
1017 if (mark_type == FAN_MARK_MOUNT) 1026 if (mark_type == FAN_MARK_MOUNT)
1018 ret = fanotify_remove_vfsmount_mark(group, mnt, mask, flags); 1027 ret = fanotify_remove_vfsmount_mark(group, mnt, mask,
1028 flags);
1019 else if (mark_type == FAN_MARK_FILESYSTEM) 1029 else if (mark_type == FAN_MARK_FILESYSTEM)
1020 ret = fanotify_remove_sb_mark(group, mnt->mnt_sb, mask, flags); 1030 ret = fanotify_remove_sb_mark(group, mnt->mnt_sb, mask,
1031 flags);
1021 else 1032 else
1022 ret = fanotify_remove_inode_mark(group, inode, mask, flags); 1033 ret = fanotify_remove_inode_mark(group, inode, mask,
1034 flags);
1023 break; 1035 break;
1024 default: 1036 default:
1025 ret = -EINVAL; 1037 ret = -EINVAL;
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index d2dd16cb5989..d593d4269561 100644
--- a/fs/notify/mark.c
+++ b/fs/notify/mark.c
@@ -82,6 +82,7 @@
82#include <linux/slab.h> 82#include <linux/slab.h>
83#include <linux/spinlock.h> 83#include <linux/spinlock.h>
84#include <linux/srcu.h> 84#include <linux/srcu.h>
85#include <linux/ratelimit.h>
85 86
86#include <linux/atomic.h> 87#include <linux/atomic.h>
87 88
@@ -481,7 +482,8 @@ int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b)
481} 482}
482 483
483static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, 484static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
484 unsigned int type) 485 unsigned int type,
486 __kernel_fsid_t *fsid)
485{ 487{
486 struct inode *inode = NULL; 488 struct inode *inode = NULL;
487 struct fsnotify_mark_connector *conn; 489 struct fsnotify_mark_connector *conn;
@@ -493,6 +495,11 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
493 INIT_HLIST_HEAD(&conn->list); 495 INIT_HLIST_HEAD(&conn->list);
494 conn->type = type; 496 conn->type = type;
495 conn->obj = connp; 497 conn->obj = connp;
498 /* Cache fsid of filesystem containing the object */
499 if (fsid)
500 conn->fsid = *fsid;
501 else
502 conn->fsid.val[0] = conn->fsid.val[1] = 0;
496 if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) 503 if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
497 inode = igrab(fsnotify_conn_inode(conn)); 504 inode = igrab(fsnotify_conn_inode(conn));
498 /* 505 /*
@@ -544,7 +551,7 @@ out:
544 */ 551 */
545static int fsnotify_add_mark_list(struct fsnotify_mark *mark, 552static int fsnotify_add_mark_list(struct fsnotify_mark *mark,
546 fsnotify_connp_t *connp, unsigned int type, 553 fsnotify_connp_t *connp, unsigned int type,
547 int allow_dups) 554 int allow_dups, __kernel_fsid_t *fsid)
548{ 555{
549 struct fsnotify_mark *lmark, *last = NULL; 556 struct fsnotify_mark *lmark, *last = NULL;
550 struct fsnotify_mark_connector *conn; 557 struct fsnotify_mark_connector *conn;
@@ -553,15 +560,36 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark,
553 560
554 if (WARN_ON(!fsnotify_valid_obj_type(type))) 561 if (WARN_ON(!fsnotify_valid_obj_type(type)))
555 return -EINVAL; 562 return -EINVAL;
563
564 /* Backend is expected to check for zero fsid (e.g. tmpfs) */
565 if (fsid && WARN_ON_ONCE(!fsid->val[0] && !fsid->val[1]))
566 return -ENODEV;
567
556restart: 568restart:
557 spin_lock(&mark->lock); 569 spin_lock(&mark->lock);
558 conn = fsnotify_grab_connector(connp); 570 conn = fsnotify_grab_connector(connp);
559 if (!conn) { 571 if (!conn) {
560 spin_unlock(&mark->lock); 572 spin_unlock(&mark->lock);
561 err = fsnotify_attach_connector_to_object(connp, type); 573 err = fsnotify_attach_connector_to_object(connp, type, fsid);
562 if (err) 574 if (err)
563 return err; 575 return err;
564 goto restart; 576 goto restart;
577 } else if (fsid && (conn->fsid.val[0] || conn->fsid.val[1]) &&
578 (fsid->val[0] != conn->fsid.val[0] ||
579 fsid->val[1] != conn->fsid.val[1])) {
580 /*
581 * Backend is expected to check for non uniform fsid
582 * (e.g. btrfs), but maybe we missed something?
583 * Only allow setting conn->fsid once to non zero fsid.
584 * inotify and non-fid fanotify groups do not set nor test
585 * conn->fsid.
586 */
587 pr_warn_ratelimited("%s: fsid mismatch on object of type %u: "
588 "%x.%x != %x.%x\n", __func__, conn->type,
589 fsid->val[0], fsid->val[1],
590 conn->fsid.val[0], conn->fsid.val[1]);
591 err = -EXDEV;
592 goto out_err;
565 } 593 }
566 594
567 /* is mark the first mark? */ 595 /* is mark the first mark? */
@@ -606,7 +634,7 @@ out_err:
606 */ 634 */
607int fsnotify_add_mark_locked(struct fsnotify_mark *mark, 635int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
608 fsnotify_connp_t *connp, unsigned int type, 636 fsnotify_connp_t *connp, unsigned int type,
609 int allow_dups) 637 int allow_dups, __kernel_fsid_t *fsid)
610{ 638{
611 struct fsnotify_group *group = mark->group; 639 struct fsnotify_group *group = mark->group;
612 int ret = 0; 640 int ret = 0;
@@ -627,7 +655,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
627 fsnotify_get_mark(mark); /* for g_list */ 655 fsnotify_get_mark(mark); /* for g_list */
628 spin_unlock(&mark->lock); 656 spin_unlock(&mark->lock);
629 657
630 ret = fsnotify_add_mark_list(mark, connp, type, allow_dups); 658 ret = fsnotify_add_mark_list(mark, connp, type, allow_dups, fsid);
631 if (ret) 659 if (ret)
632 goto err; 660 goto err;
633 661
@@ -648,13 +676,13 @@ err:
648} 676}
649 677
650int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp, 678int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp,
651 unsigned int type, int allow_dups) 679 unsigned int type, int allow_dups, __kernel_fsid_t *fsid)
652{ 680{
653 int ret; 681 int ret;
654 struct fsnotify_group *group = mark->group; 682 struct fsnotify_group *group = mark->group;
655 683
656 mutex_lock(&group->mark_mutex); 684 mutex_lock(&group->mark_mutex);
657 ret = fsnotify_add_mark_locked(mark, connp, type, allow_dups); 685 ret = fsnotify_add_mark_locked(mark, connp, type, allow_dups, fsid);
658 mutex_unlock(&group->mark_mutex); 686 mutex_unlock(&group->mark_mutex);
659 return ret; 687 return ret;
660} 688}