mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-03-31 19:45:21 +00:00
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
Documentation/filesystems
fs
include/linux
|
@ -166,13 +166,11 @@ prototypes:
|
||||||
void (*kill_sb) (struct super_block *);
|
void (*kill_sb) (struct super_block *);
|
||||||
locking rules:
|
locking rules:
|
||||||
may block
|
may block
|
||||||
get_sb yes
|
|
||||||
mount yes
|
mount yes
|
||||||
kill_sb yes
|
kill_sb yes
|
||||||
|
|
||||||
->get_sb() returns error or 0 with locked superblock attached to the vfsmount
|
->mount() returns ERR_PTR or the root dentry; its superblock should be locked
|
||||||
(exclusive on ->s_umount).
|
on return.
|
||||||
->mount() returns ERR_PTR or the root dentry.
|
|
||||||
->kill_sb() takes a write-locked superblock, does all shutdown work on it,
|
->kill_sb() takes a write-locked superblock, does all shutdown work on it,
|
||||||
unlocks and drops the reference.
|
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,
|
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
|
so the i_size should not change when hole punching, even when puching the end of
|
||||||
a file off.
|
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 *);
|
extern int unregister_filesystem(struct file_system_type *);
|
||||||
|
|
||||||
The passed struct file_system_type describes your filesystem. When a
|
The passed struct file_system_type describes your filesystem. When a
|
||||||
request is made to mount a device onto a directory in your filespace,
|
request is made to mount a filesystem onto a directory in your namespace,
|
||||||
the VFS will call the appropriate get_sb() method for the specific
|
the VFS will call the appropriate mount() method for the specific
|
||||||
filesystem. The dentry for the mount point will then be updated to
|
filesystem. New vfsmount refering to the tree returned by ->mount()
|
||||||
point to the root inode for the new filesystem.
|
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
|
You can see all filesystems that are registered to the kernel in the
|
||||||
file /proc/filesystems.
|
file /proc/filesystems.
|
||||||
|
@ -107,14 +108,14 @@ file /proc/filesystems.
|
||||||
struct file_system_type
|
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:
|
members are defined:
|
||||||
|
|
||||||
struct file_system_type {
|
struct file_system_type {
|
||||||
const char *name;
|
const char *name;
|
||||||
int fs_flags;
|
int fs_flags;
|
||||||
int (*get_sb) (struct file_system_type *, int,
|
struct dentry (*mount) (struct file_system_type *, int,
|
||||||
const char *, void *, struct vfsmount *);
|
const char *, void *);
|
||||||
void (*kill_sb) (struct super_block *);
|
void (*kill_sb) (struct super_block *);
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
struct file_system_type * next;
|
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.)
|
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
|
filesystem should be mounted
|
||||||
|
|
||||||
kill_sb: the method to call when an instance of this filesystem
|
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
|
owner: for internal VFS use: you should initialize this to THIS_MODULE in
|
||||||
most cases.
|
most cases.
|
||||||
|
@ -141,7 +142,7 @@ struct file_system_type {
|
||||||
|
|
||||||
s_lock_key, s_umount_key: lockdep-specific
|
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
|
struct file_system_type *fs_type: describes the filesystem, partly initialized
|
||||||
by the specific filesystem code
|
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
|
void *data: arbitrary mount options, usually comes as an ASCII
|
||||||
string (see "Mount Options" section)
|
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
|
The arguments match those of mount(2) and their interpretation
|
||||||
in the dev_name and fs_type contains a filesystem of the type the method
|
depends on filesystem type. E.g. for block filesystems, dev_name is
|
||||||
supports. If it succeeds in opening the named block device, it initializes a
|
interpreted as block device name, that device is opened and if it
|
||||||
struct super_block descriptor for the filesystem contained by the block device.
|
contains a suitable filesystem image the method creates and initializes
|
||||||
On failure it returns an error.
|
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
|
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
|
a "struct super_operations" which describes the next level of the
|
||||||
filesystem implementation.
|
filesystem implementation.
|
||||||
|
|
||||||
Usually, a filesystem uses one of the generic get_sb() implementations
|
Usually, a filesystem uses one of the generic mount() implementations
|
||||||
and provides a fill_super() method instead. The generic methods are:
|
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
|
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.
|
must initialize this properly.
|
||||||
|
|
||||||
void *data: arbitrary mount options, usually comes as an ASCII
|
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;
|
int err = 0;
|
||||||
struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
|
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_putc(m, ' ');
|
||||||
seq_path(m, &mnt_path, " \t\n\\");
|
seq_path(m, &mnt_path, " \t\n\\");
|
||||||
seq_putc(m, ' ');
|
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,
|
seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id,
|
||||||
MAJOR(sb->s_dev), MINOR(sb->s_dev));
|
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_putc(m, ' ');
|
||||||
seq_path_root(m, &mnt_path, &root, " \t\n\\");
|
seq_path_root(m, &mnt_path, &root, " \t\n\\");
|
||||||
if (root.mnt != p->root.mnt || root.dentry != p->root.dentry) {
|
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, " - ");
|
seq_puts(m, " - ");
|
||||||
show_type(m, sb);
|
show_type(m, sb);
|
||||||
seq_putc(m, ' ');
|
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");
|
seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw");
|
||||||
err = show_sb_opts(m, sb);
|
err = show_sb_opts(m, sb);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -1086,11 +1102,15 @@ static int show_vfsstat(struct seq_file *m, void *v)
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
/* device */
|
/* device */
|
||||||
if (mnt->mnt_devname) {
|
if (mnt->mnt_sb->s_op->show_devname) {
|
||||||
seq_puts(m, "device ");
|
err = mnt->mnt_sb->s_op->show_devname(m, mnt);
|
||||||
mangle(m, mnt->mnt_devname);
|
} else {
|
||||||
} else
|
if (mnt->mnt_devname) {
|
||||||
seq_puts(m, "no device");
|
seq_puts(m, "device ");
|
||||||
|
mangle(m, mnt->mnt_devname);
|
||||||
|
} else
|
||||||
|
seq_puts(m, "no device");
|
||||||
|
}
|
||||||
|
|
||||||
/* mount point */
|
/* mount point */
|
||||||
seq_puts(m, " mounted on ");
|
seq_puts(m, " mounted on ");
|
||||||
|
@ -1104,7 +1124,8 @@ static int show_vfsstat(struct seq_file *m, void *v)
|
||||||
/* optional statistics */
|
/* optional statistics */
|
||||||
if (mnt->mnt_sb->s_op->show_stats) {
|
if (mnt->mnt_sb->s_op->show_stats) {
|
||||||
seq_putc(m, ' ');
|
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');
|
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);
|
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 = {
|
const struct dentry_operations nfs_dentry_operations = {
|
||||||
.d_revalidate = nfs_lookup_revalidate,
|
.d_revalidate = nfs_lookup_revalidate,
|
||||||
.d_delete = nfs_dentry_delete,
|
.d_delete = nfs_dentry_delete,
|
||||||
.d_iput = nfs_dentry_iput,
|
.d_iput = nfs_dentry_iput,
|
||||||
.d_automount = nfs_d_automount,
|
.d_automount = nfs_d_automount,
|
||||||
|
.d_release = nfs_d_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
|
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_delete = nfs_dentry_delete,
|
||||||
.d_iput = nfs_dentry_iput,
|
.d_iput = nfs_dentry_iput,
|
||||||
.d_automount = nfs_d_automount,
|
.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
|
* 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_server *server = NFS_SB(sb);
|
||||||
struct nfs_fsinfo fsinfo;
|
struct nfs_fsinfo fsinfo;
|
||||||
struct dentry *ret;
|
struct dentry *ret;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
void *name = kstrdup(devname, GFP_KERNEL);
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
/* get the actual root for this mount */
|
/* get the actual root for this mount */
|
||||||
fsinfo.fattr = nfs_alloc_fattr();
|
fsinfo.fattr = nfs_alloc_fattr();
|
||||||
if (fsinfo.fattr == NULL)
|
if (fsinfo.fattr == NULL) {
|
||||||
|
kfree(name);
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
|
error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
|
||||||
if (error < 0) {
|
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);
|
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:
|
out:
|
||||||
|
if (name)
|
||||||
|
kfree(name);
|
||||||
nfs_free_fattr(fsinfo.fattr);
|
nfs_free_fattr(fsinfo.fattr);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -169,27 +184,35 @@ out:
|
||||||
/*
|
/*
|
||||||
* get an NFS4 root dentry from the root filehandle
|
* 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_server *server = NFS_SB(sb);
|
||||||
struct nfs_fattr *fattr = NULL;
|
struct nfs_fattr *fattr = NULL;
|
||||||
struct dentry *ret;
|
struct dentry *ret;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
void *name = kstrdup(devname, GFP_KERNEL);
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
dprintk("--> nfs4_get_root()\n");
|
dprintk("--> nfs4_get_root()\n");
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
/* get the info about the server and filesystem */
|
/* get the info about the server and filesystem */
|
||||||
error = nfs4_server_capabilities(server, mntfh);
|
error = nfs4_server_capabilities(server, mntfh);
|
||||||
if (error < 0) {
|
if (error < 0) {
|
||||||
dprintk("nfs_get_root: getcaps error = %d\n",
|
dprintk("nfs_get_root: getcaps error = %d\n",
|
||||||
-error);
|
-error);
|
||||||
|
kfree(name);
|
||||||
return ERR_PTR(error);
|
return ERR_PTR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
fattr = nfs_alloc_fattr();
|
fattr = nfs_alloc_fattr();
|
||||||
if (fattr == NULL)
|
if (fattr == NULL) {
|
||||||
return ERR_PTR(-ENOMEM);;
|
kfree(name);
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
/* get the actual root for this mount */
|
/* get the actual root for this mount */
|
||||||
error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr);
|
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);
|
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:
|
out:
|
||||||
|
if (name)
|
||||||
|
kfree(name);
|
||||||
nfs_free_fattr(fattr);
|
nfs_free_fattr(fattr);
|
||||||
dprintk("<-- nfs4_get_root()\n");
|
dprintk("<-- nfs4_get_root()\n");
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -163,10 +163,10 @@ static inline void nfs_fs_proc_exit(void)
|
||||||
|
|
||||||
/* nfs4namespace.c */
|
/* nfs4namespace.c */
|
||||||
#ifdef CONFIG_NFS_V4
|
#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
|
#else
|
||||||
static inline
|
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);
|
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);
|
extern void nfs_sb_deactive(struct super_block *sb);
|
||||||
|
|
||||||
/* namespace.c */
|
/* namespace.c */
|
||||||
extern char *nfs_path(const char *base,
|
extern char *nfs_path(char **p, struct dentry *dentry,
|
||||||
const struct dentry *droot,
|
|
||||||
const struct dentry *dentry,
|
|
||||||
char *buffer, ssize_t buflen);
|
char *buffer, ssize_t buflen);
|
||||||
extern struct vfsmount *nfs_d_automount(struct path *path);
|
extern struct vfsmount *nfs_d_automount(struct path *path);
|
||||||
|
|
||||||
/* getroot.c */
|
/* 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
|
#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);
|
extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh);
|
||||||
#endif
|
#endif
|
||||||
|
@ -288,12 +288,11 @@ extern int _nfs4_call_sync_session(struct nfs_server *server,
|
||||||
/*
|
/*
|
||||||
* Determine the device name as a string
|
* Determine the device name as a string
|
||||||
*/
|
*/
|
||||||
static inline char *nfs_devname(const struct vfsmount *mnt_parent,
|
static inline char *nfs_devname(struct dentry *dentry,
|
||||||
const struct dentry *dentry,
|
|
||||||
char *buffer, ssize_t buflen)
|
char *buffer, ssize_t buflen)
|
||||||
{
|
{
|
||||||
return nfs_path(mnt_parent->mnt_devname, mnt_parent->mnt_root,
|
char *dummy;
|
||||||
dentry, buffer, buflen);
|
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);
|
static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts);
|
||||||
int nfs_mountpoint_expiry_timeout = 500 * HZ;
|
int nfs_mountpoint_expiry_timeout = 500 * HZ;
|
||||||
|
|
||||||
static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
|
static struct vfsmount *nfs_do_submount(struct dentry *dentry,
|
||||||
const struct dentry *dentry,
|
|
||||||
struct nfs_fh *fh,
|
struct nfs_fh *fh,
|
||||||
struct nfs_fattr *fattr);
|
struct nfs_fattr *fattr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* nfs_path - reconstruct the path given an arbitrary dentry
|
* nfs_path - reconstruct the path given an arbitrary dentry
|
||||||
* @base - arbitrary string to prepend to the path
|
* @base - used to return pointer to the end of devname part of path
|
||||||
* @droot - pointer to root dentry for mountpoint
|
|
||||||
* @dentry - pointer to dentry
|
* @dentry - pointer to dentry
|
||||||
* @buffer - result buffer
|
* @buffer - result buffer
|
||||||
* @buflen - length of buffer
|
* @buflen - length of buffer
|
||||||
*
|
*
|
||||||
* Helper function for constructing the path from the
|
* Helper function for constructing the server pathname
|
||||||
* root dentry to an arbitrary hashed dentry.
|
* by arbitrary hashed dentry.
|
||||||
*
|
*
|
||||||
* This is mainly for use in figuring out the path on the
|
* 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,
|
char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen)
|
||||||
const struct dentry *droot,
|
|
||||||
const struct dentry *dentry,
|
|
||||||
char *buffer, ssize_t buflen)
|
|
||||||
{
|
{
|
||||||
char *end;
|
char *end;
|
||||||
int namelen;
|
int namelen;
|
||||||
unsigned seq;
|
unsigned seq;
|
||||||
|
const char *base;
|
||||||
|
|
||||||
rename_retry:
|
rename_retry:
|
||||||
end = buffer+buflen;
|
end = buffer+buflen;
|
||||||
|
@ -60,7 +57,10 @@ rename_retry:
|
||||||
|
|
||||||
seq = read_seqbegin(&rename_lock);
|
seq = read_seqbegin(&rename_lock);
|
||||||
rcu_read_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;
|
namelen = dentry->d_name.len;
|
||||||
buflen -= namelen + 1;
|
buflen -= namelen + 1;
|
||||||
if (buflen < 0)
|
if (buflen < 0)
|
||||||
|
@ -68,27 +68,47 @@ rename_retry:
|
||||||
end -= namelen;
|
end -= namelen;
|
||||||
memcpy(end, dentry->d_name.name, namelen);
|
memcpy(end, dentry->d_name.name, namelen);
|
||||||
*--end = '/';
|
*--end = '/';
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
dentry = dentry->d_parent;
|
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;
|
goto rename_retry;
|
||||||
|
}
|
||||||
if (*end != '/') {
|
if (*end != '/') {
|
||||||
if (--buflen < 0)
|
if (--buflen < 0) {
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
|
rcu_read_unlock();
|
||||||
goto Elong;
|
goto Elong;
|
||||||
|
}
|
||||||
*--end = '/';
|
*--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);
|
namelen = strlen(base);
|
||||||
/* Strip off excess slashes in base string */
|
/* Strip off excess slashes in base string */
|
||||||
while (namelen > 0 && base[namelen - 1] == '/')
|
while (namelen > 0 && base[namelen - 1] == '/')
|
||||||
namelen--;
|
namelen--;
|
||||||
buflen -= namelen;
|
buflen -= namelen;
|
||||||
if (buflen < 0)
|
if (buflen < 0) {
|
||||||
|
spin_lock(&dentry->d_lock);
|
||||||
|
rcu_read_unlock();
|
||||||
goto Elong;
|
goto Elong;
|
||||||
|
}
|
||||||
end -= namelen;
|
end -= namelen;
|
||||||
memcpy(end, base, namelen);
|
memcpy(end, base, namelen);
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
|
rcu_read_unlock();
|
||||||
return end;
|
return end;
|
||||||
Elong_unlock:
|
Elong_unlock:
|
||||||
|
spin_lock(&dentry->d_lock);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
if (read_seqretry(&rename_lock, seq))
|
if (read_seqretry(&rename_lock, seq))
|
||||||
goto rename_retry;
|
goto rename_retry;
|
||||||
|
@ -143,9 +163,9 @@ struct vfsmount *nfs_d_automount(struct path *path)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
|
if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
|
||||||
mnt = nfs_do_refmount(path->mnt, path->dentry);
|
mnt = nfs_do_refmount(path->dentry);
|
||||||
else
|
else
|
||||||
mnt = nfs_do_submount(path->mnt, path->dentry, fh, fattr);
|
mnt = nfs_do_submount(path->dentry, fh, fattr);
|
||||||
if (IS_ERR(mnt))
|
if (IS_ERR(mnt))
|
||||||
goto out;
|
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
|
* nfs_do_submount - set up mountpoint when crossing a filesystem boundary
|
||||||
* @mnt_parent - mountpoint of parent directory
|
|
||||||
* @dentry - parent directory
|
* @dentry - parent directory
|
||||||
* @fh - filehandle for new root dentry
|
* @fh - filehandle for new root dentry
|
||||||
* @fattr - attributes for new root inode
|
* @fattr - attributes for new root inode
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
|
static struct vfsmount *nfs_do_submount(struct dentry *dentry,
|
||||||
const struct dentry *dentry,
|
|
||||||
struct nfs_fh *fh,
|
struct nfs_fh *fh,
|
||||||
struct nfs_fattr *fattr)
|
struct nfs_fattr *fattr)
|
||||||
{
|
{
|
||||||
struct nfs_clone_mount mountdata = {
|
struct nfs_clone_mount mountdata = {
|
||||||
.sb = mnt_parent->mnt_sb,
|
.sb = dentry->d_sb,
|
||||||
.dentry = dentry,
|
.dentry = dentry,
|
||||||
.fh = fh,
|
.fh = fh,
|
||||||
.fattr = fattr,
|
.fattr = fattr,
|
||||||
|
@ -237,11 +255,11 @@ static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
|
||||||
dentry->d_name.name);
|
dentry->d_name.name);
|
||||||
if (page == NULL)
|
if (page == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE);
|
devname = nfs_devname(dentry, page, PAGE_SIZE);
|
||||||
mnt = (struct vfsmount *)devname;
|
mnt = (struct vfsmount *)devname;
|
||||||
if (IS_ERR(devname))
|
if (IS_ERR(devname))
|
||||||
goto free_page;
|
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:
|
||||||
free_page((unsigned long)page);
|
free_page((unsigned long)page);
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -54,33 +54,29 @@ Elong:
|
||||||
/*
|
/*
|
||||||
* Determine the mount path as a string
|
* Determine the mount path as a string
|
||||||
*/
|
*/
|
||||||
static char *nfs4_path(const struct vfsmount *mnt_parent,
|
static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen)
|
||||||
const struct dentry *dentry,
|
|
||||||
char *buffer, ssize_t buflen)
|
|
||||||
{
|
{
|
||||||
const char *srvpath;
|
char *limit;
|
||||||
|
char *path = nfs_path(&limit, dentry, buffer, buflen);
|
||||||
srvpath = strchr(mnt_parent->mnt_devname, ':');
|
if (!IS_ERR(path)) {
|
||||||
if (srvpath)
|
char *colon = strchr(path, ':');
|
||||||
srvpath++;
|
if (colon && colon < limit)
|
||||||
else
|
path = colon + 1;
|
||||||
srvpath = mnt_parent->mnt_devname;
|
}
|
||||||
|
return path;
|
||||||
return nfs_path(srvpath, mnt_parent->mnt_root, dentry, buffer, buflen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we
|
* Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we
|
||||||
* believe to be the server path to this dentry
|
* believe to be the server path to this dentry
|
||||||
*/
|
*/
|
||||||
static int nfs4_validate_fspath(const struct vfsmount *mnt_parent,
|
static int nfs4_validate_fspath(struct dentry *dentry,
|
||||||
const struct dentry *dentry,
|
|
||||||
const struct nfs4_fs_locations *locations,
|
const struct nfs4_fs_locations *locations,
|
||||||
char *page, char *page2)
|
char *page, char *page2)
|
||||||
{
|
{
|
||||||
const char *path, *fs_path;
|
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))
|
if (IS_ERR(path))
|
||||||
return PTR_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
|
* nfs_follow_referral - set up mountpoint when hitting a referral on moved error
|
||||||
* @mnt_parent - mountpoint of parent directory
|
|
||||||
* @dentry - parent directory
|
* @dentry - parent directory
|
||||||
* @locations - array of NFSv4 server location information
|
* @locations - array of NFSv4 server location information
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
|
static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
|
||||||
const struct dentry *dentry,
|
|
||||||
const struct nfs4_fs_locations *locations)
|
const struct nfs4_fs_locations *locations)
|
||||||
{
|
{
|
||||||
struct vfsmount *mnt = ERR_PTR(-ENOENT);
|
struct vfsmount *mnt = ERR_PTR(-ENOENT);
|
||||||
struct nfs_clone_mount mountdata = {
|
struct nfs_clone_mount mountdata = {
|
||||||
.sb = mnt_parent->mnt_sb,
|
.sb = dentry->d_sb,
|
||||||
.dentry = dentry,
|
.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;
|
char *page = NULL, *page2 = NULL;
|
||||||
int loc, error;
|
int loc, error;
|
||||||
|
@ -198,7 +192,7 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Ensure fs path is a prefix of current dentry path */
|
/* 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) {
|
if (error < 0) {
|
||||||
mnt = ERR_PTR(error);
|
mnt = ERR_PTR(error);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -225,11 +219,10 @@ out:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* nfs_do_refmount - handle crossing a referral on server
|
* nfs_do_refmount - handle crossing a referral on server
|
||||||
* @mnt_parent - mountpoint of referral
|
|
||||||
* @dentry - dentry 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 vfsmount *mnt = ERR_PTR(-ENOMEM);
|
||||||
struct dentry *parent;
|
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)
|
fs_locations->fs_path.ncomponents <= 0)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
mnt = nfs_follow_referral(mnt_parent, dentry, fs_locations);
|
mnt = nfs_follow_referral(dentry, fs_locations);
|
||||||
out_free:
|
out_free:
|
||||||
__free_page(page);
|
__free_page(page);
|
||||||
kfree(fs_locations);
|
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 void nfs_umount_begin(struct super_block *);
|
||||||
static int nfs_statfs(struct dentry *, struct kstatfs *);
|
static int nfs_statfs(struct dentry *, struct kstatfs *);
|
||||||
static int nfs_show_options(struct seq_file *, struct vfsmount *);
|
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_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,
|
static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type,
|
||||||
int flags, const char *dev_name, void *raw_data);
|
int flags, const char *dev_name, void *raw_data);
|
||||||
static void nfs_put_super(struct super_block *);
|
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 = {
|
static struct file_system_type nfs_fs_type = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = "nfs",
|
.name = "nfs",
|
||||||
.get_sb = nfs_get_sb,
|
.mount = nfs_fs_mount,
|
||||||
.kill_sb = nfs_kill_super,
|
.kill_sb = nfs_kill_super,
|
||||||
.fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
|
.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,
|
.evict_inode = nfs_evict_inode,
|
||||||
.umount_begin = nfs_umount_begin,
|
.umount_begin = nfs_umount_begin,
|
||||||
.show_options = nfs_show_options,
|
.show_options = nfs_show_options,
|
||||||
|
.show_devname = nfs_show_devname,
|
||||||
|
.show_path = nfs_show_path,
|
||||||
.show_stats = nfs_show_stats,
|
.show_stats = nfs_show_stats,
|
||||||
.remount_fs = nfs_remount,
|
.remount_fs = nfs_remount,
|
||||||
};
|
};
|
||||||
|
@ -303,16 +308,16 @@ static const struct super_operations nfs_sops = {
|
||||||
#ifdef CONFIG_NFS_V4
|
#ifdef CONFIG_NFS_V4
|
||||||
static int nfs4_validate_text_mount_data(void *options,
|
static int nfs4_validate_text_mount_data(void *options,
|
||||||
struct nfs_parsed_mount_data *args, const char *dev_name);
|
struct nfs_parsed_mount_data *args, const char *dev_name);
|
||||||
static int nfs4_try_mount(int flags, const char *dev_name,
|
static struct dentry *nfs4_try_mount(int flags, const char *dev_name,
|
||||||
struct nfs_parsed_mount_data *data, struct vfsmount *mnt);
|
struct nfs_parsed_mount_data *data);
|
||||||
static int nfs4_get_sb(struct file_system_type *fs_type,
|
static struct dentry *nfs4_mount(struct file_system_type *fs_type,
|
||||||
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
|
int flags, const char *dev_name, void *raw_data);
|
||||||
static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type,
|
static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type,
|
||||||
int flags, const char *dev_name, void *raw_data);
|
int flags, const char *dev_name, void *raw_data);
|
||||||
static struct dentry *nfs4_xdev_mount(struct file_system_type *fs_type,
|
static struct dentry *nfs4_xdev_mount(struct file_system_type *fs_type,
|
||||||
int flags, const char *dev_name, void *raw_data);
|
int flags, const char *dev_name, void *raw_data);
|
||||||
static int nfs4_referral_get_sb(struct file_system_type *fs_type,
|
static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
|
||||||
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
|
int flags, const char *dev_name, void *raw_data);
|
||||||
static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type,
|
static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type,
|
||||||
int flags, const char *dev_name, void *raw_data);
|
int flags, const char *dev_name, void *raw_data);
|
||||||
static void nfs4_kill_super(struct super_block *sb);
|
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 = {
|
static struct file_system_type nfs4_fs_type = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = "nfs4",
|
.name = "nfs4",
|
||||||
.get_sb = nfs4_get_sb,
|
.mount = nfs4_mount,
|
||||||
.kill_sb = nfs4_kill_super,
|
.kill_sb = nfs4_kill_super,
|
||||||
.fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
|
.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 = {
|
struct file_system_type nfs4_referral_fs_type = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = "nfs4",
|
.name = "nfs4",
|
||||||
.get_sb = nfs4_referral_get_sb,
|
.mount = nfs4_referral_mount,
|
||||||
.kill_sb = nfs4_kill_super,
|
.kill_sb = nfs4_kill_super,
|
||||||
.fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
|
.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,
|
.evict_inode = nfs4_evict_inode,
|
||||||
.umount_begin = nfs_umount_begin,
|
.umount_begin = nfs_umount_begin,
|
||||||
.show_options = nfs_show_options,
|
.show_options = nfs_show_options,
|
||||||
|
.show_devname = nfs_show_devname,
|
||||||
|
.show_path = nfs_show_path,
|
||||||
.show_stats = nfs_show_stats,
|
.show_stats = nfs_show_stats,
|
||||||
.remount_fs = nfs_remount,
|
.remount_fs = nfs_remount,
|
||||||
};
|
};
|
||||||
|
@ -726,6 +733,28 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
|
||||||
return 0;
|
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
|
* 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);
|
return bdi_register_dev(&server->backing_dev_info, server->s_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nfs_get_sb(struct file_system_type *fs_type,
|
static struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
|
||||||
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
|
int flags, const char *dev_name, void *raw_data)
|
||||||
{
|
{
|
||||||
struct nfs_server *server = NULL;
|
struct nfs_server *server = NULL;
|
||||||
struct super_block *s;
|
struct super_block *s;
|
||||||
struct nfs_parsed_mount_data *data;
|
struct nfs_parsed_mount_data *data;
|
||||||
struct nfs_fh *mntfh;
|
struct nfs_fh *mntfh;
|
||||||
struct dentry *mntroot;
|
struct dentry *mntroot = ERR_PTR(-ENOMEM);
|
||||||
int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
|
int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
|
||||||
struct nfs_sb_mountdata sb_mntdata = {
|
struct nfs_sb_mountdata sb_mntdata = {
|
||||||
.mntflags = flags,
|
.mntflags = flags,
|
||||||
};
|
};
|
||||||
int error = -ENOMEM;
|
int error;
|
||||||
|
|
||||||
data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION);
|
data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION);
|
||||||
mntfh = nfs_alloc_fhandle();
|
mntfh = nfs_alloc_fhandle();
|
||||||
|
@ -2290,12 +2319,14 @@ static int nfs_get_sb(struct file_system_type *fs_type,
|
||||||
|
|
||||||
/* Validate the mount data */
|
/* Validate the mount data */
|
||||||
error = nfs_validate_mount_data(raw_data, data, mntfh, dev_name);
|
error = nfs_validate_mount_data(raw_data, data, mntfh, dev_name);
|
||||||
if (error < 0)
|
if (error < 0) {
|
||||||
|
mntroot = ERR_PTR(error);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_NFS_V4
|
#ifdef CONFIG_NFS_V4
|
||||||
if (data->version == 4) {
|
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->client_address);
|
||||||
kfree(data->nfs_server.export_path);
|
kfree(data->nfs_server.export_path);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -2305,7 +2336,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
|
||||||
/* Get a volume representation */
|
/* Get a volume representation */
|
||||||
server = nfs_create_server(data, mntfh);
|
server = nfs_create_server(data, mntfh);
|
||||||
if (IS_ERR(server)) {
|
if (IS_ERR(server)) {
|
||||||
error = PTR_ERR(server);
|
mntroot = ERR_CAST(server);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
sb_mntdata.server = server;
|
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 */
|
/* 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);
|
s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata);
|
||||||
if (IS_ERR(s)) {
|
if (IS_ERR(s)) {
|
||||||
error = PTR_ERR(s);
|
mntroot = ERR_CAST(s);
|
||||||
goto out_err_nosb;
|
goto out_err_nosb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2325,8 +2356,10 @@ static int nfs_get_sb(struct file_system_type *fs_type,
|
||||||
server = NULL;
|
server = NULL;
|
||||||
} else {
|
} else {
|
||||||
error = nfs_bdi_register(server);
|
error = nfs_bdi_register(server);
|
||||||
if (error)
|
if (error) {
|
||||||
|
mntroot = ERR_PTR(error);
|
||||||
goto error_splat_bdi;
|
goto error_splat_bdi;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!s->s_root) {
|
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);
|
s, data ? data->fscache_uniq : NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
mntroot = nfs_get_root(s, mntfh);
|
mntroot = nfs_get_root(s, mntfh, dev_name);
|
||||||
if (IS_ERR(mntroot)) {
|
if (IS_ERR(mntroot))
|
||||||
error = PTR_ERR(mntroot);
|
|
||||||
goto error_splat_super;
|
goto error_splat_super;
|
||||||
}
|
|
||||||
|
|
||||||
error = security_sb_set_mnt_opts(s, &data->lsm_opts);
|
error = security_sb_set_mnt_opts(s, &data->lsm_opts);
|
||||||
if (error)
|
if (error)
|
||||||
goto error_splat_root;
|
goto error_splat_root;
|
||||||
|
|
||||||
s->s_flags |= MS_ACTIVE;
|
s->s_flags |= MS_ACTIVE;
|
||||||
mnt->mnt_sb = s;
|
|
||||||
mnt->mnt_root = mntroot;
|
|
||||||
error = 0;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kfree(data->nfs_server.hostname);
|
kfree(data->nfs_server.hostname);
|
||||||
|
@ -2359,7 +2387,7 @@ out:
|
||||||
out_free_fh:
|
out_free_fh:
|
||||||
nfs_free_fhandle(mntfh);
|
nfs_free_fhandle(mntfh);
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return error;
|
return mntroot;
|
||||||
|
|
||||||
out_err_nosb:
|
out_err_nosb:
|
||||||
nfs_free_server(server);
|
nfs_free_server(server);
|
||||||
|
@ -2367,6 +2395,7 @@ out_err_nosb:
|
||||||
|
|
||||||
error_splat_root:
|
error_splat_root:
|
||||||
dput(mntroot);
|
dput(mntroot);
|
||||||
|
mntroot = ERR_PTR(error);
|
||||||
error_splat_super:
|
error_splat_super:
|
||||||
if (server && !s->s_root)
|
if (server && !s->s_root)
|
||||||
bdi_unregister(&server->backing_dev_info);
|
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);
|
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)) {
|
if (IS_ERR(mntroot)) {
|
||||||
error = PTR_ERR(mntroot);
|
error = PTR_ERR(mntroot);
|
||||||
goto error_splat_super;
|
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);
|
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)) {
|
if (IS_ERR(mntroot)) {
|
||||||
error = PTR_ERR(mntroot);
|
error = PTR_ERR(mntroot);
|
||||||
goto error_splat_super;
|
goto error_splat_super;
|
||||||
|
@ -2771,27 +2800,6 @@ static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
|
||||||
return root_mnt;
|
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 nfs_referral_count {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
const struct task_struct *task;
|
const struct task_struct *task;
|
||||||
|
@ -2858,17 +2866,18 @@ static void nfs_referral_loop_unprotect(void)
|
||||||
kfree(p);
|
kfree(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nfs_follow_remote_path(struct vfsmount *root_mnt,
|
static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt,
|
||||||
const char *export_path, struct vfsmount *mnt_target)
|
const char *export_path)
|
||||||
{
|
{
|
||||||
struct nameidata *nd = NULL;
|
struct nameidata *nd = NULL;
|
||||||
struct mnt_namespace *ns_private;
|
struct mnt_namespace *ns_private;
|
||||||
struct super_block *s;
|
struct super_block *s;
|
||||||
|
struct dentry *dentry;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
nd = kmalloc(sizeof(*nd), GFP_KERNEL);
|
nd = kmalloc(sizeof(*nd), GFP_KERNEL);
|
||||||
if (nd == NULL)
|
if (nd == NULL)
|
||||||
return -ENOMEM;
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
ns_private = create_mnt_ns(root_mnt);
|
ns_private = create_mnt_ns(root_mnt);
|
||||||
ret = PTR_ERR(ns_private);
|
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;
|
s = nd->path.mnt->mnt_sb;
|
||||||
atomic_inc(&s->s_active);
|
atomic_inc(&s->s_active);
|
||||||
mnt_target->mnt_sb = s;
|
dentry = dget(nd->path.dentry);
|
||||||
mnt_target->mnt_root = dget(nd->path.dentry);
|
|
||||||
|
|
||||||
/* Correct the device pathname */
|
|
||||||
nfs_fix_devname(&nd->path, mnt_target);
|
|
||||||
|
|
||||||
path_put(&nd->path);
|
path_put(&nd->path);
|
||||||
kfree(nd);
|
kfree(nd);
|
||||||
down_write(&s->s_umount);
|
down_write(&s->s_umount);
|
||||||
return 0;
|
return dentry;
|
||||||
out_put_mnt_ns:
|
out_put_mnt_ns:
|
||||||
put_mnt_ns(ns_private);
|
put_mnt_ns(ns_private);
|
||||||
out_mntput:
|
out_mntput:
|
||||||
mntput(root_mnt);
|
mntput(root_mnt);
|
||||||
out_err:
|
out_err:
|
||||||
kfree(nd);
|
kfree(nd);
|
||||||
return ret;
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nfs4_try_mount(int flags, const char *dev_name,
|
static struct dentry *nfs4_try_mount(int flags, const char *dev_name,
|
||||||
struct nfs_parsed_mount_data *data,
|
struct nfs_parsed_mount_data *data)
|
||||||
struct vfsmount *mnt)
|
|
||||||
{
|
{
|
||||||
char *export_path;
|
char *export_path;
|
||||||
struct vfsmount *root_mnt;
|
struct vfsmount *root_mnt;
|
||||||
int error;
|
struct dentry *res;
|
||||||
|
|
||||||
dfprintk(MOUNT, "--> nfs4_try_mount()\n");
|
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.hostname);
|
||||||
data->nfs_server.export_path = export_path;
|
data->nfs_server.export_path = export_path;
|
||||||
|
|
||||||
error = PTR_ERR(root_mnt);
|
res = ERR_CAST(root_mnt);
|
||||||
if (IS_ERR(root_mnt))
|
if (!IS_ERR(root_mnt))
|
||||||
goto out;
|
res = nfs_follow_remote_path(root_mnt, export_path);
|
||||||
|
|
||||||
error = nfs_follow_remote_path(root_mnt, export_path, mnt);
|
dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s\n",
|
||||||
|
IS_ERR(res) ? PTR_ERR(res) : 0,
|
||||||
out:
|
IS_ERR(res) ? " [error]" : "");
|
||||||
dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n", error,
|
return res;
|
||||||
error != 0 ? " [error]" : "");
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the superblock for an NFS4 mountpoint
|
* Get the superblock for an NFS4 mountpoint
|
||||||
*/
|
*/
|
||||||
static int nfs4_get_sb(struct file_system_type *fs_type,
|
static struct dentry *nfs4_mount(struct file_system_type *fs_type,
|
||||||
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
|
int flags, const char *dev_name, void *raw_data)
|
||||||
{
|
{
|
||||||
struct nfs_parsed_mount_data *data;
|
struct nfs_parsed_mount_data *data;
|
||||||
int error = -ENOMEM;
|
int error = -ENOMEM;
|
||||||
|
struct dentry *res = ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
data = nfs_alloc_parsed_mount_data(4);
|
data = nfs_alloc_parsed_mount_data(4);
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
|
@ -2952,10 +2955,14 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
|
||||||
|
|
||||||
/* Validate the mount data */
|
/* Validate the mount data */
|
||||||
error = nfs4_validate_mount_data(raw_data, data, dev_name);
|
error = nfs4_validate_mount_data(raw_data, data, dev_name);
|
||||||
if (error < 0)
|
if (error < 0) {
|
||||||
|
res = ERR_PTR(error);
|
||||||
goto out;
|
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:
|
out:
|
||||||
kfree(data->client_address);
|
kfree(data->client_address);
|
||||||
|
@ -2964,9 +2971,9 @@ out:
|
||||||
kfree(data->fscache_uniq);
|
kfree(data->fscache_uniq);
|
||||||
out_free_data:
|
out_free_data:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
dprintk("<-- nfs4_get_sb() = %d%s\n", error,
|
dprintk("<-- nfs4_mount() = %d%s\n", error,
|
||||||
error != 0 ? " [error]" : "");
|
error != 0 ? " [error]" : "");
|
||||||
return error;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfs4_kill_super(struct super_block *sb)
|
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);
|
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)) {
|
if (IS_ERR(mntroot)) {
|
||||||
error = PTR_ERR(mntroot);
|
error = PTR_ERR(mntroot);
|
||||||
goto error_splat_super;
|
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);
|
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)) {
|
if (IS_ERR(mntroot)) {
|
||||||
error = PTR_ERR(mntroot);
|
error = PTR_ERR(mntroot);
|
||||||
goto error_splat_super;
|
goto error_splat_super;
|
||||||
|
@ -3160,16 +3167,15 @@ error_splat_bdi:
|
||||||
/*
|
/*
|
||||||
* Create an NFS4 server record on referral traversal
|
* Create an NFS4 server record on referral traversal
|
||||||
*/
|
*/
|
||||||
static int nfs4_referral_get_sb(struct file_system_type *fs_type,
|
static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
|
||||||
int flags, const char *dev_name, void *raw_data,
|
int flags, const char *dev_name, void *raw_data)
|
||||||
struct vfsmount *mnt)
|
|
||||||
{
|
{
|
||||||
struct nfs_clone_mount *data = raw_data;
|
struct nfs_clone_mount *data = raw_data;
|
||||||
char *export_path;
|
char *export_path;
|
||||||
struct vfsmount *root_mnt;
|
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;
|
export_path = data->mnt_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);
|
flags, data, data->hostname);
|
||||||
data->mnt_path = export_path;
|
data->mnt_path = export_path;
|
||||||
|
|
||||||
error = PTR_ERR(root_mnt);
|
res = ERR_CAST(root_mnt);
|
||||||
if (IS_ERR(root_mnt))
|
if (!IS_ERR(root_mnt))
|
||||||
goto out;
|
res = nfs_follow_remote_path(root_mnt, export_path);
|
||||||
|
dprintk("<-- nfs4_referral_mount() = %ld%s\n",
|
||||||
error = nfs_follow_remote_path(root_mnt, export_path, mnt);
|
IS_ERR(res) ? PTR_ERR(res) : 0,
|
||||||
out:
|
IS_ERR(res) ? " [error]" : "");
|
||||||
dprintk("<-- nfs4_referral_get_sb() = %d%s\n", error,
|
return res;
|
||||||
error != 0 ? " [error]" : "");
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_NFS_V4 */
|
#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);
|
alias = d_lookup(parent, &data->args.name);
|
||||||
if (alias != NULL) {
|
if (alias != NULL) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
void *devname_garbage = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hey, we raced with lookup... See if we need to transfer
|
* 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);
|
spin_lock(&alias->d_lock);
|
||||||
if (alias->d_inode != NULL &&
|
if (alias->d_inode != NULL &&
|
||||||
!(alias->d_flags & DCACHE_NFSFS_RENAMED)) {
|
!(alias->d_flags & DCACHE_NFSFS_RENAMED)) {
|
||||||
|
devname_garbage = alias->d_fsdata;
|
||||||
alias->d_fsdata = data;
|
alias->d_fsdata = data;
|
||||||
alias->d_flags |= DCACHE_NFSFS_RENAMED;
|
alias->d_flags |= DCACHE_NFSFS_RENAMED;
|
||||||
ret = 1;
|
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);
|
spin_unlock(&alias->d_lock);
|
||||||
nfs_dec_sillycount(dir);
|
nfs_dec_sillycount(dir);
|
||||||
dput(alias);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
data->dir = igrab(dir);
|
data->dir = igrab(dir);
|
||||||
|
@ -252,6 +261,7 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct nfs_unlinkdata *data;
|
struct nfs_unlinkdata *data;
|
||||||
int status = -ENOMEM;
|
int status = -ENOMEM;
|
||||||
|
void *devname_garbage = NULL;
|
||||||
|
|
||||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
|
@ -269,8 +279,16 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
|
if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
dentry->d_flags |= DCACHE_NFSFS_RENAMED;
|
dentry->d_flags |= DCACHE_NFSFS_RENAMED;
|
||||||
|
devname_garbage = dentry->d_fsdata;
|
||||||
dentry->d_fsdata = data;
|
dentry->d_fsdata = data;
|
||||||
spin_unlock(&dentry->d_lock);
|
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;
|
return 0;
|
||||||
out_unlock:
|
out_unlock:
|
||||||
spin_unlock(&dentry->d_lock);
|
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) {
|
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
|
||||||
dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
|
dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
|
||||||
data = dentry->d_fsdata;
|
data = dentry->d_fsdata;
|
||||||
|
dentry->d_fsdata = NULL;
|
||||||
}
|
}
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
|
|
||||||
|
@ -315,6 +334,7 @@ nfs_cancel_async_unlink(struct dentry *dentry)
|
||||||
struct nfs_unlinkdata *data = dentry->d_fsdata;
|
struct nfs_unlinkdata *data = dentry->d_fsdata;
|
||||||
|
|
||||||
dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
|
dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
|
||||||
|
dentry->d_fsdata = NULL;
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
nfs_free_unlinkdata(data);
|
nfs_free_unlinkdata(data);
|
||||||
return;
|
return;
|
||||||
|
|
67
fs/super.c
67
fs/super.c
|
@ -843,23 +843,6 @@ error:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(mount_bdev);
|
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)
|
void kill_block_super(struct super_block *sb)
|
||||||
{
|
{
|
||||||
struct block_device *bdev = sb->s_bdev;
|
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);
|
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)
|
static int compare_single(struct super_block *s, void *p)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -943,22 +910,6 @@ struct dentry *mount_single(struct file_system_type *fs_type,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(mount_single);
|
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 *
|
struct vfsmount *
|
||||||
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
|
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;
|
goto out_free_secdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type->mount) {
|
root = type->mount(type, flags, name, data);
|
||||||
root = type->mount(type, flags, name, data);
|
if (IS_ERR(root)) {
|
||||||
if (IS_ERR(root)) {
|
error = PTR_ERR(root);
|
||||||
error = PTR_ERR(root);
|
goto out_free_secdata;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
mnt->mnt_root = root;
|
||||||
|
mnt->mnt_sb = root->d_sb;
|
||||||
BUG_ON(!mnt->mnt_sb);
|
BUG_ON(!mnt->mnt_sb);
|
||||||
WARN_ON(!mnt->mnt_sb->s_bdi);
|
WARN_ON(!mnt->mnt_sb->s_bdi);
|
||||||
mnt->mnt_sb->s_flags |= MS_BORN;
|
mnt->mnt_sb->s_flags |= MS_BORN;
|
||||||
|
|
|
@ -1631,6 +1631,8 @@ struct super_operations {
|
||||||
void (*umount_begin) (struct super_block *);
|
void (*umount_begin) (struct super_block *);
|
||||||
|
|
||||||
int (*show_options)(struct seq_file *, struct vfsmount *);
|
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 *);
|
int (*show_stats)(struct seq_file *, struct vfsmount *);
|
||||||
#ifdef CONFIG_QUOTA
|
#ifdef CONFIG_QUOTA
|
||||||
ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
|
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 {
|
struct file_system_type {
|
||||||
const char *name;
|
const char *name;
|
||||||
int fs_flags;
|
int fs_flags;
|
||||||
int (*get_sb) (struct file_system_type *, int,
|
|
||||||
const char *, void *, struct vfsmount *);
|
|
||||||
struct dentry *(*mount) (struct file_system_type *, int,
|
struct dentry *(*mount) (struct file_system_type *, int,
|
||||||
const char *, void *);
|
const char *, void *);
|
||||||
void (*kill_sb) (struct super_block *);
|
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,
|
extern struct dentry *mount_bdev(struct file_system_type *fs_type,
|
||||||
int flags, const char *dev_name, void *data,
|
int flags, const char *dev_name, void *data,
|
||||||
int (*fill_super)(struct super_block *, void *, int));
|
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,
|
extern struct dentry *mount_single(struct file_system_type *fs_type,
|
||||||
int flags, void *data,
|
int flags, void *data,
|
||||||
int (*fill_super)(struct super_block *, void *, int));
|
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,
|
extern struct dentry *mount_nodev(struct file_system_type *fs_type,
|
||||||
int flags, void *data,
|
int flags, void *data,
|
||||||
int (*fill_super)(struct super_block *, void *, int));
|
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 generic_shutdown_super(struct super_block *sb);
|
||||||
void kill_block_super(struct super_block *sb);
|
void kill_block_super(struct super_block *sb);
|
||||||
void kill_anon_super(struct super_block *sb);
|
void kill_anon_super(struct super_block *sb);
|
||||||
|
|
Loading…
Add table
Reference in a new issue