Skip to content

Commit 7232522

Browse files
amir73iljankara
authored andcommitted
fanotify: store fsid in mark instead of in connector
Some filesystems like fuse and nfs have zero or non-unique fsid. We would like to avoid reporting ambiguous fsid in events, so we need to avoid marking objects with same fsid and different sb. To make this easier to enforce, store the fsid in the marks of the group instead of in the shared conenctor. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz> Message-Id: <20231130165619.3386452-2-amir73il@gmail.com>
1 parent 994d5c5 commit 7232522

5 files changed

Lines changed: 42 additions & 70 deletions

File tree

fs/notify/fanotify/fanotify.c

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -838,9 +838,8 @@ static struct fanotify_event *fanotify_alloc_event(
838838
}
839839

840840
/*
841-
* Get cached fsid of the filesystem containing the object from any connector.
842-
* All connectors are supposed to have the same fsid, but we do not verify that
843-
* here.
841+
* Get cached fsid of the filesystem containing the object from any mark.
842+
* All marks are supposed to have the same fsid, but we do not verify that here.
844843
*/
845844
static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
846845
{
@@ -849,17 +848,9 @@ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
849848
__kernel_fsid_t fsid = {};
850849

851850
fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
852-
struct fsnotify_mark_connector *conn;
853-
854-
conn = READ_ONCE(mark->connector);
855-
/* Mark is just getting destroyed or created? */
856-
if (!conn)
857-
continue;
858-
if (!(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID))
851+
if (!(mark->flags & FSNOTIFY_MARK_FLAG_HAS_FSID))
859852
continue;
860-
/* Pairs with smp_wmb() in fsnotify_add_mark_list() */
861-
smp_rmb();
862-
fsid = conn->fsid;
853+
fsid = FANOTIFY_MARK(mark)->fsid;
863854
if (WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1]))
864855
continue;
865856
return fsid;
@@ -1068,7 +1059,7 @@ static void fanotify_freeing_mark(struct fsnotify_mark *mark,
10681059

10691060
static void fanotify_free_mark(struct fsnotify_mark *fsn_mark)
10701061
{
1071-
kmem_cache_free(fanotify_mark_cache, fsn_mark);
1062+
kmem_cache_free(fanotify_mark_cache, FANOTIFY_MARK(fsn_mark));
10721063
}
10731064

10741065
const struct fsnotify_ops fanotify_fsnotify_ops = {

fs/notify/fanotify/fanotify.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,16 @@ static inline unsigned int fanotify_event_hash_bucket(
489489
return event->hash & FANOTIFY_HTABLE_MASK;
490490
}
491491

492+
struct fanotify_mark {
493+
struct fsnotify_mark fsn_mark;
494+
__kernel_fsid_t fsid;
495+
};
496+
497+
static inline struct fanotify_mark *FANOTIFY_MARK(struct fsnotify_mark *mark)
498+
{
499+
return container_of(mark, struct fanotify_mark, fsn_mark);
500+
}
501+
492502
static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark)
493503
{
494504
unsigned int mflags = 0;

fs/notify/fanotify/fanotify_user.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,7 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
11991199
__kernel_fsid_t *fsid)
12001200
{
12011201
struct ucounts *ucounts = group->fanotify_data.ucounts;
1202+
struct fanotify_mark *fan_mark;
12021203
struct fsnotify_mark *mark;
12031204
int ret;
12041205

@@ -1211,17 +1212,26 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
12111212
!inc_ucount(ucounts->ns, ucounts->uid, UCOUNT_FANOTIFY_MARKS))
12121213
return ERR_PTR(-ENOSPC);
12131214

1214-
mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL);
1215-
if (!mark) {
1215+
fan_mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL);
1216+
if (!fan_mark) {
12161217
ret = -ENOMEM;
12171218
goto out_dec_ucounts;
12181219
}
12191220

1221+
mark = &fan_mark->fsn_mark;
12201222
fsnotify_init_mark(mark, group);
12211223
if (fan_flags & FAN_MARK_EVICTABLE)
12221224
mark->flags |= FSNOTIFY_MARK_FLAG_NO_IREF;
12231225

