* [PATCH 1/3] Update the automount document to reflect the new VFS automounting hook
@ 2011-03-03 16:57 David Howells
2011-03-03 16:57 ` [PATCH 2/3] Make VFS handle mount autoexpiry David Howells
2011-03-03 16:58 ` [PATCH 3/3] autofs4: Use no_printk() for no-op DPRINTK() and use __VA_ARGS__ too David Howells
0 siblings, 2 replies; 3+ messages in thread
From: David Howells @ 2011-03-03 16:57 UTC (permalink / raw)
To: viro, hch, raven; +Cc: linux-devel, autofs, linux-kernel, David Howells
Update the automount document to reflect the new VFS automounting hook
(d_automount()).
Signed-off-by: David Howells <dhowells@redhat.com>
---
Documentation/filesystems/automount-support.txt | 150 ++++++++++++++++-------
Documentation/filesystems/vfs.txt | 3
fs/namei.c | 1
3 files changed, 109 insertions(+), 45 deletions(-)
diff --git a/Documentation/filesystems/automount-support.txt b/Documentation/filesystems/automount-support.txt
index 7cac200..c0512b7 100644
--- a/Documentation/filesystems/automount-support.txt
+++ b/Documentation/filesystems/automount-support.txt
@@ -1,59 +1,117 @@
-Support is available for filesystems that wish to do automounting support (such
-as kAFS which can be found in fs/afs/). This facility includes allowing
-in-kernel mounts to be performed and mountpoint degradation to be
-requested. The latter can also be requested by userspace.
+ ============================
+ VFS SUPPORT FOR AUTOMOUNTING
+ ============================
+
+Support is available for filesystems that wish to do automounting (such as AFS,
+CIFS, NFS and autofs). This facility includes allowing in-kernel mounts to be
+performed and mountpoint expiry to be requested.
+
+An automount point is a dentry that has DCACHE_NEED_AUTOMOUNT set upon it. It
+must also be furnished with a d_automount() dentry operation.
+
+A d_automount() dentry op can be given to any directory or other file type. It
+will be ignored unless the flag is also set. This means that the dentry op
+table can be shared with non-automount point objects.
+
+An S_AUTOMOUNT inode flag is also defined that can be used to mark an inode as
+being an automount point. This is automatically propagated to the dentry by
+__d_instantiate(), and thus those dcache functions that call it, such as
+d_add().
+
+
+==============================
+THE AUTOMOUNT DENTRY OPERATION
+==============================
+
+The automount dentry operation must be a function matching the following
+prototype:
+
+ struct vfsmount *foo_d_automount(struct path *mountpoint);
+
+It is passed a pointer to a path node describing the directory to be mounted
+upon. It is assumed that the data associated with this directory will be
+sufficient to detail the volume or device that should be mounted on this
+mountpoint.
+
+This function will be called from pathwalk in refwalk mode with no locks held,
+so it is safe to sleep here (it is assumed that you will need to sleep to get
+the new superblock and root directory).
+
+On return, under normal successful conditions, the function should return the
+new vfsmount and the caller will mount it. If the mount should expire at some
+future date, it should be placed on the expiry list with mnt_set_expiry()
+before returning and the expiry procedure started. The new vfsmount should be
+returned with at least two references upon so that if it is on an expiry list,
+mark_mounts_for_expiry() won't delete it if the caller has to sleep.
+
+The function may return NULL if it managed to mount on the mountpoint itself
+(say by invoking a userspace daemon). It should not use mountpoint->mnt to do
+this. In this case, the caller will loop around and simply check for a new
+mount having appeared on this dentry in this namespace.
+
+The function may return -EISDIR to indicate it wants the caller to ignore the
+automount flag and let the user see the underlying directory. This is needed
+to have a userspace daemon perform the mount.
+
+Otherwise the function should return an error code to terminate pathwalk with
+that error.
+
+If a new vfsmount is returned, but the caller fails to perform do_add_mount()
+upon it, then then the vfsmount will be unlinked from the expiry list and both
+the refs upon it will be released.
+
+Note that if this function is called more than 40 times in a given pathwalk,
+-ELOOP will be given instead of calling this again. The check makes use of the
+symbolic link handling variables, so any symbolic links traversed will reduce
+this number.
======================
IN-KERNEL AUTOMOUNTING
======================
-A filesystem can now mount another filesystem on one of its directories by the
-following procedure:
+A filesystem will now normally mount another filesystem on one of its
+directories by the following procedure:
- (1) Give the directory a follow_link() operation.
+ (1) Set the S_AUTOMOUNT flag on the inode for an automount directory. If the
+ filesystem's automount points are not directories (e.g. AFS), they must be
+ converted to be so.
- When the directory is accessed, the follow_link op will be called, and
- it will be provided with the location of the mountpoint in the nameidata
- structure (vfsmount and dentry).
+ (2) Give dentries of such directories a d_automount() dentry operation. When
+ an attempt is made to traverse the directory, the d_automount() op will be
+ called, and it will be provided with the location of the mountpoint in the
+ VFS directory tree.
- (2) Have the follow_link() op do the following steps:
+ (2) Have the d_automount() op do the following steps:
(a) Call vfs_kern_mount() to call the appropriate filesystem to set up a
superblock and gain a vfsmount structure representing it.
- (b) Copy the nameidata provided as an argument and substitute the dentry
- argument into it the copy.
-
- (c) Call do_add_mount() to install the new vfsmount into the namespace's
- mountpoint tree, thus making it accessible to userspace. Use the
- nameidata set up in (b) as the destination.
+ (b) The ref count of the vfsmount must be incremented. This will prevent
+ automatic expiry if that is used. The increment is mandatory either
+ way.
- If the mountpoint will be automatically expired, then do_add_mount()
- should also be given the location of an expiration list (see further
- down).
+ (c) If the new vfsmount will be automatically expired, then
+ mnt_set_expiry() should be called for it and the expiry procedure
+ started.
- (d) Release the path in the nameidata argument and substitute in the new
- vfsmount and its root dentry. The ref counts on these will need
- incrementing.
+ (d) Return the vfsmount to the caller to be added into the mount tree.
Then from userspace, you can just do something like:
- [root@andromeda root]# mount -t afs \#root.afs. /afs
- [root@andromeda root]# ls /afs
- asd cambridge cambridge.redhat.com grand.central.org
- [root@andromeda root]# ls /afs/cambridge
- afsdoc
- [root@andromeda root]# ls /afs/cambridge/afsdoc/
- ChangeLog html LICENSE pdf RELNOTES-1.2.2
+ root# mount -t afs "#grand.central.org:root.cell." /afs -o autocell
+ root# ls /afs
+ archive/ cvs/ doc/ local/ project/ service/ software/ user/ www/
+ root# ls /afs/archive/linuxdev/fedora9/i386/repodata/
+ filelists.xml.gz other.xml.gz primary.xml.gz repomd.xml
And then if you look in the mountpoint catalogue, you'll see something like:
[root@andromeda root]# cat /proc/mounts
...
- #root.afs. /afs afs rw 0 0
- #root.cell. /afs/cambridge.redhat.com afs rw 0 0
- #afsdoc. /afs/cambridge.redhat.com/afsdoc afs rw 0 0
+ #grand.central.org:root.cell. /afs afs rw,relatime,autocell 0 0
+ #root.archive. /afs/archive afs rw,relatime,cell=grand.central.org 0 0
+ #a.linuxdev. /afs/archive/linuxdev afs rw,relatime,cell=grand.central.org 0 0
===========================
@@ -65,28 +123,30 @@ mountpoint to be expired in the automounting procedure outlined above.
To do expiration, you need to follow these steps:
- (3) Create at least one list off which the vfsmounts to be expired can be
- hung. Access to this list will be governed by the vfsmount_lock.
+ (1) Create at least one list off which the vfsmounts to be expired can be
+ hung. Access to this list will be governed by namespace_sem and
+ vfsmount_lock.
- (4) In step (2c) above, the call to do_add_mount() should be provided with a
- pointer to this list. It will hang the vfsmount off of it if it succeeds.
+ (2) In step (2c) above, mnt_set_expiry() should be called with a pointer to
+ this list. It will add the vfsmount to the list with the appropriate locks
+ held.
- (5) When you want mountpoints to be expired, call mark_mounts_for_expiry()
- with a pointer to this list. This will process the list, marking every
- vfsmount thereon for potential expiry on the next call.
+ (3) To cause mountpoints to expire, call mark_mounts_for_expiry() with a
+ pointer to this list. This will process the list, marking every vfsmount
+ thereon for potential expiry on the next call.
If a vfsmount was already flagged for expiry, and if its usage count is 1
- (it's only referenced by its parent vfsmount), then it will be deleted
+ (ie. it's only referenced by its parent vfsmount), then it will be deleted
from the namespace and thrown away (effectively unmounted).
It may prove simplest to simply call this at regular intervals, using
some sort of timed event to drive it.
-The expiration flag is cleared by calls to mntput. This means that expiration
+The expiration flag is cleared by calls to mntput. This means that expiration
will only happen on the second expiration request after the last time the
mountpoint was accessed.
-If a mountpoint is moved, it gets removed from the expiration list. If a bind
+If a mountpoint is moved, it gets removed from the expiration list. If a bind
mount is made on an expirable mount, the new vfsmount will not be on the
expiration list and will not expire.
@@ -101,8 +161,8 @@ USERSPACE DRIVEN EXPIRY
As an alternative, it is possible for userspace to request expiry of any
mountpoint (though some will be rejected - the current process's idea of the
-rootfs for example). It does this by passing the MNT_EXPIRE flag to
-umount(). This flag is considered incompatible with MNT_FORCE and MNT_DETACH.
+rootfs for example). It does this by passing the MNT_EXPIRE flag to umount().
+This flag is considered incompatible with MNT_FORCE and MNT_DETACH.
If the mountpoint in question is in referenced by something other than
umount() or its parent mountpoint, an EBUSY error will be returned and the
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 94cf97b..c6878a0 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -952,6 +952,9 @@ struct dentry_operations {
dentry. This is set by __d_instantiate() if S_AUTOMOUNT is set on the
inode being added.
+ See Documentation/filesystems/automount-support.txt for more
+ information.
+
d_manage: called to allow the filesystem to manage the transition from a
dentry (optional). This allows autofs, for example, to hold up clients
waiting to explore behind a 'mountpoint' whilst letting the daemon go
diff --git a/fs/namei.c b/fs/namei.c
index 0087cf9..97c92a2 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -869,6 +869,7 @@ int follow_up(struct path *path)
* Perform an automount
* - return -EISDIR to tell follow_managed() to stop and return the path we
* were called with.
+ * - see Documentation/filesystems/automount-support.txt.
*/
static int follow_automount(struct path *path, unsigned flags,
bool *need_mntput)
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 2/3] Make VFS handle mount autoexpiry
2011-03-03 16:57 [PATCH 1/3] Update the automount document to reflect the new VFS automounting hook David Howells
@ 2011-03-03 16:57 ` David Howells
2011-03-03 16:58 ` [PATCH 3/3] autofs4: Use no_printk() for no-op DPRINTK() and use __VA_ARGS__ too David Howells
1 sibling, 0 replies; 3+ messages in thread
From: David Howells @ 2011-03-03 16:57 UTC (permalink / raw)
To: viro, hch, raven; +Cc: linux-devel, autofs, linux-kernel, David Howells
Make the VFS handle mount autoexpiry, rather than doing it in the filesystems
(such as AFS, CIFS and NFS). This simplifies the reference counting, since
do_add_mount() once again adds mounts to the expiration list, and simplifies
the filesystems since they no longer have to do anything barring set
MNT_EXPIRABLE on an expirable mount before returning it.
Additionally, provide a tuning knob to set the periodicity of the reaper in
seconds:
/proc/sys/fs/mount-expiry-period
The default is 10 minutes.
The NFS sysctl (nfs_mountpoint_timeout) is removed in its favour.
Signed-off-by: David Howells <dhowells@redhat.com>
---
Documentation/filesystems/vfs.txt | 7 +-
fs/afs/internal.h | 1
fs/afs/mntpt.c | 60 ++-------------------
fs/afs/super.c | 1
fs/cifs/cifs_dfs_ref.c | 53 ++-----------------
fs/cifs/cifsfs.c | 3 -
fs/cifs/cifsproto.h | 1
fs/namei.c | 8 +--
fs/namespace.c | 106 ++++++++++++++++---------------------
fs/nfs/client.c | 1
fs/nfs/namespace.c | 26 ---------
fs/nfs/sysctl.c | 7 --
include/linux/mount.h | 5 +-
kernel/sysctl.c | 11 ++++
14 files changed, 76 insertions(+), 214 deletions(-)
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index c6878a0..3a40c31 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -943,10 +943,9 @@ struct dentry_operations {
ordinary directory and returned to pathwalk to continue walking.
If a vfsmount is returned, the caller will attempt to mount it on the
- mountpoint and will remove the vfsmount from its expiration list in
- the case of failure. The vfsmount should be returned with 2 refs on
- it to prevent automatic expiration - the caller will clean up the
- additional ref.
+ mountpoint and will clean it up on failure. If mnt_expiry_mark is set
+ on the vfsmount, the caller will add it to the global expiration list
+ if successfully mounted and clear the mark.
This function is only used if DCACHE_NEED_AUTOMOUNT is set on the
dentry. This is set by __d_instantiate() if S_AUTOMOUNT is set on the
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 5a9b684..cb7d2c7 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -594,7 +594,6 @@ extern const struct file_operations afs_mntpt_file_operations;
extern struct vfsmount *afs_d_automount(struct path *);
extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);
-extern void afs_mntpt_kill_timer(void);
/*
* proc.c
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index aa59184..74b43b9 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -24,7 +24,6 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir,
struct dentry *dentry,
struct nameidata *nd);
static int afs_mntpt_open(struct inode *inode, struct file *file);
-static void afs_mntpt_expiry_timed_out(struct work_struct *work);
const struct file_operations afs_mntpt_file_operations = {
.open = afs_mntpt_open,
@@ -41,11 +40,6 @@ const struct inode_operations afs_autocell_inode_operations = {
.getattr = afs_getattr,
};
-static LIST_HEAD(afs_vfsmounts);
-static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out);
-
-static unsigned long afs_mntpt_expiry_timeout = 10 * 60;
-
/*
* check a symbolic link to see whether it actually encodes a mountpoint
* - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately
@@ -136,11 +130,12 @@ static int afs_mntpt_open(struct inode *inode, struct file *file)
/*
* create a vfsmount to be automounted
*/
-static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
+struct vfsmount *afs_d_automount(struct path *mountpoint)
{
struct afs_super_info *super;
struct vfsmount *mnt;
struct afs_vnode *vnode;
+ struct dentry *mntpt = mountpoint->dentry;
struct page *page;
char *devname, *options;
bool rwpath = false;
@@ -219,6 +214,9 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options);
_debug("--- mount result %p ---", mnt);
+ if (!IS_ERR(mnt))
+ mnt->mnt_expiry_mark = 1;
+
free_page((unsigned long) devname);
free_page((unsigned long) options);
_leave(" = %p", mnt);
@@ -234,51 +232,3 @@ error_no_devname:
_leave(" = %d", ret);
return ERR_PTR(ret);
}
-
-/*
- * handle an automount point
- */
-struct vfsmount *afs_d_automount(struct path *path)
-{
- struct vfsmount *newmnt;
-
- _enter("{%s,%s}", path->mnt->mnt_devname, path->dentry->d_name.name);
-
- newmnt = afs_mntpt_do_automount(path->dentry);
- if (IS_ERR(newmnt))
- return newmnt;
-
- mntget(newmnt); /* prevent immediate expiration */
- mnt_set_expiry(newmnt, &afs_vfsmounts);
- queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,
- afs_mntpt_expiry_timeout * HZ);
- _leave(" = %p {%s}", newmnt, newmnt->mnt_devname);
- return newmnt;
-}
-
-/*
- * handle mountpoint expiry timer going off
- */
-static void afs_mntpt_expiry_timed_out(struct work_struct *work)
-{
- _enter("");
-
- if (!list_empty(&afs_vfsmounts)) {
- mark_mounts_for_expiry(&afs_vfsmounts);
- queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,
- afs_mntpt_expiry_timeout * HZ);
- }
-
- _leave("");
-}
-
-/*
- * kill the AFS mountpoint timer if it's still running
- */
-void afs_mntpt_kill_timer(void)
-{
- _enter("");
-
- ASSERT(list_empty(&afs_vfsmounts));
- cancel_delayed_work_sync(&afs_mntpt_expiry_timer);
-}
diff --git a/fs/afs/super.c b/fs/afs/super.c
index fb240e8..3217a42 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -115,7 +115,6 @@ void __exit afs_fs_exit(void)
{
_enter("");
- afs_mntpt_kill_timer();
unregister_filesystem(&afs_fs_type);
if (atomic_read(&afs_count_active_inodes) != 0) {
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index 0a265ad..923a92b 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -24,29 +24,6 @@
#include "dns_resolve.h"
#include "cifs_debug.h"
-static LIST_HEAD(cifs_dfs_automount_list);
-
-static void cifs_dfs_expire_automounts(struct work_struct *work);
-static DECLARE_DELAYED_WORK(cifs_dfs_automount_task,
- cifs_dfs_expire_automounts);
-static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ;
-
-static void cifs_dfs_expire_automounts(struct work_struct *work)
-{
- struct list_head *list = &cifs_dfs_automount_list;
-
- mark_mounts_for_expiry(list);
- if (!list_empty(list))
- schedule_delayed_work(&cifs_dfs_automount_task,
- cifs_dfs_mountpoint_expiry_timeout);
-}
-
-void cifs_dfs_release_automount_timer(void)
-{
- BUG_ON(!list_empty(&cifs_dfs_automount_list));
- cancel_delayed_work_sync(&cifs_dfs_automount_task);
-}
-
/**
* cifs_get_share_name - extracts share name from UNC
* @node_name: pointer to UNC string
@@ -267,8 +244,9 @@ static void dump_referral(const struct dfs_info3_param *ref)
/*
* Create a vfsmount that we can automount
*/
-static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
+struct vfsmount *cifs_dfs_d_automount(struct path *mountpoint)
{
+ struct dentry *mntpt = mountpoint->dentry;
struct dfs_info3_param *referrals = NULL;
unsigned int num_referrals = 0;
struct cifs_sb_info *cifs_sb;
@@ -325,8 +303,10 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
full_path, referrals + i);
cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__,
referrals[i].node_name, mnt);
- if (!IS_ERR(mnt))
+ if (!IS_ERR(mnt)) {
+ mnt->mnt_expiry_mark = 1;
goto success;
+ }
}
/* no valid submounts were found; return error from get_dfs_path() by
@@ -343,28 +323,5 @@ cdda_exit:
return mnt;
}
-/*
- * Attempt to automount the referral
- */
-struct vfsmount *cifs_dfs_d_automount(struct path *path)
-{
- struct vfsmount *newmnt;
-
- cFYI(1, "in %s", __func__);
-
- newmnt = cifs_dfs_do_automount(path->dentry);
- if (IS_ERR(newmnt)) {
- cFYI(1, "leaving %s [automount failed]" , __func__);
- return newmnt;
- }
-
- mntget(newmnt); /* prevent immediate expiration */
- mnt_set_expiry(newmnt, &cifs_dfs_automount_list);
- schedule_delayed_work(&cifs_dfs_automount_task,
- cifs_dfs_mountpoint_expiry_timeout);
- cFYI(1, "leaving %s [ok]" , __func__);
- return newmnt;
-}
-
const struct inode_operations cifs_dfs_referral_inode_operations = {
};
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index f297013..c91ae83 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1067,9 +1067,6 @@ exit_cifs(void)
cFYI(DBG2, "exit_cifs");
cifs_proc_clean();
cifs_fscache_unregister();
-#ifdef CONFIG_CIFS_DFS_UPCALL
- cifs_dfs_release_automount_timer();
-#endif
#ifdef CONFIG_CIFS_UPCALL
unregister_key_type(&cifs_spnego_key_type);
#endif
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 8096f27..f3f8099 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -147,7 +147,6 @@ extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
const char *);
extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
-extern void cifs_dfs_release_automount_timer(void);
void cifs_proc_init(void);
void cifs_proc_clean(void);
diff --git a/fs/namei.c b/fs/namei.c
index 97c92a2..aac0375 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -923,11 +923,13 @@ static int follow_automount(struct path *path, unsigned flags,
return 0;
err = finish_automount(mnt, path);
-
switch (err) {
case -EBUSY:
/* Someone else made a mount here whilst we were busy */
- return 0;
+ err = 0;
+ default:
+ mntput(mnt);
+ return err;
case 0:
dput(path->dentry);
if (*need_mntput)
@@ -936,8 +938,6 @@ static int follow_automount(struct path *path, unsigned flags,
path->dentry = dget(mnt->mnt_root);
*need_mntput = true;
return 0;
- default:
- return err;
}
}
diff --git a/fs/namespace.c b/fs/namespace.c
index d1edf26..b9cb274 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -50,6 +50,11 @@ static struct list_head *mount_hashtable __read_mostly;
static struct kmem_cache *mnt_cache __read_mostly;
static struct rw_semaphore namespace_sem;
+unsigned long mnt_expiry_period = 15;
+static LIST_HEAD(mnt_expirable_mounts);
+static void do_periodic_mount_expiry(struct work_struct *);
+static DECLARE_DELAYED_WORK(periodic_mount_expiry, do_periodic_mount_expiry);
+
/* /sys/fs */
struct kobject *fs_kobj;
EXPORT_SYMBOL_GPL(fs_kobj);
@@ -1882,7 +1887,6 @@ static int do_new_mount(struct path *path, char *type, int flags,
int mnt_flags, char *name, void *data)
{
struct vfsmount *mnt;
- int err;
if (!type)
return -EINVAL;
@@ -1895,45 +1899,26 @@ static int do_new_mount(struct path *path, char *type, int flags,
if (IS_ERR(mnt))
return PTR_ERR(mnt);
- err = do_add_mount(mnt, path, mnt_flags);
- if (err)
- mntput(mnt);
- return err;
+ return do_add_mount(mnt, path, mnt_flags);
}
+/*
+ * Mount the given mount on the specified mountpoint.
+ * - does not drop the caller's ref from the mount.
+ */
int finish_automount(struct vfsmount *m, struct path *path)
{
- int err;
- /* The new mount record should have at least 2 refs to prevent it being
- * expired before we get a chance to add it
- */
- BUG_ON(mnt_get_count(m) < 2);
-
if (m->mnt_sb == path->mnt->mnt_sb &&
- m->mnt_root == path->dentry) {
- err = -ELOOP;
- goto fail;
- }
+ m->mnt_root == path->dentry)
+ return -ELOOP;
- err = do_add_mount(m, path, path->mnt->mnt_flags | MNT_SHRINKABLE);
- if (!err)
- return 0;
-fail:
- /* remove m from any expiration list it may be on */
- if (!list_empty(&m->mnt_expire)) {
- down_write(&namespace_sem);
- br_write_lock(vfsmount_lock);
- list_del_init(&m->mnt_expire);
- br_write_unlock(vfsmount_lock);
- up_write(&namespace_sem);
- }
- mntput(m);
- mntput(m);
- return err;
+ mntget(m);
+ return do_add_mount(m, path, path->mnt->mnt_flags | MNT_SHRINKABLE);
}
/*
- * add a mount into a namespace's mount tree
+ * Add a mount into a namespace's mount tree.
+ * - the caller's ref on the new mount is consumed unconditionally.
*/
static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags)
{
@@ -1942,62 +1927,59 @@ static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flag
mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL);
down_write(&namespace_sem);
- /* Something was mounted here while we slept */
+ /* Something may have been mounted here while we slept */
err = follow_down(path, true);
if (err < 0)
- goto unlock;
+ goto error;
err = -EINVAL;
if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
- goto unlock;
+ goto error;
/* Refuse the same filesystem on the same mount point */
err = -EBUSY;
if (path->mnt->mnt_sb == newmnt->mnt_sb &&
path->mnt->mnt_root == path->dentry)
- goto unlock;
+ goto error;
err = -EINVAL;
if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode))
- goto unlock;
+ goto error;
newmnt->mnt_flags = mnt_flags;
err = graft_tree(newmnt, path);
+ if (err < 0)
+ goto error;
-unlock:
+ if (newmnt->mnt_expiry_mark) {
+ newmnt->mnt_expiry_mark = 0;
+ br_write_lock(vfsmount_lock);
+ list_add_tail(&newmnt->mnt_expire, &mnt_expirable_mounts);
+ br_write_unlock(vfsmount_lock);
+ schedule_delayed_work(&periodic_mount_expiry,
+ mnt_expiry_period * HZ);
+ }
up_write(&namespace_sem);
- return err;
-}
-
-/**
- * mnt_set_expiry - Put a mount on an expiration list
- * @mnt: The mount to list.
- * @expiry_list: The list to add the mount to.
- */
-void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list)
-{
- down_write(&namespace_sem);
- br_write_lock(vfsmount_lock);
-
- list_add_tail(&mnt->mnt_expire, expiry_list);
+ return 0;
- br_write_unlock(vfsmount_lock);
+error:
up_write(&namespace_sem);
+ mntput(newmnt);
+ return err;
}
-EXPORT_SYMBOL(mnt_set_expiry);
/*
- * process a list of expirable mountpoints with the intent of discarding any
- * mountpoints that aren't in use and haven't been touched since last we came
- * here
+ * Periodically process the list of expirable mountpoints with the intent of
+ * discarding any mountpoints that aren't in use and haven't been touched since
+ * last we came here.
*/
-void mark_mounts_for_expiry(struct list_head *mounts)
+static void do_periodic_mount_expiry(struct work_struct *work)
{
struct vfsmount *mnt, *next;
LIST_HEAD(graveyard);
LIST_HEAD(umounts);
- if (list_empty(mounts))
+ if (list_empty(&mnt_expirable_mounts))
return;
down_write(&namespace_sem);
@@ -2009,7 +1991,7 @@ void mark_mounts_for_expiry(struct list_head *mounts)
* - still marked for expiry (marked on the last call here; marks are
* cleared by mntput())
*/
- list_for_each_entry_safe(mnt, next, mounts, mnt_expire) {
+ list_for_each_entry_safe(mnt, next, &mnt_expirable_mounts, mnt_expire) {
if (!xchg(&mnt->mnt_expiry_mark, 1) ||
propagate_mount_busy(mnt, 1))
continue;
@@ -2024,9 +2006,11 @@ void mark_mounts_for_expiry(struct list_head *mounts)
up_write(&namespace_sem);
release_mounts(&umounts);
-}
-EXPORT_SYMBOL_GPL(mark_mounts_for_expiry);
+ if (!list_empty(&mnt_expirable_mounts))
+ schedule_delayed_work(&periodic_mount_expiry,
+ mnt_expiry_period * HZ);
+}
/*
* Ripoff of 'select_parent()'
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index bd3ca32..5552ff2 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -1083,7 +1083,6 @@ void nfs_free_server(struct nfs_server *server)
nfs_free_iostats(server->io_stats);
bdi_destroy(&server->backing_dev_info);
kfree(server);
- nfs_release_automount_timer();
dprintk("<-- nfs_free_server()\n");
}
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index f32b860..3a4a2fa 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -19,12 +19,6 @@
#define NFSDBG_FACILITY NFSDBG_VFS
-static void nfs_expire_automounts(struct work_struct *work);
-
-static LIST_HEAD(nfs_automount_list);
-static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts);
-int nfs_mountpoint_expiry_timeout = 500 * HZ;
-
static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
const struct dentry *dentry,
struct nfs_fh *fh,
@@ -149,11 +143,8 @@ struct vfsmount *nfs_d_automount(struct path *path)
if (IS_ERR(mnt))
goto out;
+ mnt->mnt_expiry_mark = 1;
dprintk("%s: done, success\n", __func__);
- mntget(mnt); /* prevent immediate expiration */
- mnt_set_expiry(mnt, &nfs_automount_list);
- schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
-
out:
nfs_free_fattr(fattr);
nfs_free_fhandle(fh);
@@ -169,21 +160,6 @@ const struct inode_operations nfs_mountpoint_inode_operations = {
const struct inode_operations nfs_referral_inode_operations = {
};
-static void nfs_expire_automounts(struct work_struct *work)
-{
- struct list_head *list = &nfs_automount_list;
-
- mark_mounts_for_expiry(list);
- if (!list_empty(list))
- schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
-}
-
-void nfs_release_automount_timer(void)
-{
- if (list_empty(&nfs_automount_list))
- cancel_delayed_work(&nfs_automount_task);
-}
-
/*
* Clone a mountpoint of the appropriate type
*/
diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c
index 978aaeb..aa35724 100644
--- a/fs/nfs/sysctl.c
+++ b/fs/nfs/sysctl.c
@@ -43,13 +43,6 @@ static ctl_table nfs_cb_sysctls[] = {
#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
#endif
{
- .procname = "nfs_mountpoint_timeout",
- .data = &nfs_mountpoint_expiry_timeout,
- .maxlen = sizeof(nfs_mountpoint_expiry_timeout),
- .mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
- },
- {
.procname = "nfs_congestion_kb",
.data = &nfs_congestion_kb,
.maxlen = sizeof(nfs_congestion_kb),
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 604f122..0e46c54 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -108,9 +108,8 @@ extern struct vfsmount *vfs_kern_mount(struct file_system_type *type,
int flags, const char *name,
void *data);
-extern void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list);
-extern void mark_mounts_for_expiry(struct list_head *mounts);
-
extern dev_t name_to_dev_t(char *name);
+extern unsigned long mnt_expiry_period;
+
#endif /* _LINUX_MOUNT_H */
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 0f1bd83..f132dbd 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -56,6 +56,7 @@
#include <linux/kprobes.h>
#include <linux/pipe_fs_i.h>
#include <linux/oom.h>
+#include <linux/mount.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
@@ -122,6 +123,7 @@ static int one_hundred = 100;
#ifdef CONFIG_PRINTK
static int ten_thousand = 10000;
#endif
+static unsigned long max_timeout_ul = ULONG_MAX / HZ;
/* this is needed for the proc_doulongvec_minmax of vm_dirty_bytes */
static unsigned long dirty_bytes_min = 2 * PAGE_SIZE;
@@ -1484,6 +1486,15 @@ static struct ctl_table fs_table[] = {
.proc_handler = &pipe_proc_fn,
.extra1 = &pipe_min_size,
},
+ {
+ .procname = "mount-expiry-period",
+ .data = &mnt_expiry_period,
+ .maxlen = sizeof(mnt_expiry_period),
+ .mode = 0644,
+ .proc_handler = proc_doulongvec_minmax,
+ .extra1 = &one_ul,
+ .extra2 = &max_timeout_ul,
+ },
{ }
};
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 3/3] autofs4: Use no_printk() for no-op DPRINTK() and use __VA_ARGS__ too
2011-03-03 16:57 [PATCH 1/3] Update the automount document to reflect the new VFS automounting hook David Howells
2011-03-03 16:57 ` [PATCH 2/3] Make VFS handle mount autoexpiry David Howells
@ 2011-03-03 16:58 ` David Howells
1 sibling, 0 replies; 3+ messages in thread
From: David Howells @ 2011-03-03 16:58 UTC (permalink / raw)
To: viro, hch, raven; +Cc: linux-devel, autofs, linux-kernel, David Howells
Use no_printk() for autofs's no-op DPRINTK() to prevent unused statements from
becoming accidentally obsolete, and use __VA_ARGS__ too as that's the standard
way.
Signed-off-by: David Howells <dhowells@redhat.com>
---
fs/autofs4/autofs_i.h | 10 +++++++---
fs/autofs4/waitq.c | 3 ++-
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 54f9237..ef89828 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -40,13 +40,17 @@
/* #define DEBUG */
#ifdef DEBUG
-#define DPRINTK(fmt, args...) \
+#define DPRINTK(fmt, ...) \
do { \
printk(KERN_DEBUG "pid %d: %s: " fmt "\n", \
- current->pid, __func__, ##args); \
+ current->pid, __func__, ##__VA_ARGS__); \
} while (0)
#else
-#define DPRINTK(fmt, args...) do {} while (0)
+#define DPRINTK(fmt, ...) \
+do { \
+ no_printk(KERN_DEBUG "pid %d: %s: " fmt "\n", \
+ current->pid, __func__, ##__VA_ARGS__); \
+} while (0)
#endif
#define AUTOFS_WARN(fmt, args...) \
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 5601005..4d169cf 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -104,7 +104,8 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
size_t pktsz;
DPRINTK("wait id = 0x%08lx, name = %.*s, type=%d",
- wq->wait_queue_token, wq->name.len, wq->name.name, type);
+ (unsigned long)wq->wait_queue_token,
+ wq->name.len, wq->name.name, type);
memset(&pkt,0,sizeof pkt); /* For security reasons */
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2011-03-03 16:58 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-03-03 16:57 [PATCH 1/3] Update the automount document to reflect the new VFS automounting hook David Howells
2011-03-03 16:57 ` [PATCH 2/3] Make VFS handle mount autoexpiry David Howells
2011-03-03 16:58 ` [PATCH 3/3] autofs4: Use no_printk() for no-op DPRINTK() and use __VA_ARGS__ too David Howells
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®