Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/viro/vfs-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (23 commits)
  sanitize vfsmount refcounting changes
  fix old umount_tree() breakage
  autofs4: Merge the remaining dentry ops tables
  Unexport do_add_mount() and add in follow_automount(), not ->d_automount()
  Allow d_manage() to be used in RCU-walk mode
  Remove a further kludge from __do_follow_link()
  autofs4: Bump version
  autofs4: Add v4 pseudo direct mount support
  autofs4: Fix wait validation
  autofs4: Clean up autofs4_free_ino()
  autofs4: Clean up dentry operations
  autofs4: Clean up inode operations
  autofs4: Remove unused code
  autofs4: Add d_manage() dentry operation
  autofs4: Add d_automount() dentry operation
  Remove the automount through follow_link() kludge code from pathwalk
  CIFS: Use d_automount() rather than abusing follow_link()
  NFS: Use d_automount() rather than abusing follow_link()
  AFS: Use d_automount() rather than abusing follow_link()
  Add an AT_NO_AUTOMOUNT flag to suppress terminal automount
  ...
  • Loading branch information
Linus Torvalds committed Jan 16, 2011
2 parents 1b59be2 + f03c659 commit f8206b9
Show file tree
Hide file tree
Showing 40 changed files with 1,009 additions and 854 deletions.
4 changes: 4 additions & 0 deletions Documentation/filesystems/Locking
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ prototypes:
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
struct vfsmount *(*d_automount)(struct path *path);
int (*d_manage)(struct dentry *, bool);

locking rules:
rename_lock ->d_lock may block rcu-walk
Expand All @@ -29,6 +31,8 @@ d_delete: no yes no no
d_release: no no yes no
d_iput: no no yes no
d_dname: no no no no
d_automount: no no yes no
d_manage: no no yes (ref-walk) maybe

--------------------------- inode_operations ---------------------------
prototypes:
Expand Down
43 changes: 43 additions & 0 deletions Documentation/filesystems/vfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,8 @@ struct dentry_operations {
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
int (*d_manage)(struct dentry *, bool, bool);
};

d_revalidate: called when the VFS needs to revalidate a dentry. This
Expand Down Expand Up @@ -930,6 +932,47 @@ struct dentry_operations {
at the end of the buffer, and returns a pointer to the first char.
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 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
inode being added.

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
past and construct the subtree there. 0 should be returned to let the
calling process continue. -EISDIR can be returned to tell pathwalk to
use this directory as an ordinary directory and to ignore anything
mounted on it and not to check the automount flag. Any other error
code will abort pathwalk completely.

If the 'mounting_here' parameter is true, then namespace_sem is being
held by the caller and the function should not initiate any mounts or
unmounts that it will then wait for.

If the 'rcu_walk' parameter is true, then the caller is doing a
pathwalk in RCU-walk mode. Sleeping is not permitted in this mode,
and the caller can be asked to leave it and call again by returing
-ECHILD.

This function is only used if DCACHE_MANAGE_TRANSIT is set on the
dentry being transited from.

Example :

static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen)
Expand Down
2 changes: 1 addition & 1 deletion drivers/mtd/mtdchar.c
Original file line number Diff line number Diff line change
Expand Up @@ -1201,7 +1201,7 @@ static int __init init_mtdchar(void)
static void __exit cleanup_mtdchar(void)
{
unregister_mtd_user(&mtdchar_notifier);
mntput_long(mtd_inode_mnt);
mntput(mtd_inode_mnt);
unregister_filesystem(&mtd_inodefs_type);
__unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd");
}
Expand Down
5 changes: 2 additions & 3 deletions drivers/staging/autofs/dirhash.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,13 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb,
}
path.mnt = mnt;
path_get(&path);
if (!follow_down(&path)) {
if (!follow_down_one(&path)) {
path_put(&path);
DPRINTK(("autofs: not expirable\
(not a mounted directory): %s\n", ent->name));
continue;
}
while (d_mountpoint(path.dentry) && follow_down(&path))
;
follow_down(&path, false); // TODO: need to check error
umount_ok = may_umount(path.mnt);
path_put(&path);

Expand Down
1 change: 1 addition & 0 deletions fs/afs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ const struct dentry_operations afs_fs_dentry_operations = {
.d_revalidate = afs_d_revalidate,
.d_delete = afs_d_delete,
.d_release = afs_d_release,
.d_automount = afs_d_automount,
};

#define AFS_DIR_HASHTBL_SIZE 128
Expand Down
3 changes: 2 additions & 1 deletion fs/afs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
inode->i_generation = 0;

set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags);
inode->i_flags |= S_NOATIME;
set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
inode->i_flags |= S_AUTOMOUNT | S_NOATIME;
unlock_new_inode(inode);
_leave(" = %p", inode);
return inode;
Expand Down
1 change: 1 addition & 0 deletions fs/afs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,7 @@ extern const struct inode_operations afs_mntpt_inode_operations;
extern const struct inode_operations afs_autocell_inode_operations;
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);

