Skip to content

Commit 32720ac

Browse files
committed
Merge tag 'fsnotify_for_v6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull fsnotify updates from Jan Kara: "fanotify changes allowing use of fanotify directory events even for filesystems such as FUSE which don't report proper fsid" * tag 'fsnotify_for_v6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: fanotify: allow "weak" fsid when watching a single filesystem fanotify: store fsid in mark instead of in connector
2 parents 9963327 + 30ad193 commit 32720ac

5 files changed

Lines changed: 140 additions & 100 deletions

File tree

fs/notify/fanotify/fanotify.c

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,6 @@ static unsigned int fanotify_hash_path(const struct path *path)
2929
hash_ptr(path->mnt, FANOTIFY_EVENT_HASH_BITS);
3030
}
3131

32-
static inline bool fanotify_fsid_equal(__kernel_fsid_t *fsid1,
33-
__kernel_fsid_t *fsid2)
34-
{
35-
return fsid1->val[0] == fsid2->val[0] && fsid1->val[1] == fsid2->val[1];
36-
}
37-
3832
static unsigned int fanotify_hash_fsid(__kernel_fsid_t *fsid)
3933
{
4034
return hash_32(fsid->val[0], FANOTIFY_EVENT_HASH_BITS) ^
@@ -838,9 +832,8 @@ static struct fanotify_event *fanotify_alloc_event(
838832
}
839833

840834
/*
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.
835+
* Get cached fsid of the filesystem containing the object from any mark.
836+
* All marks are supposed to have the same fsid, but we do not verify that here.
844837
*/
845838
static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
846839
{
@@ -849,18 +842,11 @@ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
849842
__kernel_fsid_t fsid = {};
850843

851844
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)
845+
if (!(mark->flags & FSNOTIFY_MARK_FLAG_HAS_FSID))
857846
continue;
858-
if (!(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID))
859-
continue;
860-
/* Pairs with smp_wmb() in fsnotify_add_mark_list() */
861-
smp_rmb();
862-
fsid = conn->fsid;
863-
if (WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1]))
847+
fsid = FANOTIFY_MARK(mark)->fsid;
848+
if (!(mark->flags & FSNOTIFY_MARK_FLAG_WEAK_FSID) &&
849+
WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1]))
864850
continue;
865851
return fsid;
866852
}
@@ -942,12 +928,8 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
942928
return 0;
943929
}
944930

945-
if (FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS)) {
931+
if (FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS))
946932
fsid = fanotify_get_fsid(iter_info);
947-
/* Racing with mark destruction or creation? */
948-
if (!fsid.val[0] && !fsid.val[1])
949-
return 0;
950-
}
951933