1224-
ret = fsnotify_add_mark_locked(mark, connp, obj_type, 0, fsid);
1226+
/* Cache fsid of filesystem containing the marked object */
1227+
if (fsid) {
1228+
fan_mark->fsid = *fsid;
1229+
mark->flags |= FSNOTIFY_MARK_FLAG_HAS_FSID;
1230+
} else {
1231+
fan_mark->fsid.val[0] = fan_mark->fsid.val[1] = 0;
1232+
}
1233+
1234+
ret = fsnotify_add_mark_locked(mark, connp, obj_type, 0);
12251235
if (ret) {
12261236
fsnotify_put_mark(mark);
12271237
goto out_dec_ucounts;
@@ -1935,7 +1945,7 @@ static int __init fanotify_user_setup(void)
19351945
BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 12);
19361946
BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 11);
19371947

1938-
fanotify_mark_cache = KMEM_CACHE(fsnotify_mark,
1948+
fanotify_mark_cache = KMEM_CACHE(fanotify_mark,
19391949
SLAB_PANIC|SLAB_ACCOUNT);
19401950
fanotify_fid_event_cachep = KMEM_CACHE(fanotify_fid_event,
19411951
SLAB_PANIC);

fs/notify/mark.c

Lines changed: 8 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -537,8 +537,7 @@ int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b)
537537
}
538538

539539
static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
540-
unsigned int obj_type,
541-
__kernel_fsid_t *fsid)
540+
unsigned int obj_type)
542541
{
543542
struct fsnotify_mark_connector *conn;
544543

@@ -550,14 +549,7 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
550549
conn->flags = 0;
551550
conn->type = obj_type;
552551
conn->obj = connp;
553-
/* Cache fsid of filesystem containing the object */
554-
if (fsid) {
555-
conn->fsid = *fsid;
556-
conn->flags = FSNOTIFY_CONN_FLAG_HAS_FSID;
557-
} else {
558-
conn->fsid.val[0] = conn->fsid.val[1] = 0;
559-
conn->flags = 0;
560-
}
552+
conn->flags = 0;
561553
fsnotify_get_sb_connectors(conn);
562554

563555
/*
@@ -608,8 +600,7 @@ static struct fsnotify_mark_connector *fsnotify_grab_connector(
608600
*/
609601
static int fsnotify_add_mark_list(struct fsnotify_mark *mark,
610602
fsnotify_connp_t *connp,
611-
unsigned int obj_type,
612-
int add_flags, __kernel_fsid_t *fsid)
603+
unsigned int obj_type, int add_flags)
613604
{
614605
struct fsnotify_mark *lmark, *last = NULL;
615606
struct fsnotify_mark_connector *conn;
@@ -619,41 +610,15 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark,
619610
if (WARN_ON(!fsnotify_valid_obj_type(obj_type)))
620611
return -EINVAL;
621612

622-
/* Backend is expected to check for zero fsid (e.g. tmpfs) */
623-
if (fsid && WARN_ON_ONCE(!fsid->val[0] && !fsid->val[1]))
624-
return -ENODEV;
625-
626613
restart:
627614
spin_lock(&mark->lock);
628615
conn = fsnotify_grab_connector(connp);
629616
if (!conn) {
630617
spin_unlock(&mark->lock);
631-
err = fsnotify_attach_connector_to_object(connp, obj_type,
632-
fsid);
618+
err = fsnotify_attach_connector_to_object(connp, obj_type);
633619
if (err)
634620
return err;
635621
goto restart;
636-
} else if (fsid && !(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID)) {
637-
conn->fsid = *fsid;
638-
/* Pairs with smp_rmb() in fanotify_get_fsid() */
639-
smp_wmb();
640-
conn->flags |= FSNOTIFY_CONN_FLAG_HAS_FSID;
641-
} else if (fsid && (conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID) &&
642-
(fsid->val[0] != conn->fsid.val[0] ||
643-
fsid->val[1] != conn->fsid.val[1])) {
644-
/*
645-
* Backend is expected to check for non uniform fsid
646-
* (e.g. btrfs), but maybe we missed something?
647-
* Only allow setting conn->fsid once to non zero fsid.
648-
* inotify and non-fid fanotify groups do not set nor test
649-
* conn->fsid.
650-
*/
651-
pr_warn_ratelimited("%s: fsid mismatch on object of type %u: "
652-
"%x.%x != %x.%x\n", __func__, conn->type,
653-
fsid->val[0], fsid->val[1],
654-
conn->fsid.val[0], conn->fsid.val[1]);
655-
err = -EXDEV;
656-
goto out_err;
657622
}
658623

659624
/* is mark the first mark? */
@@ -703,7 +668,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark,
703668
*/
704669
int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
705670
fsnotify_connp_t *connp, unsigned int obj_type,
706-
int add_flags, __kernel_fsid_t *fsid)
671+
int add_flags)
707672
{
708673
struct fsnotify_group *group = mark->group;
709674
int ret = 0;
@@ -723,7 +688,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
723688
fsnotify_get_mark(mark); /* for g_list */
724689
spin_unlock(&mark->lock);
725690

726-
ret = fsnotify_add_mark_list(mark, connp, obj_type, add_flags, fsid);
691+
ret = fsnotify_add_mark_list(mark, connp, obj_type, add_flags);
727692
if (ret)
728693
goto err;
729694

@@ -742,14 +707,13 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
742707
}
743708

