Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 231525
b: refs/heads/master
c: ea5b778
h: refs/heads/master
i:
  231523: dafed7a
v: v3
  • Loading branch information
David Howells authored and Al Viro committed Jan 16, 2011
1 parent b303604 commit 2b8bda9
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 90 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ab90911ff90cdab59b31c045c3f0ae480d14f29d
refs/heads/master: ea5b778a8b98c85a87d66bf844904f9c3802b869
23 changes: 14 additions & 9 deletions trunk/Documentation/filesystems/vfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -933,15 +933,20 @@ struct dentry_operations {
dynamic_dname() helper function is provided to take care of this.

d_automount: called when an automount dentry is to be traversed (optional).
This should create a new VFS mount record, mount it on the directory
and return the record to the caller. The caller is supplied with a
path parameter giving the automount directory to describe the automount
target and the parent VFS mount record to provide inheritable mount
parameters. NULL should be returned if someone else managed to make
the automount first. If the automount failed, then an error code
should be returned. If -EISDIR is returned, then the directory will
be treated as an ordinary directory and returned to pathwalk to
continue walking.
This should create a new VFS mount record and return the record to the
caller. The caller is supplied with a path parameter giving the
automount directory to describe the automount target and the parent
VFS mount record to provide inheritable mount parameters. NULL should
be returned if someone else managed to make the automount first. If
the vfsmount creation failed, then an error code should be returned.
If -EISDIR is returned, then the directory will be treated as an
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.

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
Expand Down
25 changes: 6 additions & 19 deletions trunk/fs/afs/mntpt.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,32 +241,19 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
struct vfsmount *afs_d_automount(struct path *path)
{
struct vfsmount *newmnt;
int err;

_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);
err = do_add_mount(newmnt, path, MNT_SHRINKABLE, &afs_vfsmounts);
switch (err) {
case 0:
queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,
afs_mntpt_expiry_timeout * HZ);
_leave(" = %p {%s}", newmnt, newmnt->mnt_devname);
return newmnt;
case -EBUSY:
/* someone else made a mount here whilst we were busy */
mntput(newmnt);
_leave(" = NULL [EBUSY]");
return NULL;
default:
mntput(newmnt);
_leave(" = %d", err);
return ERR_PTR(err);
}
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;
}

/*
Expand Down
26 changes: 6 additions & 20 deletions trunk/fs/cifs/cifs_dfs_ref.c
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,6 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
struct vfsmount *cifs_dfs_d_automount(struct path *path)
{
struct vfsmount *newmnt;
int err;

cFYI(1, "in %s", __func__);

Expand All @@ -361,25 +360,12 @@ struct vfsmount *cifs_dfs_d_automount(struct path *path)
return newmnt;
}

mntget(newmnt);
err = do_add_mount(newmnt, path, path->mnt->mnt_flags | MNT_SHRINKABLE,
&cifs_dfs_automount_list);
switch (err) {
case 0:
schedule_delayed_work(&cifs_dfs_automount_task,
cifs_dfs_mountpoint_expiry_timeout);
cFYI(1, "leaving %s [ok]" , __func__);
return newmnt;
case -EBUSY:
/* someone else made a mount here whilst we were busy */
mntput(newmnt);
cFYI(1, "leaving %s [EBUSY]" , __func__);
return NULL;
default:
mntput(newmnt);
cFYI(1, "leaving %s [error %d]" , __func__, err);
return ERR_PTR(err);
}
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 = {
Expand Down
2 changes: 2 additions & 0 deletions trunk/fs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
extern void release_mounts(struct list_head *);
extern void umount_tree(struct vfsmount *, int, struct list_head *);
extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int);
extern int do_add_mount(struct vfsmount *, struct path *, int);
extern void mnt_clear_expiry(struct vfsmount *);

extern void __init mnt_init(void);

