[PATCH] Avoid unnecessary d_count/mnt_count dirtying in link_path_walk()

From: Paul Menage (pmenage@ensim.com)
Date: Tue Jul 16 2002 - 20:27:04 EST


On the error return path (including -ENOENT) in link_path_walk(), we
call

        unlock_nd(nd);
        path_release(nd);

This is equivalent to

        mntget(nd->mnt);
        dget_locked(nd->dentry);
        ...
        spin_unlock(&dcache_lock);
        ...
        dput(nd->dentry);
        mntput(nd->mnt);

The only way that this can have an effect other than bouncing the
d_count and mnt_count cachelines of the last resolved component is if
the dentry d_count reaches 0, and was either unhashed or had a
d_delete() method that returned true (in which case the dentry is thrown
away).

- Since no-one else can decrement the usage count to 0 while we hold
dcache_lock (due to the use of atomic_dec_and_lock() in dput()) this can
only occur if the usage count is zero originally (i.e. before we called
unlock_nd()).

- Since no-one else can unhash the dentry without dcache_lock (which we
hold) the dentry must be hashed if its reference count was originally 0.

- if dentry->d_op->d_delete() exists, then plausibly it could return 1
to request that the dentry by unhashed. But this failed lookup has no
noticable side-effects (other than perhaps setting DCACHE_REFERENCED)
and might easily have not occurred (and hence d_delete() not called). So
we can't lose correctness by not calling d_delete(), (unless the
d_delete() method would have spuriously decided to kill the dentry
purely due to it being marked DCACHE_REFERENCED, but that would be
pretty perverse).

Hence it is safe to skip the dget_locked()/dput().

The original pointer to nd->mnt came either from

- the current root/pwd (protected by dcache_lock)

- following a mount (protected by dcache_lock)

- was in nd->mnt when we called lock_nd() (and will be released when we
call mntput() on nd->old_mnt.

Hence it is safe to skip the mntget()/mntput()

This patch adds release_locked_nd(), which skips the dget_locked() and
mntget(), and makes use of it in the error .

Paul

diff -X /mnt/elbrus/home/pmenage/dontdiff -Naur linux-2.5.26/fs/namei.c linux-2.5.26-unlocknd/fs/namei.c
--- linux-2.5.26/fs/namei.c Tue Jul 16 16:49:31 2002
+++ linux-2.5.26-unlocknd/fs/namei.c Tue Jul 16 17:59:10 2002
@@ -275,17 +275,22 @@
 }
 
 /*for fastwalking*/
-static inline void unlock_nd(struct nameidata *nd)
+static inline void release_locked_nd(struct nameidata *nd)
 {
         struct vfsmount *mnt = nd->old_mnt;
         struct dentry *dentry = nd->old_dentry;
- mntget(nd->mnt);
- dget_locked(nd->dentry);
         nd->old_mnt = NULL;
         nd->old_dentry = NULL;
         spin_unlock(&dcache_lock);
         dput(dentry);
         mntput(mnt);
+}
+
+static inline void unlock_nd(struct nameidata *nd)
+{
+ mntget(nd->mnt);
+ dget_locked(nd->dentry);
+ release_locked_nd(nd);
 }
 
 static inline void lock_nd(struct nameidata *nd)
@@ -737,8 +742,8 @@
                 mntput(pinned.mnt);
                 return 0;
         }
- unlock_nd(nd);
- path_release(nd);
+
+ release_locked_nd(nd);
 return_err:
         dput(pinned.dentry);
         mntput(pinned.mnt);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Jul 23 2002 - 22:00:21 EST