|
@@ -339,6 +339,89 @@ out:
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+/* Check if 'dentry' should expire, or return a nearby
|
|
|
+ * dentry that is suitable.
|
|
|
+ * If returned dentry is different from arg dentry,
|
|
|
+ * then a dget() reference was taken, else not.
|
|
|
+ */
|
|
|
+static struct dentry *should_expire(struct dentry *dentry,
|
|
|
+ struct vfsmount *mnt,
|
|
|
+ unsigned long timeout,
|
|
|
+ int how)
|
|
|
+{
|
|
|
+ int do_now = how & AUTOFS_EXP_IMMEDIATE;
|
|
|
+ int exp_leaves = how & AUTOFS_EXP_LEAVES;
|
|
|
+ struct autofs_info *ino = autofs4_dentry_ino(dentry);
|
|
|
+ unsigned int ino_count;
|
|
|
+
|
|
|
+ /* No point expiring a pending mount */
|
|
|
+ if (ino->flags & AUTOFS_INF_PENDING)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Case 1: (i) indirect mount or top level pseudo direct mount
|
|
|
+ * (autofs-4.1).
|
|
|
+ * (ii) indirect mount with offset mount, check the "/"
|
|
|
+ * offset (autofs-5.0+).
|
|
|
+ */
|
|
|
+ if (d_mountpoint(dentry)) {
|
|
|
+ DPRINTK("checking mountpoint %p %.*s",
|
|
|
+ dentry, (int)dentry->d_name.len, dentry->d_name.name);
|
|
|
+
|
|
|
+ /* Can we umount this guy */
|
|
|
+ if (autofs4_mount_busy(mnt, dentry))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ /* Can we expire this guy */
|
|
|
+ if (autofs4_can_expire(dentry, timeout, do_now))
|
|
|
+ return dentry;
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)) {
|
|
|
+ DPRINTK("checking symlink %p %.*s",
|
|
|
+ dentry, (int)dentry->d_name.len, dentry->d_name.name);
|
|
|
+ /*
|
|
|
+ * A symlink can't be "busy" in the usual sense so
|
|
|
+ * just check last used for expire timeout.
|
|
|
+ */
|
|
|
+ if (autofs4_can_expire(dentry, timeout, do_now))
|
|
|
+ return dentry;
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (simple_empty(dentry))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ /* Case 2: tree mount, expire iff entire tree is not busy */
|
|
|
+ if (!exp_leaves) {
|
|
|
+ /* Path walk currently on this dentry? */
|
|
|
+ ino_count = atomic_read(&ino->count) + 1;
|
|
|
+ if (d_count(dentry) > ino_count)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (!autofs4_tree_busy(mnt, dentry, timeout, do_now))
|
|
|
+ return dentry;
|
|
|
+ /*
|
|
|
+ * Case 3: pseudo direct mount, expire individual leaves
|
|
|
+ * (autofs-4.1).
|
|
|
+ */
|
|
|
+ } else {
|
|
|
+ /* Path walk currently on this dentry? */
|
|
|
+ struct dentry *expired;
|
|
|
+ ino_count = atomic_read(&ino->count) + 1;
|
|
|
+ if (d_count(dentry) > ino_count)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
|
|
|
+ if (expired) {
|
|
|
+ if (expired == dentry)
|
|
|
+ dput(dentry);
|
|
|
+ return expired;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
/*
|
|
|
* Find an eligible tree to time-out
|
|
|
* A tree is eligible if :-
|
|
@@ -353,11 +436,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
|
|
|
unsigned long timeout;
|
|
|
struct dentry *root = sb->s_root;
|
|
|
struct dentry *dentry;
|
|
|
- struct dentry *expired = NULL;
|
|
|
- int do_now = how & AUTOFS_EXP_IMMEDIATE;
|
|
|
- int exp_leaves = how & AUTOFS_EXP_LEAVES;
|
|
|
+ struct dentry *expired;
|
|
|
struct autofs_info *ino;
|
|
|
- unsigned int ino_count;
|
|
|
|
|
|
if (!root)
|
|
|
return NULL;
|
|
@@ -368,78 +448,12 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
|
|
|
dentry = NULL;
|
|
|
while ((dentry = get_next_positive_subdir(dentry, root))) {
|
|
|
spin_lock(&sbi->fs_lock);
|
|
|
- ino = autofs4_dentry_ino(dentry);
|
|
|
- /* No point expiring a pending mount */
|
|
|
- if (ino->flags & AUTOFS_INF_PENDING)
|
|
|
- goto next;
|
|
|
-
|
|
|
- /*
|
|
|
- * Case 1: (i) indirect mount or top level pseudo direct mount
|
|
|
- * (autofs-4.1).
|
|
|
- * (ii) indirect mount with offset mount, check the "/"
|
|
|
- * offset (autofs-5.0+).
|
|
|
- */
|
|
|
- if (d_mountpoint(dentry)) {
|
|
|
- DPRINTK("checking mountpoint %p %.*s",
|
|
|
- dentry, (int)dentry->d_name.len, dentry->d_name.name);
|
|
|
-
|
|
|
- /* Can we umount this guy */
|
|
|
- if (autofs4_mount_busy(mnt, dentry))
|
|
|
- goto next;
|
|
|
-
|
|
|
- /* Can we expire this guy */
|
|
|
- if (autofs4_can_expire(dentry, timeout, do_now)) {
|
|
|
- expired = dentry;
|
|
|
- goto found;
|
|
|
- }
|
|
|
- goto next;
|
|
|
- }
|
|
|
-
|
|
|
- if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)) {
|
|
|
- DPRINTK("checking symlink %p %.*s",
|
|
|
- dentry, (int)dentry->d_name.len, dentry->d_name.name);
|
|
|
- /*
|
|
|
- * A symlink can't be "busy" in the usual sense so
|
|
|
- * just check last used for expire timeout.
|
|
|
- */
|
|
|
- if (autofs4_can_expire(dentry, timeout, do_now)) {
|
|
|
- expired = dentry;
|
|
|
- goto found;
|
|
|
- }
|
|
|
- goto next;
|
|
|
- }
|
|
|
-
|
|
|
- if (simple_empty(dentry))
|
|
|
- goto next;
|
|
|
-
|
|
|
- /* Case 2: tree mount, expire iff entire tree is not busy */
|
|
|
- if (!exp_leaves) {
|
|
|
- /* Path walk currently on this dentry? */
|
|
|
- ino_count = atomic_read(&ino->count) + 1;
|
|
|
- if (d_count(dentry) > ino_count)
|
|
|
- goto next;
|
|
|
-
|
|
|
- if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) {
|
|
|
- expired = dentry;
|
|
|
- goto found;
|
|
|
- }
|
|
|
- /*
|
|
|
- * Case 3: pseudo direct mount, expire individual leaves
|
|
|
- * (autofs-4.1).
|
|
|
- */
|
|
|
- } else {
|
|
|
- /* Path walk currently on this dentry? */
|
|
|
- ino_count = atomic_read(&ino->count) + 1;
|
|
|
- if (d_count(dentry) > ino_count)
|
|
|
- goto next;
|
|
|
-
|
|
|
- expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
|
|
|
- if (expired) {
|
|
|
+ expired = should_expire(dentry, mnt, timeout, how);
|
|
|
+ if (expired) {
|
|
|
+ if (expired != dentry)
|
|
|
dput(dentry);
|
|
|
- goto found;
|
|
|
- }
|
|
|
+ goto found;
|
|
|
}
|
|
|
-next:
|
|
|
spin_unlock(&sbi->fs_lock);
|
|
|
}
|
|
|
return NULL;
|