952934
event = fanotify_alloc_event(group, mask, data, data_type, dir,
953935
file_name, &fsid, match_mask);
@@ -1068,7 +1050,7 @@ static void fanotify_freeing_mark(struct fsnotify_mark *mark,
10681050

10691051
static void fanotify_free_mark(struct fsnotify_mark *fsn_mark)
10701052
{
1071-
kmem_cache_free(fanotify_mark_cache, fsn_mark);
1053+
kmem_cache_free(fanotify_mark_cache, FANOTIFY_MARK(fsn_mark));
10721054
}
10731055

10741056
const struct fsnotify_ops fanotify_fsnotify_ops = {

fs/notify/fanotify/fanotify.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,22 @@ 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+
502+
static inline bool fanotify_fsid_equal(__kernel_fsid_t *fsid1,
503+
__kernel_fsid_t *fsid2)
504+
{
505+
return fsid1->val[0] == fsid2->val[0] && fsid1->val[1] == fsid2->val[1];
506+
}
507+
492508
static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark)
493509
{
494510
unsigned int mflags = 0;

fs/notify/fanotify/fanotify_user.c

Lines changed: 102 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
#include <asm/ioctls.h>
2525

26-
#include "../../mount.h"
26+
#include "../fsnotify.h"
2727
#include "../fdinfo.h"
2828
#include "fanotify.h"
2929

@@ -1192,13 +1192,71 @@ static bool fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
11921192
return recalc;
11931193
}
11941194

1195+
struct fan_fsid {
1196+
struct super_block *sb;
1197+
__kernel_fsid_t id;
1198+
bool weak;
1199+
};
1200+
1201+
static int fanotify_set_mark_fsid(struct fsnotify_group *group,
1202+
struct fsnotify_mark *mark,
1203+
struct fan_fsid *fsid)
1204+
{
1205+
struct fsnotify_mark_connector *conn;
1206+
struct fsnotify_mark *old;
1207+
struct super_block *old_sb = NULL;
1208+
1209+
FANOTIFY_MARK(mark)->fsid = fsid->id;
1210+
mark->flags |= FSNOTIFY_MARK_FLAG_HAS_FSID;
1211+
if (fsid->weak)
1212+
mark->flags |= FSNOTIFY_MARK_FLAG_WEAK_FSID;
1213+
1214+
/* First mark added will determine if group is single or multi fsid */
1215+
if (list_empty(&group->marks_list))
1216+
return 0;
1217+
1218+
/* Find sb of an existing mark */
1219+
list_for_each_entry(old, &group->marks_list, g_list) {
1220+
conn = READ_ONCE(old->connector);
1221+
if (!conn)
1222+
continue;
1223+
old_sb = fsnotify_connector_sb(conn);
1224+
if (old_sb)
1225+
break;
1226+
}
1227+
1228+
/* Only detached marks left? */
1229+
if (!old_sb)
1230+
return 0;
1231+
1232+
/* Do not allow mixing of marks with weak and strong fsid */
1233+
if ((mark->flags ^ old->flags) & FSNOTIFY_MARK_FLAG_WEAK_FSID)
1234+
return -EXDEV;
1235+
1236+
/* Allow mixing of marks with strong fsid from different fs */
1237+
if (!fsid->weak)
1238+
return 0;
1239+
1240+
/* Do not allow mixing marks with weak fsid from different fs */
1241+
if (old_sb != fsid->sb)
1242+
return -EXDEV;
1243+
1244+
/* Do not allow mixing marks from different btrfs sub-volumes */
1245+
if (!fanotify_fsid_equal(&FANOTIFY_MARK(old)->fsid,
1246+
&FANOTIFY_MARK(mark)->fsid))
1247+
return -EXDEV;
1248+
1249+
return 0;
1250+
}
1251+
11951252
static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
11961253
fsnotify_connp_t *connp,
11971254
unsigned int obj_type,
11981255
unsigned int fan_flags,
1199-
__kernel_fsid_t *fsid)
1256+
struct fan_fsid *fsid)
12001257
{
12011258
struct ucounts *ucounts = group->fanotify_data.ucounts;
1259+
struct fanotify_mark *fan_mark;
12021260
struct fsnotify_mark *mark;
12031261
int ret;
12041262

@@ -1211,24 +1269,34 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
12111269
!inc_ucount(ucounts->ns, ucounts->uid, UCOUNT_FANOTIFY_MARKS))
12121270
return ERR_PTR(-ENOSPC);
12131271

1214-
mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL);
1215-
if (!mark) {
1272+
fan_mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL);
1273+
if (!fan_mark) {
12161274
ret = -ENOMEM;
12171275
goto out_dec_ucounts;
12181276
}
12191277

1278+
mark = &fan_mark->fsn_mark;
12201279
fsnotify_init_mark(mark, group);
12211280
if (fan_flags & FAN_MARK_EVICTABLE)
12221281
mark->flags |= FSNOTIFY_MARK_FLAG_NO_IREF;
12231282

1224-
ret = fsnotify_add_mark_locked(mark, connp, obj_type, 0, fsid);
1225-
if (ret) {
1226-
fsnotify_put_mark(mark);
1227-
goto out_dec_ucounts;
1283+
/* Cache fsid of filesystem containing the marked object */
1284+
if (fsid) {
1285+
ret = fanotify_set_mark_fsid(group, mark, fsid);
1286+
if (ret)
1287+
goto out_put_mark;
1288+
} else {
1289+
fan_mark->fsid.val[0] = fan_mark->fsid.val[1] = 0;
12281290
}
12291291

1292+
ret = fsnotify_add_mark_locked(mark, connp, obj_type, 0);
1293+
if (ret)
1294+
goto out_put_mark;
1295+
12301296
return mark;
12311297

1298+
out_put_mark:
1299+
fsnotify_put_mark(mark);
12321300
out_dec_ucounts:
12331301
if (!FAN_GROUP_FLAG(group, FAN_UNLIMITED_MARKS))
12341302
dec_ucount(ucounts, UCOUNT_FANOTIFY_MARKS);
@@ -1279,7 +1347,7 @@ static int fanotify_may_update_existing_mark(struct fsnotify_mark *fsn_mark,
12791347
static int fanotify_add_mark(struct fsnotify_group *group,
12801348
fsnotify_connp_t *connp, unsigned int obj_type,
12811349
__u32 mask, unsigned int fan_flags,
1282-
__kernel_fsid_t *fsid)
1350+
struct fan_fsid *fsid)
12831351
{
12841352
struct fsnotify_mark *fsn_mark;
12851353
bool recalc;
@@ -1327,23 +1395,23 @@ static int fanotify_add_mark(struct fsnotify_group *group,
13271395

13281396
static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,
13291397
struct vfsmount *mnt, __u32 mask,
1330-
unsigned int flags, __kernel_fsid_t *fsid)
1398+
unsigned int flags, struct fan_fsid *fsid)
13311399
{
13321400
return fanotify_add_mark(group, &real_mount(mnt)->mnt_fsnotify_marks,
13331401
FSNOTIFY_OBJ_TYPE_VFSMOUNT, mask, flags, fsid);
13341402
}
13351403

13361404
static int fanotify_add_sb_mark(struct fsnotify_group *group,
13371405
struct super_block *sb, __u32 mask,
1338-
unsigned int flags, __kernel_fsid_t *fsid)
1406+
unsigned int flags, struct fan_fsid *fsid)
13391407
{
13401408
return fanotify_add_mark(group, &sb->s_fsnotify_marks,
13411409
FSNOTIFY_OBJ_TYPE_SB, mask, flags, fsid);
13421410
}
13431411

