Merge branch 'mnt_devname' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'mnt_devname' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: vfs: bury ->get_sb() nfs: switch NFS from ->get_sb() to ->mount() nfs: stop mangling ->mnt_devname on NFS vfs: new superblock methods to override /proc/*/mount{s,info} nfs: nfs_do_{ref,sub}mount() superblock argument is redundant nfs: make nfs_path() work without vfsmount nfs: store devname at disconnected NFS roots nfs: propagate devname to nfs{,4}_get_root()
This commit is contained in:
commit
054cfaacf8
13 changed files with 316 additions and 272 deletions
|
@ -166,13 +166,11 @@ prototypes:
|
|||
void (*kill_sb) (struct super_block *);
|
||||
locking rules:
|
||||
may block
|
||||
get_sb yes
|
||||
mount yes
|
||||
kill_sb yes
|
||||
|
||||
->get_sb() returns error or 0 with locked superblock attached to the vfsmount
|
||||
(exclusive on ->s_umount).
|
||||
->mount() returns ERR_PTR or the root dentry.
|
||||
->mount() returns ERR_PTR or the root dentry; its superblock should be locked
|
||||
on return.
|
||||
->kill_sb() takes a write-locked superblock, does all shutdown work on it,
|
||||
unlocks and drops the reference.
|
||||
|
||||
|
|
|
@ -394,3 +394,10 @@ file) you must return -EOPNOTSUPP if FALLOC_FL_PUNCH_HOLE is set in mode.
|
|||
Currently you can only have FALLOC_FL_PUNCH_HOLE with FALLOC_FL_KEEP_SIZE set,
|
||||
so the i_size should not change when hole punching, even when puching the end of
|
||||
a file off.
|
||||
|
||||
--
|
||||
[mandatory]
|
||||
->get_sb() is gone. Switch to use of ->mount(). Typically it's just
|
||||
a matter of switching from calling get_sb_... to mount_... and changing the
|
||||
function type. If you were doing it manually, just switch from setting ->mnt_root
|
||||
to some pointer to returning that pointer. On errors return ERR_PTR(...).
|
||||
|
|
|
@ -95,10 +95,11 @@ functions:
|
|||
extern int unregister_filesystem(struct file_system_type *);
|
||||
|
||||
The passed struct file_system_type describes your filesystem. When a
|
||||
request is made to mount a device onto a directory in your filespace,
|
||||
the VFS will call the appropriate get_sb() method for the specific
|
||||
filesystem. The dentry for the mount point will then be updated to
|
||||
point to the root inode for the new filesystem.
|
||||
request is made to mount a filesystem onto a directory in your namespace,
|
||||
the VFS will call the appropriate mount() method for the specific
|
||||
filesystem. New vfsmount refering to the tree returned by ->mount()
|
||||
will be attached to the mountpoint, so that when pathname resolution
|
||||
reaches the mountpoint it will jump into the root of that vfsmount.
|
||||
|
||||
You can see all filesystems that are registered to the kernel in the
|
||||
file /proc/filesystems.
|
||||
|
@ -107,14 +108,14 @@ file /proc/filesystems.
|
|||
struct file_system_type
|
||||
-----------------------
|
||||
|
||||
This describes the filesystem. As of kernel 2.6.22, the following
|
||||
This describes the filesystem. As of kernel 2.6.39, the following
|
||||
members are defined:
|
||||
|
||||
struct file_system_type {
|
||||
const char *name;
|
||||
int fs_flags;
|
||||
int (*get_sb) (struct file_system_type *, int,
|
||||
const char *, void *, struct vfsmount *);
|
||||
struct dentry (*mount) (struct file_system_type *, int,
|
||||
const char *, void *);
|
||||
void (*kill_sb) (struct super_block *);
|
||||
struct module *owner;
|
||||
struct file_system_type * next;
|
||||
|
@ -128,11 +129,11 @@ struct file_system_type {
|
|||
|
||||
fs_flags: various flags (i.e. FS_REQUIRES_DEV, FS_NO_DCACHE, etc.)
|
||||
|
||||
get_sb: the method to call when a new instance of this
|
||||
mount: the method to call when a new instance of this
|
||||
filesystem should be mounted
|
||||
|
||||
kill_sb: the method to call when an instance of this filesystem
|
||||
should be unmounted
|
||||
should be shut down
|
||||
|
||||
owner: for internal VFS use: you should initialize this to THIS_MODULE in
|
||||
most cases.
|
||||
|
@ -141,7 +142,7 @@ struct file_system_type {
|
|||
|
||||
s_lock_key, s_umount_key: lockdep-specific
|
||||
|
||||
The get_sb() method has the following arguments:
|
||||
The mount() method has the following arguments:
|
||||
|
||||
struct file_system_type *fs_type: describes the filesystem, partly initialized
|
||||
by the specific filesystem code
|
||||
|
@ -153,32 +154,39 @@ The get_sb() method has the following arguments:
|
|||
void *data: arbitrary mount options, usually comes as an ASCII
|
||||
string (see "Mount Options" section)
|
||||
|
||||
struct vfsmount *mnt: a vfs-internal representation of a mount point
|
||||
The mount() method must return the root dentry of the tree requested by
|
||||
caller. An active reference to its superblock must be grabbed and the
|
||||
superblock must be locked. On failure it should return ERR_PTR(error).
|
||||
|
||||
The get_sb() method must determine if the block device specified
|
||||
in the dev_name and fs_type contains a filesystem of the type the method
|
||||
supports. If it succeeds in opening the named block device, it initializes a
|
||||
struct super_block descriptor for the filesystem contained by the block device.
|
||||
On failure it returns an error.
|
||||
The arguments match those of mount(2) and their interpretation
|
||||
depends on filesystem type. E.g. for block filesystems, dev_name is
|
||||
interpreted as block device name, that device is opened and if it
|
||||
contains a suitable filesystem image the method creates and initializes
|
||||
struct super_block accordingly, returning its root dentry to caller.
|
||||
|
||||
->mount() may choose to return a subtree of existing filesystem - it
|
||||
doesn't have to create a new one. The main result from the caller's
|
||||
point of view is a reference to dentry at the root of (sub)tree to
|
||||
be attached; creation of new superblock is a common side effect.
|
||||
|
||||
The most interesting member of the superblock structure that the
|
||||
get_sb() method fills in is the "s_op" field. This is a pointer to
|
||||
mount() method fills in is the "s_op" field. This is a pointer to
|
||||
a "struct super_operations" which describes the next level of the
|
||||
filesystem implementation.
|
||||
|
||||
Usually, a filesystem uses one of the generic get_sb() implementations
|
||||
and provides a fill_super() method instead. The generic methods are:
|
||||
Usually, a filesystem uses one of the generic mount() implementations
|
||||
and provides a fill_super() callback instead. The generic variants are:
|
||||
|
||||
get_sb_bdev: mount a filesystem residing on a block device
|
||||
mount_bdev: mount a filesystem residing on a block device
|
||||
|
||||
get_sb_nodev: mount a filesystem that is not backed by a device
|
||||
mount_nodev: mount a filesystem that is not backed by a device
|
||||
|
||||
get_sb_single: mount a filesystem which shares the instance between
|
||||
mount_single: mount a filesystem which shares the instance between
|
||||
all mounts
|
||||
|
||||
A fill_super() method implementation has the following arguments:
|
||||
A fill_super() callback implementation has the following arguments:
|
||||
|
||||
struct super_block *sb: the superblock structure. The method fill_super()
|
||||
struct super_block *sb: the superblock structure. The callback
|
||||
must initialize this properly.
|
||||
|
||||
void *data: arbitrary mount options, usually comes as an ASCII
|
||||
|
|
|
@ -978,7 +978,13 @@ static int show_vfsmnt(struct seq_file *m, void *v)
|
|||
int err = 0;
|
||||
struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
|
||||
|
||||
mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
|
||||
if (mnt->mnt_sb->s_op->show_devname) {
|
||||
err = mnt->mnt_sb->s_op->show_devname(m, mnt);
|
||||
if (err)
|
||||
goto out;
|
||||
} else {
|
||||
mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
|
||||
}
|
||||
seq_putc(m, ' ');
|
||||
seq_path(m, &mnt_path, " \t\n\\");
|
||||
seq_putc(m, ' ');
|
||||
|
@ -1025,7 +1031,12 @@ static int show_mountinfo(struct seq_file *m, void *v)
|
|||
|
||||
seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id,
|
||||
MAJOR(sb->s_dev), MINOR(sb->s_dev));
|
||||
seq_dentry(m, mnt->mnt_root, " \t\n\\");
|
||||
if (sb->s_op->show_path)
|
||||
err = sb->s_op->show_path(m, mnt);
|
||||
else
|
||||
seq_dentry(m, mnt->mnt_root, " \t\n\\");
|
||||
if (err)
|
||||
goto out;
|
||||
seq_putc(m, ' ');
|
||||
seq_path_root(m, &mnt_path, &root, " \t\n\\");
|
||||
if (root.mnt != p->root.mnt || root.dentry != p->root.dentry) {
|
||||
|
@ -1060,7 +1071,12 @@ static int show_mountinfo(struct seq_file *m, void *v)
|
|||
seq_puts(m, " - ");
|
||||
show_type(m, sb);
|
||||
seq_putc(m, ' ');
|
||||
mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
|
||||
if (sb->s_op->show_devname)
|
||||
err = sb->s_op->show_devname(m, mnt);
|
||||
else
|
||||
mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
|
||||
if (err)
|
||||
goto out;
|
||||
seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw");
|
||||
err = show_sb_opts(m, sb);
|
||||
if (err)
|
||||
|
@ -1086,11 +1102,15 @@ static int show_vfsstat(struct seq_file *m, void *v)
|
|||
int err = 0;
|
||||
|
||||
/* device */
|
||||
if (mnt->mnt_devname) {
|
||||
seq_puts(m, "device ");
|
||||
mangle(m, mnt->mnt_devname);
|
||||
} else
|
||||
seq_puts(m, "no device");
|
||||
if (mnt->mnt_sb->s_op->show_devname) {
|
||||
err = mnt->mnt_sb->s_op->show_devname(m, mnt);
|
||||
} else {
|
||||
if (mnt->mnt_devname) {
|
||||
seq_puts(m, "device ");
|
||||
mangle(m, mnt->mnt_devname);
|
||||
} else
|
||||
seq_puts(m, "no device");
|
||||
}
|
||||
|
||||
/* mount point */
|
||||
seq_puts(m, " mounted on ");
|
||||
|
@ -1104,7 +1124,8 @@ static int show_vfsstat(struct seq_file *m, void *v)
|
|||
/* optional statistics */
|
||||
if (mnt->mnt_sb->s_op->show_stats) {
|
||||
seq_putc(m, ' ');
|
||||
err = mnt->mnt_sb->s_op->show_stats(m, mnt);
|
||||
if (!err)
|
||||
err = mnt->mnt_sb->s_op->show_stats(m, mnt);
|
||||
}
|
||||
|
||||
seq_putc(m, '\n');
|
||||
|
|
13
fs/nfs/dir.c
13
fs/nfs/dir.c
|
@ -1169,11 +1169,23 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
|
|||
iput(inode);
|
||||
}
|
||||
|
||||
static void nfs_d_release(struct dentry *dentry)
|
||||
{
|
||||
/* free cached devname value, if it survived that far */
|
||||
if (unlikely(dentry->d_fsdata)) {
|
||||
if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
|
||||
WARN_ON(1);
|
||||
else
|
||||
kfree(dentry->d_fsdata);
|
||||
}
|
||||
}
|
||||
|
||||
const struct dentry_operations nfs_dentry_operations = {
|
||||
.d_revalidate = nfs_lookup_revalidate,
|
||||
.d_delete = nfs_dentry_delete,
|
||||
.d_iput = nfs_dentry_iput,
|
||||
.d_automount = nfs_d_automount,
|
||||
.d_release = nfs_d_release,
|
||||
};
|
||||
|
||||
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
|
||||
|
@ -1248,6 +1260,7 @@ const struct dentry_operations nfs4_dentry_operations = {
|
|||
.d_delete = nfs_dentry_delete,
|
||||
.d_iput = nfs_dentry_iput,
|
||||
.d_automount = nfs_d_automount,
|
||||
.d_release = nfs_d_release,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -75,18 +75,25 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
|
|||
/*
|
||||
* get an NFS2/NFS3 root dentry from the root filehandle
|
||||
*/
|
||||
struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
|
||||
struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
|
||||
const char *devname)
|
||||
{
|
||||
struct nfs_server *server = NFS_SB(sb);
|
||||
struct nfs_fsinfo fsinfo;
|
||||
struct dentry *ret;
|
||||
struct inode *inode;
|
||||
void *name = kstrdup(devname, GFP_KERNEL);
|
||||
int error;
|
||||
|
||||
if (!name)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* get the actual root for this mount */
|
||||
fsinfo.fattr = nfs_alloc_fattr();
|
||||
if (fsinfo.fattr == NULL)
|
||||
if (fsinfo.fattr == NULL) {
|
||||
kfree(name);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
|
||||
if (error < 0) {
|
||||
|
@ -119,7 +126,15 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
|
|||
}
|
||||
|
||||
security_d_instantiate(ret, inode);
|
||||
spin_lock(&ret->d_lock);
|
||||
if (IS_ROOT(ret) && !(ret->d_flags & DCACHE_NFSFS_RENAMED)) {
|
||||
ret->d_fsdata = name;
|
||||
name = NULL;
|
||||
}
|
||||
spin_unlock(&ret->d_lock);
|
||||
out:
|
||||
if (name)
|
||||
kfree(name);
|
||||
nfs_free_fattr(fsinfo.fattr);
|
||||
return ret;
|
||||
}
|
||||
|
@ -169,27 +184,35 @@ out:
|
|||
/*
|
||||
* get an NFS4 root dentry from the root filehandle
|
||||
*/
|
||||
struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
|
||||
struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh,
|
||||
const char *devname)
|
||||
{
|
||||
struct nfs_server *server = NFS_SB(sb);
|
||||
struct nfs_fattr *fattr = NULL;
|
||||
struct dentry *ret;
|
||||
struct inode *inode;
|
||||
void *name = kstrdup(devname, GFP_KERNEL);
|
||||
int error;
|
||||
|
||||
dprintk("--> nfs4_get_root()\n");
|
||||
|
||||
if (!name)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* get the info about the server and filesystem */
|
||||
error = nfs4_server_capabilities(server, mntfh);
|
||||
if (error < 0) {
|
||||
dprintk("nfs_get_root: getcaps error = %d\n",
|
||||
-error);
|
||||
kfree(name);
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
fattr = nfs_alloc_fattr();
|
||||
if (fattr == NULL)
|
||||
return ERR_PTR(-ENOMEM);;
|
||||
if (fattr == NULL) {
|
||||
kfree(name);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/* get the actual root for this mount */
|
||||
error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr);
|
||||
|
@ -223,8 +246,15 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
|
|||
}
|
||||
|
||||
security_d_instantiate(ret, inode);
|
||||
|
||||
spin_lock(&ret->d_lock);
|
||||
if (IS_ROOT(ret) && !(ret->d_flags & DCACHE_NFSFS_RENAMED)) {
|
||||
ret->d_fsdata = name;
|
||||
name = NULL;
|
||||
}
|
||||
spin_unlock(&ret->d_lock);
|
||||
out:
|
||||
if (name)
|
||||
kfree(name);
|
||||
nfs_free_fattr(fattr);
|
||||
dprintk("<-- nfs4_get_root()\n");
|
||||
return ret;
|
||||
|
|
|
@ -163,10 +163,10 @@ static inline void nfs_fs_proc_exit(void)
|
|||
|
||||
/* nfs4namespace.c */
|
||||
#ifdef CONFIG_NFS_V4
|
||||
extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry);
|
||||
extern struct vfsmount *nfs_do_refmount(struct dentry *dentry);
|
||||
#else
|
||||
static inline
|
||||
struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry)
|
||||
struct vfsmount *nfs_do_refmount(struct dentry *dentry)
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
@ -247,16 +247,16 @@ extern void nfs_sb_active(struct super_block *sb);
|
|||
extern void nfs_sb_deactive(struct super_block *sb);
|
||||
|
||||
/* namespace.c */
|
||||
extern char *nfs_path(const char *base,
|
||||
const struct dentry *droot,
|
||||
const struct dentry *dentry,
|
||||
extern char *nfs_path(char **p, struct dentry *dentry,
|
||||
char *buffer, ssize_t buflen);
|
||||
extern struct vfsmount *nfs_d_automount(struct path *path);
|
||||
|
||||
/* getroot.c */
|
||||
extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *);
|
||||
extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *,
|
||||
const char *);
|
||||
#ifdef CONFIG_NFS_V4
|
||||
extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *);
|
||||
extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *,
|
||||
const char *);
|
||||
|
||||
extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh);
|
||||
#endif
|
||||
|
@ -288,12 +288,11 @@ extern int _nfs4_call_sync_session(struct nfs_server *server,
|
|||
/*
|
||||
* Determine the device name as a string
|
||||
*/
|
||||
static inline char *nfs_devname(const struct vfsmount *mnt_parent,
|
||||
const struct dentry *dentry,
|
||||
static inline char *nfs_devname(struct dentry *dentry,
|
||||
char *buffer, ssize_t buflen)
|
||||
{
|
||||
return nfs_path(mnt_parent->mnt_devname, mnt_parent->mnt_root,
|
||||
dentry, buffer, buflen);
|
||||
char *dummy;
|
||||
return nfs_path(&dummy, dentry, buffer, buflen);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -25,33 +25,30 @@ 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,
|
||||
static struct vfsmount *nfs_do_submount(struct dentry *dentry,
|
||||
struct nfs_fh *fh,
|
||||
struct nfs_fattr *fattr);
|
||||
|
||||
/*
|
||||
* nfs_path - reconstruct the path given an arbitrary dentry
|
||||
* @base - arbitrary string to prepend to the path
|
||||
* @droot - pointer to root dentry for mountpoint
|
||||
* @base - used to return pointer to the end of devname part of path
|
||||
* @dentry - pointer to dentry
|
||||
* @buffer - result buffer
|
||||
* @buflen - length of buffer
|
||||
*
|
||||
* Helper function for constructing the path from the
|
||||
* root dentry to an arbitrary hashed dentry.
|
||||
* Helper function for constructing the server pathname
|
||||
* by arbitrary hashed dentry.
|
||||
*
|
||||
* This is mainly for use in figuring out the path on the
|
||||
* server side when automounting on top of an existing partition.
|
||||
* server side when automounting on top of an existing partition
|
||||
* and in generating /proc/mounts and friends.
|
||||
*/
|
||||
char *nfs_path(const char *base,
|
||||
const struct dentry *droot,
|
||||
const struct dentry *dentry,
|
||||
char *buffer, ssize_t buflen)
|
||||
char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen)
|
||||
{
|
||||
char *end;
|
||||
int namelen;
|
||||
unsigned seq;
|
||||
const char *base;
|
||||
|
||||
rename_retry:
|
||||
end = buffer+buflen;
|
||||
|
@ -60,7 +57,10 @@ rename_retry:
|
|||
|
||||
seq = read_seqbegin(&rename_lock);
|
||||
rcu_read_lock();
|
||||
while (!IS_ROOT(dentry) && dentry != droot) {
|
||||
while (1) {
|
||||
spin_lock(&dentry->d_lock);
|
||||
if (IS_ROOT(dentry))
|
||||
break;
|
||||
namelen = dentry->d_name.len;
|
||||
buflen -= namelen + 1;
|
||||
if (buflen < 0)
|
||||
|
@ -68,27 +68,47 @@ rename_retry:
|
|||
end -= namelen;
|
||||
memcpy(end, dentry->d_name.name, namelen);
|
||||
*--end = '/';
|
||||
spin_unlock(&dentry->d_lock);
|
||||
dentry = dentry->d_parent;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
if (read_seqretry(&rename_lock, seq))
|
||||
if (read_seqretry(&rename_lock, seq)) {
|
||||
spin_unlock(&dentry->d_lock);
|
||||
rcu_read_unlock();
|
||||
goto rename_retry;
|
||||
}
|
||||
if (*end != '/') {
|
||||
if (--buflen < 0)
|
||||
if (--buflen < 0) {
|
||||
spin_unlock(&dentry->d_lock);
|
||||
rcu_read_unlock();
|
||||
goto Elong;
|
||||
}
|
||||
*--end = '/';
|
||||
}
|
||||
*p = end;
|
||||
base = dentry->d_fsdata;
|
||||
if (!base) {
|
||||
spin_unlock(&dentry->d_lock);
|
||||
rcu_read_unlock();
|
||||
WARN_ON(1);
|
||||
return end;
|
||||
}
|
||||
namelen = strlen(base);
|
||||
/* Strip off excess slashes in base string */
|
||||
while (namelen > 0 && base[namelen - 1] == '/')
|
||||
namelen--;
|
||||
buflen -= namelen;
|
||||
if (buflen < 0)
|
||||
if (buflen < 0) {
|
||||
spin_lock(&dentry->d_lock);
|
||||
rcu_read_unlock();
|
||||
goto Elong;
|
||||
}
|
||||
end -= namelen;
|
||||
memcpy(end, base, namelen);
|
||||
spin_unlock(&dentry->d_lock);
|
||||
rcu_read_unlock();
|
||||
return end;
|
||||
Elong_unlock:
|
||||
spin_lock(&dentry->d_lock);
|
||||
rcu_read_unlock();
|
||||
if (read_seqretry(&rename_lock, seq))
|
||||
goto rename_retry;
|
||||
|
@ -143,9 +163,9 @@ struct vfsmount *nfs_d_automount(struct path *path)
|
|||
}
|
||||
|
||||
if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
|
||||
mnt = nfs_do_refmount(path->mnt, path->dentry);
|
||||
mnt = nfs_do_refmount(path->dentry);
|
||||
else
|
||||
mnt = nfs_do_submount(path->mnt, path->dentry, fh, fattr);
|
||||
mnt = nfs_do_submount(path->dentry, fh, fattr);
|
||||
if (IS_ERR(mnt))
|
||||
goto out;
|
||||
|
||||
|
@ -209,19 +229,17 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
|
|||
|
||||
/**
|
||||
* nfs_do_submount - set up mountpoint when crossing a filesystem boundary
|
||||
* @mnt_parent - mountpoint of parent directory
|
||||
* @dentry - parent directory
|
||||
* @fh - filehandle for new root dentry
|
||||
* @fattr - attributes for new root inode
|
||||
*
|
||||
*/
|
||||
static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
|
||||
const struct dentry *dentry,
|
||||
static struct vfsmount *nfs_do_submount(struct dentry *dentry,
|
||||
struct nfs_fh *fh,
|
||||
struct nfs_fattr *fattr)
|
||||
{
|
||||
struct nfs_clone_mount mountdata = {
|
||||
.sb = mnt_parent->mnt_sb,
|
||||
.sb = dentry->d_sb,
|
||||
.dentry = dentry,
|
||||
.fh = fh,
|
||||
.fattr = fattr,
|
||||
|
@ -237,11 +255,11 @@ static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
|
|||
dentry->d_name.name);
|
||||
if (page == NULL)
|
||||
goto out;
|
||||
devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE);
|
||||
devname = nfs_devname(dentry, page, PAGE_SIZE);
|
||||
mnt = (struct vfsmount *)devname;
|
||||
if (IS_ERR(devname))
|
||||
goto free_page;
|
||||
mnt = nfs_do_clone_mount(NFS_SB(mnt_parent->mnt_sb), devname, &mountdata);
|
||||
mnt = nfs_do_clone_mount(NFS_SB(dentry->d_sb), devname, &mountdata);
|
||||
free_page:
|
||||
free_page((unsigned long)page);
|
||||
out:
|
||||
|
|
|
@ -54,33 +54,29 @@ Elong:
|
|||
/*
|
||||
* Determine the mount path as a string
|
||||
*/
|
||||
static char *nfs4_path(const struct vfsmount *mnt_parent,
|
||||
const struct dentry *dentry,
|
||||
char *buffer, ssize_t buflen)
|
||||
static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen)
|
||||
{
|
||||
const char *srvpath;
|
||||
|
||||
srvpath = strchr(mnt_parent->mnt_devname, ':');
|
||||
if (srvpath)
|
||||
srvpath++;
|
||||
else
|
||||
srvpath = mnt_parent->mnt_devname;
|
||||
|
||||
return nfs_path(srvpath, mnt_parent->mnt_root, dentry, buffer, buflen);
|
||||
char *limit;
|
||||
char *path = nfs_path(&limit, dentry, buffer, buflen);
|
||||
if (!IS_ERR(path)) {
|
||||
char *colon = strchr(path, ':');
|
||||
if (colon && colon < limit)
|
||||
path = colon + 1;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we
|
||||
* believe to be the server path to this dentry
|
||||
*/
|
||||
static int nfs4_validate_fspath(const struct vfsmount *mnt_parent,
|
||||
const struct dentry *dentry,
|
||||
static int nfs4_validate_fspath(struct dentry *dentry,
|
||||
const struct nfs4_fs_locations *locations,
|
||||
char *page, char *page2)
|
||||
{
|
||||
const char *path, *fs_path;
|
||||
|
||||
path = nfs4_path(mnt_parent, dentry, page, PAGE_SIZE);
|
||||
path = nfs4_path(dentry, page, PAGE_SIZE);
|
||||
if (IS_ERR(path))
|
||||
return PTR_ERR(path);
|
||||
|
||||
|
@ -165,20 +161,18 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
|
|||
|
||||
/**
|
||||
* nfs_follow_referral - set up mountpoint when hitting a referral on moved error
|
||||
* @mnt_parent - mountpoint of parent directory
|
||||
* @dentry - parent directory
|
||||
* @locations - array of NFSv4 server location information
|
||||
*
|
||||
*/
|
||||
static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
|
||||
const struct dentry *dentry,
|
||||
static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
|
||||
const struct nfs4_fs_locations *locations)
|
||||
{
|
||||
struct vfsmount *mnt = ERR_PTR(-ENOENT);
|
||||
struct nfs_clone_mount mountdata = {
|
||||
.sb = mnt_parent->mnt_sb,
|
||||
.sb = dentry->d_sb,
|
||||
.dentry = dentry,
|
||||
.authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor,
|
||||
.authflavor = NFS_SB(dentry->d_sb)->client->cl_auth->au_flavor,
|
||||
};
|
||||
char *page = NULL, *page2 = NULL;
|
||||
int loc, error;
|
||||
|
@ -198,7 +192,7 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
|
|||
goto out;
|
||||
|
||||
/* Ensure fs path is a prefix of current dentry path */
|
||||
error = nfs4_validate_fspath(mnt_parent, dentry, locations, page, page2);
|
||||
error = nfs4_validate_fspath(dentry, locations, page, page2);
|
||||
if (error < 0) {
|
||||
mnt = ERR_PTR(error);
|
||||
goto out;
|
||||
|
@ -225,11 +219,10 @@ out:
|
|||
|
||||
/*
|
||||
* nfs_do_refmount - handle crossing a referral on server
|
||||
* @mnt_parent - mountpoint of referral
|
||||
* @dentry - dentry of referral
|
||||
*
|
||||
*/
|
||||
struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry)
|
||||
struct vfsmount *nfs_do_refmount(struct dentry *dentry)
|
||||
{
|
||||
struct vfsmount *mnt = ERR_PTR(-ENOMEM);
|
||||
struct dentry *parent;
|
||||
|
@ -262,7 +255,7 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr
|
|||
fs_locations->fs_path.ncomponents <= 0)
|
||||
goto out_free;
|
||||
|
||||
mnt = nfs_follow_referral(mnt_parent, dentry, fs_locations);
|
||||
mnt = nfs_follow_referral(dentry, fs_locations);
|
||||
out_free:
|
||||
__free_page(page);
|
||||
kfree(fs_locations);
|
||||
|
|
194
fs/nfs/super.c
194
fs/nfs/super.c
|
@ -263,8 +263,11 @@ static match_table_t nfs_local_lock_tokens = {
|
|||
static void nfs_umount_begin(struct super_block *);
|
||||
static int nfs_statfs(struct dentry *, struct kstatfs *);
|
||||
static int nfs_show_options(struct seq_file *, struct vfsmount *);
|
||||
static int nfs_show_devname(struct seq_file *, struct vfsmount *);
|
||||
static int nfs_show_path(struct seq_file *, struct vfsmount *);
|
||||
static int nfs_show_stats(struct seq_file *, struct vfsmount *);
|
||||
static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *);
|
||||
static struct dentry *nfs_fs_mount(struct file_system_type *,
|
||||
int, const char *, void *);
|
||||
static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data);
|
||||
static void nfs_put_super(struct super_block *);
|
||||
|
@ -274,7 +277,7 @@ static int nfs_remount(struct super_block *sb, int *flags, char *raw_data);
|
|||
static struct file_system_type nfs_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "nfs",
|
||||
.get_sb = nfs_get_sb,
|
||||
.mount = nfs_fs_mount,
|
||||
.kill_sb = nfs_kill_super,
|
||||
.fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
|
||||
};
|
||||
|
@ -296,6 +299,8 @@ static const struct super_operations nfs_sops = {
|
|||
.evict_inode = nfs_evict_inode,
|
||||
.umount_begin = nfs_umount_begin,
|
||||
.show_options = nfs_show_options,
|
||||
.show_devname = nfs_show_devname,
|
||||
.show_path = nfs_show_path,
|
||||
.show_stats = nfs_show_stats,
|
||||
.remount_fs = nfs_remount,
|
||||
};
|
||||
|
@ -303,16 +308,16 @@ static const struct super_operations nfs_sops = {
|
|||
#ifdef CONFIG_NFS_V4
|
||||
static int nfs4_validate_text_mount_data(void *options,
|
||||
struct nfs_parsed_mount_data *args, const char *dev_name);
|
||||
static int nfs4_try_mount(int flags, const char *dev_name,
|
||||
struct nfs_parsed_mount_data *data, struct vfsmount *mnt);
|
||||
static int nfs4_get_sb(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
|
||||
static struct dentry *nfs4_try_mount(int flags, const char *dev_name,
|
||||
struct nfs_parsed_mount_data *data);
|
||||
static struct dentry *nfs4_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data);
|
||||
static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data);
|
||||
static struct dentry *nfs4_xdev_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data);
|
||||
static int nfs4_referral_get_sb(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
|
||||
static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data);
|
||||
static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data);
|
||||
static void nfs4_kill_super(struct super_block *sb);
|
||||
|
@ -320,7 +325,7 @@ static void nfs4_kill_super(struct super_block *sb);
|
|||
static struct file_system_type nfs4_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "nfs4",
|
||||
.get_sb = nfs4_get_sb,
|
||||
.mount = nfs4_mount,
|
||||
.kill_sb = nfs4_kill_super,
|
||||
.fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
|
||||
};
|
||||
|
@ -352,7 +357,7 @@ static struct file_system_type nfs4_remote_referral_fs_type = {
|
|||
struct file_system_type nfs4_referral_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "nfs4",
|
||||
.get_sb = nfs4_referral_get_sb,
|
||||
.mount = nfs4_referral_mount,
|
||||
.kill_sb = nfs4_kill_super,
|
||||
.fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
|
||||
};
|
||||
|
@ -366,6 +371,8 @@ static const struct super_operations nfs4_sops = {
|
|||
.evict_inode = nfs4_evict_inode,
|
||||
.umount_begin = nfs_umount_begin,
|
||||
.show_options = nfs_show_options,
|
||||
.show_devname = nfs_show_devname,
|
||||
.show_path = nfs_show_path,
|
||||
.show_stats = nfs_show_stats,
|
||||
.remount_fs = nfs_remount,
|
||||
};
|
||||
|
@ -726,6 +733,28 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int nfs_show_devname(struct seq_file *m, struct vfsmount *mnt)
|
||||
{
|
||||
char *page = (char *) __get_free_page(GFP_KERNEL);
|
||||
char *devname, *dummy;
|
||||
int err = 0;
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
devname = nfs_path(&dummy, mnt->mnt_root, page, PAGE_SIZE);
|
||||
if (IS_ERR(devname))
|
||||
err = PTR_ERR(devname);
|
||||
else
|
||||
seq_escape(m, devname, " \t\n\\");
|
||||
free_page((unsigned long)page);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nfs_show_path(struct seq_file *m, struct vfsmount *mnt)
|
||||
{
|
||||
seq_puts(m, "/");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Present statistical information for this VFS mountpoint
|
||||
*/
|
||||
|
@ -2267,19 +2296,19 @@ static int nfs_bdi_register(struct nfs_server *server)
|
|||
return bdi_register_dev(&server->backing_dev_info, server->s_dev);
|
||||
}
|
||||
|
||||
static int nfs_get_sb(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
|
||||
static struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data)
|
||||
{
|
||||
struct nfs_server *server = NULL;
|
||||
struct super_block *s;
|
||||
struct nfs_parsed_mount_data *data;
|
||||
struct nfs_fh *mntfh;
|
||||
struct dentry *mntroot;
|
||||
struct dentry *mntroot = ERR_PTR(-ENOMEM);
|
||||
int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
|
||||
struct nfs_sb_mountdata sb_mntdata = {
|
||||
.mntflags = flags,
|
||||
};
|
||||
int error = -ENOMEM;
|
||||
int error;
|
||||
|
||||
data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION);
|
||||
mntfh = nfs_alloc_fhandle();
|
||||
|
@ -2290,12 +2319,14 @@ static int nfs_get_sb(struct file_system_type *fs_type,
|
|||
|
||||
/* Validate the mount data */
|
||||
error = nfs_validate_mount_data(raw_data, data, mntfh, dev_name);
|
||||
if (error < 0)
|
||||
if (error < 0) {
|
||||
mntroot = ERR_PTR(error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFS_V4
|
||||
if (data->version == 4) {
|
||||
error = nfs4_try_mount(flags, dev_name, data, mnt);
|
||||
mntroot = nfs4_try_mount(flags, dev_name, data);
|
||||
kfree(data->client_address);
|
||||
kfree(data->nfs_server.export_path);
|
||||
goto out;
|
||||
|
@ -2305,7 +2336,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
|
|||
/* Get a volume representation */
|
||||
server = nfs_create_server(data, mntfh);
|
||||
if (IS_ERR(server)) {
|
||||
error = PTR_ERR(server);
|
||||
mntroot = ERR_CAST(server);
|
||||
goto out;
|
||||
}
|
||||
sb_mntdata.server = server;
|
||||
|
@ -2316,7 +2347,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
|
|||
/* Get a superblock - note that we may end up sharing one that already exists */
|
||||
s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata);
|
||||
if (IS_ERR(s)) {
|
||||
error = PTR_ERR(s);
|
||||
mntroot = ERR_CAST(s);
|
||||
goto out_err_nosb;
|
||||
}
|
||||
|
||||
|
@ -2325,8 +2356,10 @@ static int nfs_get_sb(struct file_system_type *fs_type,
|
|||
server = NULL;
|
||||
} else {
|
||||
error = nfs_bdi_register(server);
|
||||
if (error)
|
||||
if (error) {
|
||||
mntroot = ERR_PTR(error);
|
||||
goto error_splat_bdi;
|
||||
}
|
||||
}
|
||||
|
||||
if (!s->s_root) {
|
||||
|
@ -2336,20 +2369,15 @@ static int nfs_get_sb(struct file_system_type *fs_type,
|
|||
s, data ? data->fscache_uniq : NULL, NULL);
|
||||
}
|
||||
|
||||
mntroot = nfs_get_root(s, mntfh);
|
||||
if (IS_ERR(mntroot)) {
|
||||
error = PTR_ERR(mntroot);
|
||||
mntroot = nfs_get_root(s, mntfh, dev_name);
|
||||
if (IS_ERR(mntroot))
|
||||
goto error_splat_super;
|
||||
}
|
||||
|
||||
error = security_sb_set_mnt_opts(s, &data->lsm_opts);
|
||||
if (error)
|
||||
goto error_splat_root;
|
||||
|
||||
s->s_flags |= MS_ACTIVE;
|
||||
mnt->mnt_sb = s;
|
||||
mnt->mnt_root = mntroot;
|
||||
error = 0;
|
||||
|
||||
out:
|
||||
kfree(data->nfs_server.hostname);
|
||||
|
@ -2359,7 +2387,7 @@ out:
|
|||
out_free_fh:
|
||||
nfs_free_fhandle(mntfh);
|
||||
kfree(data);
|
||||
return error;
|
||||
return mntroot;
|
||||
|
||||
out_err_nosb:
|
||||
nfs_free_server(server);
|
||||
|
@ -2367,6 +2395,7 @@ out_err_nosb:
|
|||
|
||||
error_splat_root:
|
||||
dput(mntroot);
|
||||
mntroot = ERR_PTR(error);
|
||||
error_splat_super:
|
||||
if (server && !s->s_root)
|
||||
bdi_unregister(&server->backing_dev_info);
|
||||
|
@ -2450,7 +2479,7 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags,
|
|||
nfs_fscache_get_super_cookie(s, NULL, data);
|
||||
}
|
||||
|
||||
mntroot = nfs_get_root(s, data->fh);
|
||||
mntroot = nfs_get_root(s, data->fh, dev_name);
|
||||
if (IS_ERR(mntroot)) {
|
||||
error = PTR_ERR(mntroot);
|
||||
goto error_splat_super;
|
||||
|
@ -2718,7 +2747,7 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags,
|
|||
s, data ? data->fscache_uniq : NULL, NULL);
|
||||
}
|
||||
|
||||
mntroot = nfs4_get_root(s, mntfh);
|
||||
mntroot = nfs4_get_root(s, mntfh, dev_name);
|
||||
if (IS_ERR(mntroot)) {
|
||||
error = PTR_ERR(mntroot);
|
||||
goto error_splat_super;
|
||||
|
@ -2771,27 +2800,6 @@ static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
|
|||
return root_mnt;
|
||||
}
|
||||
|
||||
static void nfs_fix_devname(const struct path *path, struct vfsmount *mnt)
|
||||
{
|
||||
char *page = (char *) __get_free_page(GFP_KERNEL);
|
||||
char *devname, *tmp;
|
||||
|
||||
if (page == NULL)
|
||||
return;
|
||||
devname = nfs_path(path->mnt->mnt_devname,
|
||||
path->mnt->mnt_root, path->dentry,
|
||||
page, PAGE_SIZE);
|
||||
if (IS_ERR(devname))
|
||||
goto out_freepage;
|
||||
tmp = kstrdup(devname, GFP_KERNEL);
|
||||
if (tmp == NULL)
|
||||
goto out_freepage;
|
||||
kfree(mnt->mnt_devname);
|
||||
mnt->mnt_devname = tmp;
|
||||
out_freepage:
|
||||
free_page((unsigned long)page);
|
||||
}
|
||||
|
||||
struct nfs_referral_count {
|
||||
struct list_head list;
|
||||
const struct task_struct *task;
|
||||
|
@ -2858,17 +2866,18 @@ static void nfs_referral_loop_unprotect(void)
|
|||
kfree(p);
|
||||
}
|
||||
|
||||
static int nfs_follow_remote_path(struct vfsmount *root_mnt,
|
||||
const char *export_path, struct vfsmount *mnt_target)
|
||||
static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt,
|
||||
const char *export_path)
|
||||
{
|
||||
struct nameidata *nd = NULL;
|
||||
struct mnt_namespace *ns_private;
|
||||
struct super_block *s;
|
||||
struct dentry *dentry;
|
||||
int ret;
|
||||
|
||||
nd = kmalloc(sizeof(*nd), GFP_KERNEL);
|
||||
if (nd == NULL)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ns_private = create_mnt_ns(root_mnt);
|
||||
ret = PTR_ERR(ns_private);
|
||||
|
@ -2890,32 +2899,27 @@ static int nfs_follow_remote_path(struct vfsmount *root_mnt,
|
|||
|
||||
s = nd->path.mnt->mnt_sb;
|
||||
atomic_inc(&s->s_active);
|
||||
mnt_target->mnt_sb = s;
|
||||
mnt_target->mnt_root = dget(nd->path.dentry);
|
||||
|
||||
/* Correct the device pathname */
|
||||
nfs_fix_devname(&nd->path, mnt_target);
|
||||
dentry = dget(nd->path.dentry);
|
||||
|
||||
path_put(&nd->path);
|
||||
kfree(nd);
|
||||
down_write(&s->s_umount);
|
||||
return 0;
|
||||
return dentry;
|
||||
out_put_mnt_ns:
|
||||
put_mnt_ns(ns_private);
|
||||
out_mntput:
|
||||
mntput(root_mnt);
|
||||
out_err:
|
||||
kfree(nd);
|
||||
return ret;
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static int nfs4_try_mount(int flags, const char *dev_name,
|
||||
struct nfs_parsed_mount_data *data,
|
||||
struct vfsmount *mnt)
|
||||
static struct dentry *nfs4_try_mount(int flags, const char *dev_name,
|
||||
struct nfs_parsed_mount_data *data)
|
||||
{
|
||||
char *export_path;
|
||||
struct vfsmount *root_mnt;
|
||||
int error;
|
||||
struct dentry *res;
|
||||
|
||||
dfprintk(MOUNT, "--> nfs4_try_mount()\n");
|
||||
|
||||
|
@ -2925,26 +2929,25 @@ static int nfs4_try_mount(int flags, const char *dev_name,
|
|||
data->nfs_server.hostname);
|
||||
data->nfs_server.export_path = export_path;
|
||||
|
||||
error = PTR_ERR(root_mnt);
|
||||
if (IS_ERR(root_mnt))
|
||||
goto out;
|
||||
res = ERR_CAST(root_mnt);
|
||||
if (!IS_ERR(root_mnt))
|
||||
res = nfs_follow_remote_path(root_mnt, export_path);
|
||||
|
||||
error = nfs_follow_remote_path(root_mnt, export_path, mnt);
|
||||
|
||||
out:
|
||||
dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n", error,
|
||||
error != 0 ? " [error]" : "");
|
||||
return error;
|
||||
dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s\n",
|
||||
IS_ERR(res) ? PTR_ERR(res) : 0,
|
||||
IS_ERR(res) ? " [error]" : "");
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the superblock for an NFS4 mountpoint
|
||||
*/
|
||||
static int nfs4_get_sb(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
|
||||
static struct dentry *nfs4_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data)
|
||||
{
|
||||
struct nfs_parsed_mount_data *data;
|
||||
int error = -ENOMEM;
|
||||
struct dentry *res = ERR_PTR(-ENOMEM);
|
||||
|
||||
data = nfs_alloc_parsed_mount_data(4);
|
||||
if (data == NULL)
|
||||
|
@ -2952,10 +2955,14 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
|
|||
|
||||
/* Validate the mount data */
|
||||
error = nfs4_validate_mount_data(raw_data, data, dev_name);
|
||||
if (error < 0)
|
||||
if (error < 0) {
|
||||
res = ERR_PTR(error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = nfs4_try_mount(flags, dev_name, data, mnt);
|
||||
res = nfs4_try_mount(flags, dev_name, data);
|
||||
if (IS_ERR(res))
|
||||
error = PTR_ERR(res);
|
||||
|
||||
out:
|
||||
kfree(data->client_address);
|
||||
|
@ -2964,9 +2971,9 @@ out:
|
|||
kfree(data->fscache_uniq);
|
||||
out_free_data:
|
||||
kfree(data);
|
||||
dprintk("<-- nfs4_get_sb() = %d%s\n", error,
|
||||
dprintk("<-- nfs4_mount() = %d%s\n", error,
|
||||
error != 0 ? " [error]" : "");
|
||||
return error;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void nfs4_kill_super(struct super_block *sb)
|
||||
|
@ -3033,7 +3040,7 @@ nfs4_xdev_mount(struct file_system_type *fs_type, int flags,
|
|||
nfs_fscache_get_super_cookie(s, NULL, data);
|
||||
}
|
||||
|
||||
mntroot = nfs4_get_root(s, data->fh);
|
||||
mntroot = nfs4_get_root(s, data->fh, dev_name);
|
||||
if (IS_ERR(mntroot)) {
|
||||
error = PTR_ERR(mntroot);
|
||||
goto error_splat_super;
|
||||
|
@ -3120,7 +3127,7 @@ nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags,
|
|||
nfs_fscache_get_super_cookie(s, NULL, data);
|
||||
}
|
||||
|
||||
mntroot = nfs4_get_root(s, mntfh);
|
||||
mntroot = nfs4_get_root(s, mntfh, dev_name);
|
||||
if (IS_ERR(mntroot)) {
|
||||
error = PTR_ERR(mntroot);
|
||||
goto error_splat_super;
|
||||
|
@ -3160,16 +3167,15 @@ error_splat_bdi:
|
|||
/*
|
||||
* Create an NFS4 server record on referral traversal
|
||||
*/
|
||||
static int nfs4_referral_get_sb(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data,
|
||||
struct vfsmount *mnt)
|
||||
static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data)
|
||||
{
|
||||
struct nfs_clone_mount *data = raw_data;
|
||||
char *export_path;
|
||||
struct vfsmount *root_mnt;
|
||||
int error;
|
||||
struct dentry *res;
|
||||
|
||||
dprintk("--> nfs4_referral_get_sb()\n");
|
||||
dprintk("--> nfs4_referral_mount()\n");
|
||||
|
||||
export_path = data->mnt_path;
|
||||
data->mnt_path = "/";
|
||||
|
@ -3178,15 +3184,13 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type,
|
|||
flags, data, data->hostname);
|
||||
data->mnt_path = export_path;
|
||||
|
||||
error = PTR_ERR(root_mnt);
|
||||
if (IS_ERR(root_mnt))
|
||||
goto out;
|
||||
|
||||
error = nfs_follow_remote_path(root_mnt, export_path, mnt);
|
||||
out:
|
||||
dprintk("<-- nfs4_referral_get_sb() = %d%s\n", error,
|
||||
error != 0 ? " [error]" : "");
|
||||
return error;
|
||||
res = ERR_CAST(root_mnt);
|
||||
if (!IS_ERR(root_mnt))
|
||||
res = nfs_follow_remote_path(root_mnt, export_path);
|
||||
dprintk("<-- nfs4_referral_mount() = %ld%s\n",
|
||||
IS_ERR(res) ? PTR_ERR(res) : 0,
|
||||
IS_ERR(res) ? " [error]" : "");
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NFS_V4 */
|
||||
|
|
|
@ -148,6 +148,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n
|
|||
alias = d_lookup(parent, &data->args.name);
|
||||
if (alias != NULL) {
|
||||
int ret = 0;
|
||||
void *devname_garbage = NULL;
|
||||
|
||||
/*
|
||||
* Hey, we raced with lookup... See if we need to transfer
|
||||
|
@ -157,6 +158,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n
|
|||
spin_lock(&alias->d_lock);
|
||||
if (alias->d_inode != NULL &&
|
||||
!(alias->d_flags & DCACHE_NFSFS_RENAMED)) {
|
||||
devname_garbage = alias->d_fsdata;
|
||||
alias->d_fsdata = data;
|
||||
alias->d_flags |= DCACHE_NFSFS_RENAMED;
|
||||
ret = 1;
|
||||
|
@ -164,6 +166,13 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n
|
|||
spin_unlock(&alias->d_lock);
|
||||
nfs_dec_sillycount(dir);
|
||||
dput(alias);
|
||||
/*
|
||||
* If we'd displaced old cached devname, free it. At that
|
||||
* point dentry is definitely not a root, so we won't need
|
||||
* that anymore.
|
||||
*/
|
||||
if (devname_garbage)
|
||||
kfree(devname_garbage);
|
||||
return ret;
|
||||
}
|
||||
data->dir = igrab(dir);
|
||||
|
@ -252,6 +261,7 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry)
|
|||
{
|
||||
struct nfs_unlinkdata *data;
|
||||
int status = -ENOMEM;
|
||||
void *devname_garbage = NULL;
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (data == NULL)
|
||||
|
@ -269,8 +279,16 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry)
|
|||
if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
|
||||
goto out_unlock;
|
||||
dentry->d_flags |= DCACHE_NFSFS_RENAMED;
|
||||
devname_garbage = dentry->d_fsdata;
|
||||
dentry->d_fsdata = data;
|
||||
spin_unlock(&dentry->d_lock);
|
||||
/*
|
||||
* If we'd displaced old cached devname, free it. At that
|
||||
* point dentry is definitely not a root, so we won't need
|
||||
* that anymore.
|
||||
*/
|
||||
if (devname_garbage)
|
||||
kfree(devname_garbage);
|
||||
return 0;
|
||||
out_unlock:
|
||||
spin_unlock(&dentry->d_lock);
|
||||
|
@ -299,6 +317,7 @@ nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
|
|||
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
|
||||
dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
|
||||
data = dentry->d_fsdata;
|
||||
dentry->d_fsdata = NULL;
|
||||
}
|
||||
spin_unlock(&dentry->d_lock);
|
||||
|
||||
|
@ -315,6 +334,7 @@ nfs_cancel_async_unlink(struct dentry *dentry)
|
|||
struct nfs_unlinkdata *data = dentry->d_fsdata;
|
||||
|
||||
dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
|
||||
dentry->d_fsdata = NULL;
|
||||
spin_unlock(&dentry->d_lock);
|
||||
nfs_free_unlinkdata(data);
|
||||
return;
|
||||
|
|
67
fs/super.c
67
fs/super.c
|
@ -843,23 +843,6 @@ error:
|
|||
}
|
||||
EXPORT_SYMBOL(mount_bdev);
|
||||
|
||||
int get_sb_bdev(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *data,
|
||||
int (*fill_super)(struct super_block *, void *, int),
|
||||
struct vfsmount *mnt)
|
||||
{
|
||||
struct dentry *root;
|
||||
|
||||
root = mount_bdev(fs_type, flags, dev_name, data, fill_super);
|
||||
if (IS_ERR(root))
|
||||
return PTR_ERR(root);
|
||||
mnt->mnt_root = root;
|
||||
mnt->mnt_sb = root->d_sb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(get_sb_bdev);
|
||||
|
||||
void kill_block_super(struct super_block *sb)
|
||||
{
|
||||
struct block_device *bdev = sb->s_bdev;
|
||||
|
@ -897,22 +880,6 @@ struct dentry *mount_nodev(struct file_system_type *fs_type,
|
|||
}
|
||||
EXPORT_SYMBOL(mount_nodev);
|
||||
|
||||
int get_sb_nodev(struct file_system_type *fs_type,
|
||||
int flags, void *data,
|
||||
int (*fill_super)(struct super_block *, void *, int),
|
||||
struct vfsmount *mnt)
|
||||
{
|
||||
struct dentry *root;
|
||||
|
||||
root = mount_nodev(fs_type, flags, data, fill_super);
|
||||
if (IS_ERR(root))
|
||||
return PTR_ERR(root);
|
||||
mnt->mnt_root = root;
|
||||
mnt->mnt_sb = root->d_sb;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(get_sb_nodev);
|
||||
|
||||
static int compare_single(struct super_block *s, void *p)
|
||||
{
|
||||
return 1;
|
||||
|
@ -943,22 +910,6 @@ struct dentry *mount_single(struct file_system_type *fs_type,
|
|||
}
|
||||
EXPORT_SYMBOL(mount_single);
|
||||
|
||||
int get_sb_single(struct file_system_type *fs_type,
|
||||
int flags, void *data,
|
||||
int (*fill_super)(struct super_block *, void *, int),
|
||||
struct vfsmount *mnt)
|
||||
{
|
||||
struct dentry *root;
|
||||
root = mount_single(fs_type, flags, data, fill_super);
|
||||
if (IS_ERR(root))
|
||||
return PTR_ERR(root);
|
||||
mnt->mnt_root = root;
|
||||
mnt->mnt_sb = root->d_sb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(get_sb_single);
|
||||
|
||||
struct vfsmount *
|
||||
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
|
||||
{
|
||||
|
@ -988,19 +939,13 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
|
|||
goto out_free_secdata;
|
||||
}
|
||||
|
||||
if (type->mount) {
|
||||
root = type->mount(type, flags, name, data);
|
||||
if (IS_ERR(root)) {
|
||||
error = PTR_ERR(root);
|
||||
goto out_free_secdata;
|
||||
}
|
||||
mnt->mnt_root = root;
|
||||
mnt->mnt_sb = root->d_sb;
|
||||
} else {
|
||||
error = type->get_sb(type, flags, name, data, mnt);
|
||||
if (error < 0)
|
||||
goto out_free_secdata;
|
||||
root = type->mount(type, flags, name, data);
|
||||
if (IS_ERR(root)) {
|
||||
error = PTR_ERR(root);
|
||||
goto out_free_secdata;
|
||||
}
|
||||
mnt->mnt_root = root;
|
||||
mnt->mnt_sb = root->d_sb;
|
||||
BUG_ON(!mnt->mnt_sb);
|
||||
WARN_ON(!mnt->mnt_sb->s_bdi);
|
||||
mnt->mnt_sb->s_flags |= MS_BORN;
|
||||
|
|
|
@ -1631,6 +1631,8 @@ struct super_operations {
|
|||
void (*umount_begin) (struct super_block *);
|
||||
|
||||
int (*show_options)(struct seq_file *, struct vfsmount *);
|
||||
int (*show_devname)(struct seq_file *, struct vfsmount *);
|
||||
int (*show_path)(struct seq_file *, struct vfsmount *);
|
||||
int (*show_stats)(struct seq_file *, struct vfsmount *);
|
||||
#ifdef CONFIG_QUOTA
|
||||
ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
|
||||
|
@ -1794,8 +1796,6 @@ int sync_inode_metadata(struct inode *inode, int wait);
|
|||
struct file_system_type {
|
||||
const char *name;
|
||||
int fs_flags;
|
||||
int (*get_sb) (struct file_system_type *, int,
|
||||
const char *, void *, struct vfsmount *);
|
||||
struct dentry *(*mount) (struct file_system_type *, int,
|
||||
const char *, void *);
|
||||
void (*kill_sb) (struct super_block *);
|
||||
|
@ -1818,24 +1818,12 @@ extern struct dentry *mount_ns(struct file_system_type *fs_type, int flags,
|
|||
extern struct dentry *mount_bdev(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *data,
|
||||
int (*fill_super)(struct super_block *, void *, int));
|
||||
extern int get_sb_bdev(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *data,
|
||||
int (*fill_super)(struct super_block *, void *, int),
|
||||
struct vfsmount *mnt);
|
||||
extern struct dentry *mount_single(struct file_system_type *fs_type,
|
||||
int flags, void *data,
|
||||
int (*fill_super)(struct super_block *, void *, int));
|
||||
extern int get_sb_single(struct file_system_type *fs_type,
|
||||
int flags, void *data,
|
||||
int (*fill_super)(struct super_block *, void *, int),
|
||||
struct vfsmount *mnt);
|
||||
extern struct dentry *mount_nodev(struct file_system_type *fs_type,
|
||||
int flags, void *data,
|
||||
int (*fill_super)(struct super_block *, void *, int));
|
||||
extern int get_sb_nodev(struct file_system_type *fs_type,
|
||||
int flags, void *data,
|
||||
int (*fill_super)(struct super_block *, void *, int),
|
||||
struct vfsmount *mnt);
|
||||
void generic_shutdown_super(struct super_block *sb);
|
||||
void kill_block_super(struct super_block *sb);
|
||||
void kill_anon_super(struct super_block *sb);
|
||||
|
|
Loading…
Reference in a new issue