Expand Down
42 changes: 35 additions & 7 deletions trunk/fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,7 @@ static int follow_automount(struct path *path, unsigned flags,
bool *need_mntput)
{
struct vfsmount *mnt;
int err;

if (!path->dentry->d_op || !path->dentry->d_op->d_automount)
return -EREMOTE;
Expand Down Expand Up @@ -942,22 +943,49 @@ static int follow_automount(struct path *path, unsigned flags,
return -EREMOTE;
return PTR_ERR(mnt);
}

if (!mnt) /* mount collision */
return 0;

/* 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(mnt) < 2);

if (mnt->mnt_sb == path->mnt->mnt_sb &&
mnt->mnt_root == path->dentry) {
mnt_clear_expiry(mnt);
mntput(mnt);
mntput(mnt);
return -ELOOP;
}

dput(path->dentry);
if (*need_mntput)
mntput(path->mnt);
path->mnt = mnt;
path->dentry = dget(mnt->mnt_root);
*need_mntput = true;
return 0;
/* We need to add the mountpoint to the parent. The filesystem may
* have placed it on an expiry list, and so we need to make sure it
* won't be expired under us if do_add_mount() fails (do_add_mount()
* will eat a reference unconditionally).
*/
mntget(mnt);
err = do_add_mount(mnt, path, path->mnt->mnt_flags | MNT_SHRINKABLE);
switch (err) {
case -EBUSY:
/* Someone else made a mount here whilst we were busy */
err = 0;
default:
mnt_clear_expiry(mnt);
mntput(mnt);
mntput(mnt);
return err;
case 0:
mntput(mnt);
dput(path->dentry);
if (*need_mntput)
mntput(path->mnt);
path->mnt = mnt;
path->dentry = dget(mnt->mnt_root);
*need_mntput = true;
return 0;
}
}

/*
Expand Down
41 changes: 33 additions & 8 deletions trunk/fs/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -1925,15 +1925,14 @@ static int do_new_mount(struct path *path, char *type, int flags,
if (IS_ERR(mnt))
return PTR_ERR(mnt);

return do_add_mount(mnt, path, mnt_flags, NULL);
return do_add_mount(mnt, path, mnt_flags);
}

/*
* add a mount into a namespace's mount tree
* - provide the option of adding the new mount to an expiration list
* - this unconditionally eats one of the caller's references to newmnt.
*/
int do_add_mount(struct vfsmount *newmnt, struct path *path,
int mnt_flags, struct list_head *fslist)
int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags)
{
int err;

Expand Down Expand Up @@ -1963,9 +1962,6 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path,
if ((err = graft_tree(newmnt, path)))
goto unlock;

if (fslist) /* add to the specified expiration list */
list_add_tail(&newmnt->mnt_expire, fslist);

up_write(&namespace_sem);
return 0;

Expand All @@ -1975,7 +1971,36 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path,
return err;
}

EXPORT_SYMBOL_GPL(do_add_mount);
/**
* 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);

br_write_unlock(vfsmount_lock);
up_write(&namespace_sem);
}
EXPORT_SYMBOL(mnt_set_expiry);

/*
* Remove a vfsmount from any expiration list it may be on
*/
void mnt_clear_expiry(struct vfsmount *mnt)
{
if (!list_empty(&mnt->mnt_expire)) {
down_write(&namespace_sem);
br_write_lock(vfsmount_lock);
list_del_init(&mnt->mnt_expire);
br_write_unlock(vfsmount_lock);
up_write(&namespace_sem);
}
}

/*
* process a list of expirable mountpoints with the intent of discarding any
Expand Down
24 changes: 4 additions & 20 deletions trunk/fs/nfs/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,26 +149,10 @@ struct vfsmount *nfs_d_automount(struct path *path)
if (IS_ERR(mnt))
goto out;

mntget(mnt);
err = do_add_mount(mnt, path, path->mnt->mnt_flags | MNT_SHRINKABLE,
&nfs_automount_list);
switch (err) {
case 0:
dprintk("%s: done, success\n", __func__);
schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
break;
case -EBUSY:
/* someone else made a mount here whilst we were busy */
mntput(mnt);
dprintk("%s: done, collision\n", __func__);
mnt = NULL;
break;
default:
mntput(mnt);
dprintk("%s: done, error %d\n", __func__, err);
mnt = ERR_PTR(err);
break;
}
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);
Expand Down
7 changes: 1 addition & 6 deletions trunk/include/linux/mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,7 @@ extern struct vfsmount *vfs_kern_mount(struct file_system_type *type,
int flags, const char *name,
void *data);

struct nameidata;

struct path;
extern int do_add_mount(struct vfsmount *newmnt, struct path *path,
int mnt_flags, struct list_head *fslist);

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);
Expand Down

0 comments on commit 2b8bda9

Please sign in to comment.