Expand Down
56 changes: 13 additions & 43 deletions fs/afs/mntpt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_follow_link(struct dentry *dentry, struct nameidata *nd);
static void afs_mntpt_expiry_timed_out(struct work_struct *work);

const struct file_operations afs_mntpt_file_operations = {
Expand All @@ -34,13 +33,11 @@ const struct file_operations afs_mntpt_file_operations = {

const struct inode_operations afs_mntpt_inode_operations = {
.lookup = afs_mntpt_lookup,
.follow_link = afs_mntpt_follow_link,
.readlink = page_readlink,
.getattr = afs_getattr,
};

const struct inode_operations afs_autocell_inode_operations = {
.follow_link = afs_mntpt_follow_link,
.getattr = afs_getattr,
};

Expand Down Expand Up @@ -88,6 +85,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
_debug("symlink is a mountpoint");
spin_lock(&vnode->lock);
set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
vnode->vfs_inode.i_flags |= S_AUTOMOUNT;
spin_unlock(&vnode->lock);
}

Expand Down Expand Up @@ -238,52 +236,24 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
}

/*
* follow a link from a mountpoint directory, thus causing it to be mounted
* handle an automount point
*/
static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd)
struct vfsmount *afs_d_automount(struct path *path)
{
struct vfsmount *newmnt;
int err;

_enter("%p{%s},{%s:%p{%s},}",
dentry,
dentry->d_name.name,
nd->path.mnt->mnt_devname,
dentry,
nd->path.dentry->d_name.name);

dput(nd->path.dentry);
nd->path.dentry = dget(dentry);

newmnt = afs_mntpt_do_automount(nd->path.dentry);
if (IS_ERR(newmnt)) {
path_put(&nd->path);
return (void *)newmnt;
}
_enter("{%s,%s}", path->mnt->mnt_devname, path->dentry->d_name.name);

mntget(newmnt);
err = do_add_mount(newmnt, &nd->path, MNT_SHRINKABLE, &afs_vfsmounts);
switch (err) {
case 0:
path_put(&nd->path);
nd->path.mnt = newmnt;
nd->path.dentry = dget(newmnt->mnt_root);
queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,
afs_mntpt_expiry_timeout * HZ);
break;
case -EBUSY:
/* someone else made a mount here whilst we were busy */
while (d_mountpoint(nd->path.dentry) &&
follow_down(&nd->path))
;
err = 0;
default:
mntput(newmnt);
break;
}
newmnt = afs_mntpt_do_automount(path->dentry);
if (IS_ERR(newmnt))
return 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
2 changes: 1 addition & 1 deletion fs/anon_inodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ static int __init anon_inode_init(void)
return 0;

err_mntput:
mntput_long(anon_inode_mnt);
mntput(anon_inode_mnt);
err_unregister_filesystem:
unregister_filesystem(&anon_inode_fs_type);
err_exit:
Expand Down
99 changes: 75 additions & 24 deletions fs/autofs4/autofs_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ struct autofs_info {
};

#define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */
#define AUTOFS_INF_MOUNTPOINT (1<<1) /* mountpoint status for direct expire */
#define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */

