hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/fs/notify/mark.c
....@@ -1,19 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
3
- *
4
- * This program is free software; you can redistribute it and/or modify
5
- * it under the terms of the GNU General Public License as published by
6
- * the Free Software Foundation; either version 2, or (at your option)
7
- * any later version.
8
- *
9
- * This program is distributed in the hope that it will be useful,
10
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- * GNU General Public License for more details.
13
- *
14
- * You should have received a copy of the GNU General Public License
15
- * along with this program; see the file COPYING. If not, write to
16
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
174 */
185
196 /*
....@@ -82,6 +69,7 @@
8269 #include <linux/slab.h>
8370 #include <linux/spinlock.h>
8471 #include <linux/srcu.h>
72
+#include <linux/ratelimit.h>
8573
8674 #include <linux/atomic.h>
8775
....@@ -115,6 +103,8 @@
115103 return &fsnotify_conn_inode(conn)->i_fsnotify_mask;
116104 else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT)
117105 return &fsnotify_conn_mount(conn)->mnt_fsnotify_mask;
106
+ else if (conn->type == FSNOTIFY_OBJ_TYPE_SB)
107
+ return &fsnotify_conn_sb(conn)->s_fsnotify_mask;
118108 return NULL;
119109 }
120110
....@@ -195,6 +185,8 @@
195185 atomic_long_inc(&inode->i_sb->s_fsnotify_inode_refs);
196186 } else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
197187 fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0;
188
+ } else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) {
189
+ fsnotify_conn_sb(conn)->s_fsnotify_mask = 0;
198190 }
199191
200192 rcu_assign_pointer(*(conn->obj), NULL);
....@@ -234,13 +226,13 @@
234226
235227 void fsnotify_put_mark(struct fsnotify_mark *mark)
236228 {
237
- struct fsnotify_mark_connector *conn;
229
+ struct fsnotify_mark_connector *conn = READ_ONCE(mark->connector);
238230 void *objp = NULL;
239231 unsigned int type = FSNOTIFY_OBJ_TYPE_DETACHED;
240232 bool free_conn = false;
241233
242234 /* Catch marks that were actually never attached to object */
243
- if (!mark->connector) {
235
+ if (!conn) {
244236 if (refcount_dec_and_test(&mark->refcnt))
245237 fsnotify_final_mark_destroy(mark);
246238 return;
....@@ -250,10 +242,9 @@
250242 * We have to be careful so that traversals of obj_list under lock can
251243 * safely grab mark reference.
252244 */
253
- if (!refcount_dec_and_lock(&mark->refcnt, &mark->connector->lock))
245
+ if (!refcount_dec_and_lock(&mark->refcnt, &conn->lock))
254246 return;
255247
256
- conn = mark->connector;
257248 hlist_del_init_rcu(&mark->obj_list);
258249 if (hlist_empty(&conn->list)) {
259250 objp = fsnotify_detach_connector_from_object(conn, &type);
....@@ -261,7 +252,7 @@
261252 } else {
262253 __fsnotify_recalc_mask(conn);
263254 }
264
- mark->connector = NULL;
255
+ WRITE_ONCE(mark->connector, NULL);
265256 spin_unlock(&conn->lock);
266257
267258 fsnotify_drop_object(type, objp);
....@@ -285,6 +276,7 @@
285276 queue_delayed_work(system_unbound_wq, &reaper_work,
286277 FSNOTIFY_REAPER_DELAY);
287278 }
279
+EXPORT_SYMBOL_GPL(fsnotify_put_mark);
288280
289281 /*
290282 * Get mark reference when we found the mark via lockless traversal of object
....@@ -333,13 +325,16 @@
333325 }
334326
335327 bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
328
+ __releases(&fsnotify_mark_srcu)
336329 {
337330 int type;
338331
339332 fsnotify_foreach_obj_type(type) {
340333 /* This can fail if mark is being removed */
341
- if (!fsnotify_get_mark_safe(iter_info->marks[type]))
334
+ if (!fsnotify_get_mark_safe(iter_info->marks[type])) {
335
+ __release(&fsnotify_mark_srcu);
342336 goto fail;
337
+ }
343338 }
344339
345340 /*
....@@ -358,6 +353,7 @@
358353 }
359354
360355 void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info)
356
+ __acquires(&fsnotify_mark_srcu)
361357 {
362358 int type;
363359
....@@ -434,11 +430,12 @@
434430 void fsnotify_destroy_mark(struct fsnotify_mark *mark,
435431 struct fsnotify_group *group)
436432 {
437
- mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
433
+ mutex_lock(&group->mark_mutex);
438434 fsnotify_detach_mark(mark);
439435 mutex_unlock(&group->mark_mutex);
440436 fsnotify_free_mark(mark);
441437 }
438
+EXPORT_SYMBOL_GPL(fsnotify_destroy_mark);
442439
443440 /*
444441 * Sorting function for lists of fsnotify marks.
....@@ -477,7 +474,8 @@
477474 }
478475
479476 static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp,
480
- unsigned int type)
477
+ unsigned int type,
478
+ __kernel_fsid_t *fsid)
481479 {
482480 struct inode *inode = NULL;
483481 struct fsnotify_mark_connector *conn;
....@@ -489,6 +487,14 @@
489487 INIT_HLIST_HEAD(&conn->list);
490488 conn->type = type;
491489 conn->obj = connp;
490
+ /* Cache fsid of filesystem containing the object */
491
+ if (fsid) {
492
+ conn->fsid = *fsid;
493
+ conn->flags = FSNOTIFY_CONN_FLAG_HAS_FSID;
494
+ } else {
495
+ conn->fsid.val[0] = conn->fsid.val[1] = 0;
496
+ conn->flags = 0;
497
+ }
492498 if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
493499 inode = igrab(fsnotify_conn_inode(conn));
494500 /*
....@@ -540,7 +546,7 @@
540546 */
541547 static int fsnotify_add_mark_list(struct fsnotify_mark *mark,
542548 fsnotify_connp_t *connp, unsigned int type,
543
- int allow_dups)
549
+ int allow_dups, __kernel_fsid_t *fsid)
544550 {
545551 struct fsnotify_mark *lmark, *last = NULL;
546552 struct fsnotify_mark_connector *conn;
....@@ -549,15 +555,41 @@
549555
550556 if (WARN_ON(!fsnotify_valid_obj_type(type)))
551557 return -EINVAL;
558
+
559
+ /* Backend is expected to check for zero fsid (e.g. tmpfs) */
560
+ if (fsid && WARN_ON_ONCE(!fsid->val[0] && !fsid->val[1]))
561
+ return -ENODEV;
562
+
552563 restart:
553564 spin_lock(&mark->lock);
554565 conn = fsnotify_grab_connector(connp);
555566 if (!conn) {
556567 spin_unlock(&mark->lock);
557
- err = fsnotify_attach_connector_to_object(connp, type);
568
+ err = fsnotify_attach_connector_to_object(connp, type, fsid);
558569 if (err)
559570 return err;
560571 goto restart;
572
+ } else if (fsid && !(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID)) {
573
+ conn->fsid = *fsid;
574
+ /* Pairs with smp_rmb() in fanotify_get_fsid() */
575
+ smp_wmb();
576
+ conn->flags |= FSNOTIFY_CONN_FLAG_HAS_FSID;
577
+ } else if (fsid && (conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID) &&
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;
561593 }
562594
563595 /* is mark the first mark? */
....@@ -588,7 +620,12 @@
588620 /* mark should be the last entry. last is the current last entry */
589621 hlist_add_behind_rcu(&mark->obj_list, &last->obj_list);
590622 added:
591
- mark->connector = conn;
623
+ /*
624
+ * Since connector is attached to object using cmpxchg() we are
625
+ * guaranteed that connector initialization is fully visible by anyone
626
+ * seeing mark->connector set.
627
+ */
628
+ WRITE_ONCE(mark->connector, conn);
592629 out_err:
593630 spin_unlock(&conn->lock);
594631 spin_unlock(&mark->lock);
....@@ -602,7 +639,7 @@
602639 */
603640 int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
604641 fsnotify_connp_t *connp, unsigned int type,
605
- int allow_dups)
642
+ int allow_dups, __kernel_fsid_t *fsid)
606643 {
607644 struct fsnotify_group *group = mark->group;
608645 int ret = 0;
....@@ -623,7 +660,7 @@
623660 fsnotify_get_mark(mark); /* for g_list */
624661 spin_unlock(&mark->lock);
625662
626
- ret = fsnotify_add_mark_list(mark, connp, type, allow_dups);
663
+ ret = fsnotify_add_mark_list(mark, connp, type, allow_dups, fsid);
627664 if (ret)
628665 goto err;
629666
....@@ -644,16 +681,17 @@
644681 }
645682
646683 int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp,
647
- unsigned int type, int allow_dups)
684
+ unsigned int type, int allow_dups, __kernel_fsid_t *fsid)
648685 {
649686 int ret;
650687 struct fsnotify_group *group = mark->group;
651688
652689 mutex_lock(&group->mark_mutex);
653
- ret = fsnotify_add_mark_locked(mark, connp, type, allow_dups);
690
+ ret = fsnotify_add_mark_locked(mark, connp, type, allow_dups, fsid);
654691 mutex_unlock(&group->mark_mutex);
655692 return ret;
656693 }
694
+EXPORT_SYMBOL_GPL(fsnotify_add_mark);
657695
658696 /*
659697 * Given a list of marks, find the mark associated with given group. If found
....@@ -680,6 +718,7 @@
680718 spin_unlock(&conn->lock);
681719 return NULL;
682720 }
721
+EXPORT_SYMBOL_GPL(fsnotify_find_mark);
683722
684723 /* Clear any marks in a group with given type mask */
685724 void fsnotify_clear_marks_by_group(struct fsnotify_group *group,
....@@ -703,7 +742,7 @@
703742 * move marks to free to to_free list in one go and then free marks in
704743 * to_free list one by one.
705744 */
706
- mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
745
+ mutex_lock(&group->mark_mutex);
707746 list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
708747 if ((1U << mark->connector->type) & type_mask)
709748 list_move(&mark->g_list, &to_free);
....@@ -712,7 +751,7 @@
712751
713752 clear:
714753 while (1) {
715
- mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
754
+ mutex_lock(&group->mark_mutex);
716755 if (list_empty(head)) {
717756 mutex_unlock(&group->mark_mutex);
718757 break;
....@@ -776,7 +815,9 @@
776815 refcount_set(&mark->refcnt, 1);
777816 fsnotify_get_group(group);
778817 mark->group = group;
818
+ WRITE_ONCE(mark->connector, NULL);
779819 }
820
+EXPORT_SYMBOL_GPL(fsnotify_init_mark);
780821
781822 /*
782823 * Destroy all marks in destroy_list, waits for SRCU period to finish before
....@@ -805,3 +846,4 @@
805846 {
806847 flush_delayed_work(&reaper_work);
807848 }
849
+EXPORT_SYMBOL_GPL(fsnotify_wait_marks_destroyed);