forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PATCH] autofs4: add v5 expire logic
This patch adds expire logic for autofs direct mounts. Signed-off-by: Ian Kent <[email protected]> Cc: Al Viro <[email protected]> Cc: Christoph Hellwig <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
- Loading branch information
Showing
1 changed file
with
87 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ | |
* | ||
* Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved | ||
* Copyright 1999-2000 Jeremy Fitzhardinge <[email protected]> | ||
* Copyright 2001-2003 Ian Kent <[email protected]> | ||
* Copyright 2001-2006 Ian Kent <[email protected]> | ||
* | ||
* This file is part of the Linux kernel and is made available under | ||
* the terms of the GNU General Public License, version 2, or at your | ||
|
@@ -99,6 +99,39 @@ static struct dentry *next_dentry(struct dentry *p, struct dentry *root) | |
return list_entry(next, struct dentry, d_u.d_child); | ||
} | ||
|
||
/* | ||
* Check a direct mount point for busyness. | ||
* Direct mounts have similar expiry semantics to tree mounts. | ||
* The tree is not busy iff no mountpoints are busy and there are no | ||
* autofs submounts. | ||
*/ | ||
static int autofs4_direct_busy(struct vfsmount *mnt, | ||
struct dentry *top, | ||
unsigned long timeout, | ||
int do_now) | ||
{ | ||
DPRINTK("top %p %.*s", | ||
top, (int) top->d_name.len, top->d_name.name); | ||
|
||
/* Not a mountpoint - give up */ | ||
if (!d_mountpoint(top)) | ||
return 1; | ||
|
||
/* If it's busy update the expiry counters */ | ||
if (!may_umount_tree(mnt)) { | ||
struct autofs_info *ino = autofs4_dentry_ino(top); | ||
if (ino) | ||
ino->last_used = jiffies; | ||
return 1; | ||
} | ||
|
||
/* Timeout of a direct mount is determined by its top dentry */ | ||
if (!autofs4_can_expire(top, timeout, do_now)) | ||
return 1; | ||
|
||
return 0; | ||
} | ||
|
||
/* Check a directory tree of mount points for busyness | ||
* The tree is not busy iff no mountpoints are busy | ||
*/ | ||
|
@@ -208,16 +241,48 @@ static struct dentry *autofs4_check_leaves(struct vfsmount *mnt, | |
return NULL; | ||
} | ||
|
||
/* Check if we can expire a direct mount (possibly a tree) */ | ||
static struct dentry *autofs4_expire_direct(struct super_block *sb, | ||
struct vfsmount *mnt, | ||
struct autofs_sb_info *sbi, | ||
int how) | ||
{ | ||
unsigned long timeout; | ||
struct dentry *root = dget(sb->s_root); | ||
int do_now = how & AUTOFS_EXP_IMMEDIATE; | ||
|
||
if (!sbi->exp_timeout || !root) | ||
return NULL; | ||
|
||
now = jiffies; | ||
timeout = sbi->exp_timeout; | ||
|
||
/* Lock the tree as we must expire as a whole */ | ||
spin_lock(&sbi->fs_lock); | ||
if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { | ||
struct autofs_info *ino = autofs4_dentry_ino(root); | ||
|
||
/* Set this flag early to catch sys_chdir and the like */ | ||
ino->flags |= AUTOFS_INF_EXPIRING; | ||
spin_unlock(&sbi->fs_lock); | ||
return root; | ||
} | ||
spin_unlock(&sbi->fs_lock); | ||
dput(root); | ||
|
||
return NULL; | ||
} | ||
|
||
/* | ||
* Find an eligible tree to time-out | ||
* A tree is eligible if :- | ||
* - it is unused by any user process | ||
* - it has been unused for exp_timeout time | ||
*/ | ||
static struct dentry *autofs4_expire(struct super_block *sb, | ||
struct vfsmount *mnt, | ||
struct autofs_sb_info *sbi, | ||
int how) | ||
static struct dentry *autofs4_expire_indirect(struct super_block *sb, | ||
struct vfsmount *mnt, | ||
struct autofs_sb_info *sbi, | ||
int how) | ||
{ | ||
unsigned long timeout; | ||
struct dentry *root = sb->s_root; | ||
|
@@ -249,7 +314,12 @@ static struct dentry *autofs4_expire(struct super_block *sb, | |
dentry = dget(dentry); | ||
spin_unlock(&dcache_lock); | ||
|
||
/* Case 1: indirect mount or top level direct mount */ | ||
/* | ||
* 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); | ||
|
@@ -283,7 +353,10 @@ static struct dentry *autofs4_expire(struct super_block *sb, | |
break; | ||
} | ||
spin_unlock(&sbi->fs_lock); | ||
/* Case 3: direct mount, expire individual leaves */ | ||
/* | ||
* Case 3: pseudo direct mount, expire individual leaves | ||
* (autofs-4.1). | ||
*/ | ||
} else { | ||
expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); | ||
if (expired) { | ||
|
@@ -325,7 +398,7 @@ int autofs4_expire_run(struct super_block *sb, | |
pkt.hdr.proto_version = sbi->version; | ||
pkt.hdr.type = autofs_ptype_expire; | ||
|
||
if ((dentry = autofs4_expire(sb, mnt, sbi, 0)) == NULL) | ||
if ((dentry = autofs4_expire_indirect(sb, mnt, sbi, 0)) == NULL) | ||
return -EAGAIN; | ||
|
||
pkt.len = dentry->d_name.len; | ||
|
@@ -351,7 +424,12 @@ int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt, | |
if (arg && get_user(do_now, arg)) | ||
return -EFAULT; | ||
|
||
if ((dentry = autofs4_expire(sb, mnt, sbi, do_now)) != NULL) { | ||
if (sbi->type & AUTOFS_TYP_DIRECT) | ||
dentry = autofs4_expire_direct(sb, mnt, sbi, do_now); | ||
else | ||
dentry = autofs4_expire_indirect(sb, mnt, sbi, do_now); | ||
|
||
if (dentry) { | ||
struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
|
||
/* This is synchronous because it makes the daemon a | ||
|