Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/kern Finish previous, evaluate the lowest mount on first...



details:   https://anonhg.NetBSD.org/src/rev/560eb62c2405
branches:  trunk
changeset: 368882:560eb62c2405
user:      hannken <hannken%NetBSD.org@localhost>
date:      Thu Aug 11 10:17:44 2022 +0000

description:
Finish previous, evaluate the lowest mount on first access
to "struct mount_info" and store it here so we no longer
derefence the "struct mount" from fstrans_alloc_lwp_info().

Reported-by: syzbot+5a79214d043395b550d8%syzkaller.appspotmail.com@localhost

diffstat:

 sys/kern/vfs_trans.c |  76 ++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 54 insertions(+), 22 deletions(-)

diffs (161 lines):

diff -r 50281785a498 -r 560eb62c2405 sys/kern/vfs_trans.c
--- a/sys/kern/vfs_trans.c      Wed Aug 10 13:38:26 2022 +0000
+++ b/sys/kern/vfs_trans.c      Thu Aug 11 10:17:44 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vfs_trans.c,v 1.66 2022/07/08 07:42:47 hannken Exp $   */
+/*     $NetBSD: vfs_trans.c,v 1.67 2022/08/11 10:17:44 hannken Exp $   */
 
 /*-
  * Copyright (c) 2007, 2020 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_trans.c,v 1.66 2022/07/08 07:42:47 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_trans.c,v 1.67 2022/08/11 10:17:44 hannken Exp $");
 
 /*
  * File system transaction operations.
@@ -87,6 +87,7 @@
        SLIST_ENTRY(fstrans_mount_info) fmi_hash;
        LIST_HEAD(, fscow_handler) fmi_cow_handler;
        struct mount *fmi_mount;
+       struct fstrans_mount_info *fmi_lower_info;
        struct lwp *fmi_owner;
 };
 SLIST_HEAD(fstrans_mount_hashhead, fstrans_mount_info);
@@ -229,13 +230,29 @@
 fstrans_mount_get(struct mount *mp)
 {
        uint32_t indx;
-       struct fstrans_mount_info *fmi;
+       struct fstrans_mount_info *fmi, *fmi_lower;
 
        KASSERT(mutex_owned(&fstrans_lock));
 
        indx = fstrans_mount_hash(mp);
        SLIST_FOREACH(fmi, &fstrans_mount_hashtab[indx], fmi_hash) {
                if (fmi->fmi_mount == mp) {
+                       if (__predict_false(mp->mnt_lower != NULL &&
+                           fmi->fmi_lower_info == NULL)) {
+                               /*
+                                * Intern the lower/lowest mount into
+                                * this mount info on first lookup.
+                                */
+                               KASSERT(fmi->fmi_ref_cnt == 1);
+
+                               fmi_lower = fstrans_mount_get(mp->mnt_lower);
+                               if (fmi_lower && fmi_lower->fmi_lower_info)
+                                       fmi_lower = fmi_lower->fmi_lower_info;
+                               if (fmi_lower == NULL)
+                                       return NULL;
+                               fmi->fmi_lower_info = fmi_lower;
+                               fmi->fmi_lower_info->fmi_ref_cnt += 1;
+                       }
                        return fmi;
                }
        }
@@ -262,6 +279,9 @@
        KASSERT(LIST_FIRST(&fmi->fmi_cow_handler) == NULL);
        KASSERT(fmi->fmi_owner == NULL);
 
+       if (fmi->fmi_lower_info)
+               fstrans_mount_dtor(fmi->fmi_lower_info);
+
        KASSERT(fstrans_gone_count > 0);
        fstrans_gone_count -= 1;
 
@@ -287,6 +307,7 @@
        LIST_INIT(&newfmi->fmi_cow_handler);
        newfmi->fmi_cow_change = false;
        newfmi->fmi_mount = mp;
+       newfmi->fmi_lower_info = NULL;
        newfmi->fmi_owner = NULL;
 
        mutex_enter(&fstrans_lock);
@@ -374,7 +395,7 @@
 static struct fstrans_lwp_info *
 fstrans_alloc_lwp_info(struct mount *mp)
 {
-       struct fstrans_lwp_info *fli;
+       struct fstrans_lwp_info *fli, *fli_lower;
        struct fstrans_mount_info *fmi;
 
        for (fli = curlwp->l_fstrans; fli; fli = fli->fli_succ) {
@@ -383,6 +404,32 @@
        }
 
        /*
+        * Lookup mount info and get lower mount per lwp info.
+        */
+       mutex_enter(&fstrans_lock);
+       fmi = fstrans_mount_get(mp);
+       if (fmi == NULL) {
+               mutex_exit(&fstrans_lock);
+               return NULL;
+       }
+       fmi->fmi_ref_cnt += 1;
+       mutex_exit(&fstrans_lock);
+
+       if (fmi->fmi_lower_info) {
+               fli_lower =
+                   fstrans_alloc_lwp_info(fmi->fmi_lower_info->fmi_mount);
+               if (fli_lower == NULL) {
+                       mutex_enter(&fstrans_lock);
+                       fstrans_mount_dtor(fmi);
+                       mutex_exit(&fstrans_lock);
+
+                       return NULL;
+               }
+       } else {
+               fli_lower = NULL;
+       }
+
+       /*
         * Allocate a new entry.
         */
        fli = pool_cache_get(fstrans_lwp_cache, PR_WAITOK);
@@ -395,30 +442,18 @@
        KASSERT(fli->fli_self == NULL);
 
        /*
-        * Attach the mount info if it is valid.
+        * Attach the mount info and alias.
         */
 
-       mutex_enter(&fstrans_lock);
-       fmi = fstrans_mount_get(mp);
-       if (fmi == NULL) {
-               mutex_exit(&fstrans_lock);
-               pool_cache_put(fstrans_lwp_cache, fli);
-               return NULL;
-       }
        fli->fli_self = curlwp;
        fli->fli_mount = mp;
        fli->fli_mountinfo = fmi;
-       fmi->fmi_ref_cnt += 1;
-       do {
-               mp = mp->mnt_lower;
-       } while (mp && mp->mnt_lower);
-       mutex_exit(&fstrans_lock);
 
        fli->fli_succ = curlwp->l_fstrans;
        curlwp->l_fstrans = fli;
 
-       if (mp) {
-               fli->fli_alias = fstrans_alloc_lwp_info(mp);
+       if (fli_lower) {
+               fli->fli_alias = fli_lower;
                fli->fli_alias->fli_alias_cnt++;
                fli = fli->fli_alias;
        }
@@ -499,9 +534,6 @@
 
        s = pserialize_read_enter();
        if (__predict_true(grant_lock(fmi, lock_type))) {
-
-               KASSERT(!fmi->fmi_gone);
-
                fli->fli_trans_cnt = 1;
                fli->fli_lock_type = lock_type;
                pserialize_read_exit(s);



Home | Main Index | Thread Index | Old Index