struct autofs_wait_queue {
Expand Down Expand Up @@ -176,13 +175,6 @@ static inline int autofs4_ispending(struct dentry *dentry)
return 0;
}

static inline void autofs4_copy_atime(struct file *src, struct file *dst)
{
dst->f_path.dentry->d_inode->i_atime =
src->f_path.dentry->d_inode->i_atime;
return;
}

struct inode *autofs4_get_inode(struct super_block *, struct autofs_info *);
void autofs4_free_ino(struct autofs_info *);

Expand Down Expand Up @@ -212,11 +204,83 @@ void autofs_dev_ioctl_exit(void);

extern const struct inode_operations autofs4_symlink_inode_operations;
extern const struct inode_operations autofs4_dir_inode_operations;
extern const struct inode_operations autofs4_root_inode_operations;
extern const struct inode_operations autofs4_indirect_root_inode_operations;
extern const struct inode_operations autofs4_direct_root_inode_operations;
extern const struct file_operations autofs4_dir_operations;
extern const struct file_operations autofs4_root_operations;
extern const struct dentry_operations autofs4_dentry_operations;

/* VFS automount flags management functions */

static inline void __managed_dentry_set_automount(struct dentry *dentry)
{
dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
}

static inline void managed_dentry_set_automount(struct dentry *dentry)
{
spin_lock(&dentry->d_lock);
__managed_dentry_set_automount(dentry);
spin_unlock(&dentry->d_lock);
}

static inline void __managed_dentry_clear_automount(struct dentry *dentry)
{
dentry->d_flags &= ~DCACHE_NEED_AUTOMOUNT;
}

static inline void managed_dentry_clear_automount(struct dentry *dentry)
{
spin_lock(&dentry->d_lock);
__managed_dentry_clear_automount(dentry);
spin_unlock(&dentry->d_lock);
}

static inline void __managed_dentry_set_transit(struct dentry *dentry)
{
dentry->d_flags |= DCACHE_MANAGE_TRANSIT;
}

static inline void managed_dentry_set_transit(struct dentry *dentry)
{
spin_lock(&dentry->d_lock);
__managed_dentry_set_transit(dentry);
spin_unlock(&dentry->d_lock);
}

static inline void __managed_dentry_clear_transit(struct dentry *dentry)
{
dentry->d_flags &= ~DCACHE_MANAGE_TRANSIT;
}

static inline void managed_dentry_clear_transit(struct dentry *dentry)
{
spin_lock(&dentry->d_lock);
__managed_dentry_clear_transit(dentry);
spin_unlock(&dentry->d_lock);
}

static inline void __managed_dentry_set_managed(struct dentry *dentry)
{
dentry->d_flags |= (DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT);
}

static inline void managed_dentry_set_managed(struct dentry *dentry)
{
spin_lock(&dentry->d_lock);
__managed_dentry_set_managed(dentry);
spin_unlock(&dentry->d_lock);
}

static inline void __managed_dentry_clear_managed(struct dentry *dentry)
{
dentry->d_flags &= ~(DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT);
}

static inline void managed_dentry_clear_managed(struct dentry *dentry)
{
spin_lock(&dentry->d_lock);
__managed_dentry_clear_managed(dentry);
spin_unlock(&dentry->d_lock);
}

/* Initializing function */

Expand All @@ -229,19 +293,6 @@ int autofs4_wait(struct autofs_sb_info *,struct dentry *, enum autofs_notify);
int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int);
void autofs4_catatonic_mode(struct autofs_sb_info *);

static inline int autofs4_follow_mount(struct path *path)
{
int res = 0;

while (d_mountpoint(path->dentry)) {
int followed = follow_down(path);
if (!followed)
break;
res = 1;
}
return res;
}

static inline u32 autofs4_get_dev(struct autofs_sb_info *sbi)
{
return new_encode_dev(sbi->sb->s_dev);
Expand Down
2 changes: 1 addition & 1 deletion fs/autofs4/dev-ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,

err = have_submounts(path.dentry);

if (follow_down(&path))
if (follow_down_one(&path))
magic = path.mnt->mnt_sb->s_magic;
}

Expand Down
Loading

0 comments on commit f8206b9

Please sign in to comment.