13441412
static int fanotify_add_inode_mark(struct fsnotify_group *group,
13451413
struct inode *inode, __u32 mask,
1346-
unsigned int flags, __kernel_fsid_t *fsid)
1414+
unsigned int flags, struct fan_fsid *fsid)
13471415
{
13481416
pr_debug("%s: group=%p inode=%p\n", __func__, group, inode);
13491417

@@ -1554,20 +1622,25 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
15541622
return fd;
15551623
}
15561624

1557-
static int fanotify_test_fsid(struct dentry *dentry, __kernel_fsid_t *fsid)
1625+
static int fanotify_test_fsid(struct dentry *dentry, unsigned int flags,
1626+
struct fan_fsid *fsid)
15581627
{
1628+
unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
15591629
__kernel_fsid_t root_fsid;
15601630
int err;
15611631

15621632
/*
15631633
* Make sure dentry is not of a filesystem with zero fsid (e.g. fuse).
15641634
*/
1565-
err = vfs_get_fsid(dentry, fsid);
1635+
err = vfs_get_fsid(dentry, &fsid->id);
15661636
if (err)
15671637
return err;
15681638

1569-
if (!fsid->val[0] && !fsid->val[1])
1570-
return -ENODEV;
1639+
fsid->sb = dentry->d_sb;
1640+
if (!fsid->id.val[0] && !fsid->id.val[1]) {
1641+
err = -ENODEV;
1642+
goto weak;
1643+
}
15711644

15721645
/*
15731646
* Make sure dentry is not of a filesystem subvolume (e.g. btrfs)
@@ -1577,11 +1650,18 @@ static int fanotify_test_fsid(struct dentry *dentry, __kernel_fsid_t *fsid)
15771650
if (err)
15781651
return err;
15791652

1580-
if (root_fsid.val[0] != fsid->val[0] ||
1581-
root_fsid.val[1] != fsid->val[1])
1582-
return -EXDEV;
1653+
if (!fanotify_fsid_equal(&root_fsid, &fsid->id)) {
1654+
err = -EXDEV;
1655+
goto weak;
1656+
}
15831657

1658+
fsid->weak = false;
15841659
return 0;
1660+
1661+
weak:
1662+
/* Allow weak fsid when marking inodes */
1663+
fsid->weak = true;
1664+
return (mark_type == FAN_MARK_INODE) ? 0 : err;
15851665
}
15861666

15871667
/* Check if filesystem can encode a unique fid */
@@ -1665,7 +1745,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
16651745
struct fsnotify_group *group;
16661746
struct fd f;
16671747
struct path path;
1668-
__kernel_fsid_t __fsid, *fsid = NULL;
1748+
struct fan_fsid __fsid, *fsid = NULL;
16691749
u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS;
16701750
unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
16711751
unsigned int mark_cmd = flags & FANOTIFY_MARK_CMD_BITS;
@@ -1817,7 +1897,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
18171897
}
18181898

18191899
if (fid_mode) {
1820-
ret = fanotify_test_fsid(path.dentry, &__fsid);
1900+
ret = fanotify_test_fsid(path.dentry, flags, &__fsid);
18211901
if (ret)
18221902
goto path_put_and_out;
18231903

@@ -1935,7 +2015,7 @@ static int __init fanotify_user_setup(void)
19352015
BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 12);
19362016
BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 11);
19372017

1938-
fanotify_mark_cache = KMEM_CACHE(fsnotify_mark,
2018+
fanotify_mark_cache = KMEM_CACHE(fanotify_mark,
19392019
SLAB_PANIC|SLAB_ACCOUNT);
19402020
fanotify_fid_event_cachep = KMEM_CACHE(fanotify_fid_event,
19412021
SLAB_PANIC);

0 commit comments

Comments
 (0)