744709
int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp,
745-
unsigned int obj_type, int add_flags,
746-
__kernel_fsid_t *fsid)
710+
unsigned int obj_type, int add_flags)
747711
{
748712
int ret;
749713
struct fsnotify_group *group = mark->group;
750714

751715
fsnotify_group_lock(group);
752-
ret = fsnotify_add_mark_locked(mark, connp, obj_type, add_flags, fsid);
716+
ret = fsnotify_add_mark_locked(mark, connp, obj_type, add_flags);
753717
fsnotify_group_unlock(group);
754718
return ret;
755719
}

include/linux/fsnotify_backend.h

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -472,10 +472,8 @@ typedef struct fsnotify_mark_connector __rcu *fsnotify_connp_t;
472472
struct fsnotify_mark_connector {
473473
spinlock_t lock;
474474
unsigned short type; /* Type of object [lock] */
475-
#define FSNOTIFY_CONN_FLAG_HAS_FSID 0x01
476475
#define FSNOTIFY_CONN_FLAG_HAS_IREF 0x02
477476
unsigned short flags; /* flags [lock] */
478-
__kernel_fsid_t fsid; /* fsid of filesystem containing object */
479477
union {
480478
/* Object pointer [lock] */
481479
fsnotify_connp_t *obj;
@@ -530,6 +528,7 @@ struct fsnotify_mark {
530528
#define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x0100
531529
#define FSNOTIFY_MARK_FLAG_NO_IREF 0x0200
532530
#define FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS 0x0400
531+
#define FSNOTIFY_MARK_FLAG_HAS_FSID 0x0800
533532
unsigned int flags; /* flags [mark->lock] */
534533
};
535534

@@ -763,27 +762,25 @@ extern struct fsnotify_mark *fsnotify_find_mark(fsnotify_connp_t *connp,
763762
/* attach the mark to the object */
764763
extern int fsnotify_add_mark(struct fsnotify_mark *mark,
765764
fsnotify_connp_t *connp, unsigned int obj_type,
766-
int add_flags, __kernel_fsid_t *fsid);
765+
int add_flags);
767766
extern int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
768767
fsnotify_connp_t *connp,
769-
unsigned int obj_type, int add_flags,
770-
__kernel_fsid_t *fsid);
768+
unsigned int obj_type, int add_flags);
771769

772770
/* attach the mark to the inode */
773771
static inline int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
774772
struct inode *inode,
775773
int add_flags)
776774
{
777775
return fsnotify_add_mark(mark, &inode->i_fsnotify_marks,
778-
FSNOTIFY_OBJ_TYPE_INODE, add_flags, NULL);
776+
FSNOTIFY_OBJ_TYPE_INODE, add_flags);
779777
}
780778
static inline int fsnotify_add_inode_mark_locked(struct fsnotify_mark *mark,
781779
struct inode *inode,
782780
int add_flags)
783781
{
784782
return fsnotify_add_mark_locked(mark, &inode->i_fsnotify_marks,
785-
FSNOTIFY_OBJ_TYPE_INODE, add_flags,
786-
NULL);
783+
FSNOTIFY_OBJ_TYPE_INODE, add_flags);
787784
}
788785

789786
/* given a group and a mark, flag mark to be freed when all references are dropped */

0 commit comments

Comments
 (0)