Commit 1d77062b authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge git://git.linux-nfs.org/pub/linux/nfs-2.6

* git://git.linux-nfs.org/pub/linux/nfs-2.6: (51 commits)
  nfs: remove nfs_put_link()
  nfs-build-fix-99
  git-nfs-build-fixes
  Merge branch 'odirect'
  NFS: alloc nfs_read/write_data as direct I/O is scheduled
  NFS: Eliminate nfs_get_user_pages()
  NFS: refactor nfs_direct_free_user_pages
  NFS: remove user_addr, user_count, and pos from nfs_direct_req
  NFS: "open code" the NFS direct write rescheduler
  NFS: Separate functions for counting outstanding NFS direct I/Os
  NLM: Fix reclaim races
  NLM: sem to mutex conversion
  locks.c: add the fl_owner to nlm_compare_locks
  NFS: Display the chosen RPCSEC_GSS security flavour in /proc/mounts
  NFS: Split fs/nfs/inode.c
  NFS: Fix typo in nfs_do_clone_mount()
  NFS: Fix compile errors introduced by referrals patches
  NFSv4: Ensure that referral mounts bind to a reserved port
  NFSv4: A root pathname is sent as a zero component4
  NFSv4: Follow a referral
  ...
parents 25581ad1 76a9f26c
......@@ -19,7 +19,7 @@ following procedure:
(2) Have the follow_link() op do the following steps:
(a) Call do_kern_mount() to call the appropriate filesystem to set up a
(a) Call vfs_kern_mount() to call the appropriate filesystem to set up a
superblock and gain a vfsmount structure representing it.
(b) Copy the nameidata provided as an argument and substitute the dentry
......
......@@ -569,7 +569,7 @@ static int create_special_files (void)
ignore_mount = 1;
/* create the devices special file */
retval = simple_pin_fs("usbfs", &usbfs_mount, &usbfs_mount_count);
retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count);
if (retval) {
err ("Unable to get usbfs mount");
goto exit;
......
......@@ -256,11 +256,12 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt)
}
static void
v9fs_umount_begin(struct super_block *sb)
v9fs_umount_begin(struct vfsmount *vfsmnt, int flags)
{
struct v9fs_session_info *v9ses = sb->s_fs_info;
struct v9fs_session_info *v9ses = vfsmnt->mnt_sb->s_fs_info;
v9fs_session_cancel(v9ses);
if (flags & MNT_FORCE)
v9fs_session_cancel(v9ses);
}
static struct super_operations v9fs_super_ops = {
......
......@@ -203,7 +203,7 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
/* try and do the mount */
kdebug("--- attempting mount %s -o %s ---", devname, options);
mnt = do_kern_mount("afs", 0, devname, options);
mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options);
kdebug("--- mount result %p ---", mnt);
free_page((unsigned long) devname);
......
......@@ -48,7 +48,7 @@ static void afs_put_super(struct super_block *sb);
static void afs_destroy_inode(struct inode *inode);
static struct file_system_type afs_fs_type = {
struct file_system_type afs_fs_type = {
.owner = THIS_MODULE,
.name = "afs",
.get_sb = afs_get_sb,
......
......@@ -38,6 +38,8 @@ static inline struct afs_super_info *AFS_FS_S(struct super_block *sb)
return sb->s_fs_info;
}
extern struct file_system_type afs_fs_type;
#endif /* __KERNEL__ */
#endif /* _LINUX_AFS_SUPER_H */
......@@ -55,6 +55,7 @@ typedef struct {
} Node;
static DEFINE_RWLOCK(entries_lock);
static struct file_system_type bm_fs_type;
static struct vfsmount *bm_mnt;
static int entry_count;
......@@ -637,7 +638,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
if (!inode)
goto out2;
err = simple_pin_fs("binfmt_misc", &bm_mnt, &entry_count);
err = simple_pin_fs(&bm_fs_type, &bm_mnt, &entry_count);
if (err) {
iput(inode);
inode = NULL;
......
......@@ -403,12 +403,14 @@ static struct quotactl_ops cifs_quotactl_ops = {
#endif
#ifdef CONFIG_CIFS_EXPERIMENTAL
static void cifs_umount_begin(struct super_block * sblock)
static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
{
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo * tcon;
cifs_sb = CIFS_SB(sblock);
if (!(flags & MNT_FORCE))
return;
cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
if(cifs_sb == NULL)
return;
......
......@@ -118,7 +118,7 @@ static struct file_system_type configfs_fs_type = {
int configfs_pin_fs(void)
{
return simple_pin_fs("configfs", &configfs_mount,
return simple_pin_fs(&configfs_fs_type, &configfs_mount,
&configfs_mnt_count);
}
......
......@@ -199,7 +199,7 @@ struct dentry *debugfs_create_file(const char *name, mode_t mode,
pr_debug("debugfs: creating file '%s'\n",name);
error = simple_pin_fs("debugfs", &debugfs_mount, &debugfs_mount_count);
error = simple_pin_fs(&debug_fs_type, &debugfs_mount, &debugfs_mount_count);
if (error)
goto exit;
......
......@@ -198,9 +198,10 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
return inode;
}
static void fuse_umount_begin(struct super_block *sb)
static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags)
{
fuse_abort_conn(get_fuse_conn_super(sb));
if (flags & MNT_FORCE)
fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb));
}
static void fuse_put_super(struct super_block *sb)
......
......@@ -424,13 +424,13 @@ out:
static DEFINE_SPINLOCK(pin_fs_lock);
int simple_pin_fs(char *name, struct vfsmount **mount, int *count)
int simple_pin_fs(struct file_system_type *type, struct vfsmount **mount, int *count)
{
struct vfsmount *mnt = NULL;
spin_lock(&pin_fs_lock);
if (unlikely(!*mount)) {
spin_unlock(&pin_fs_lock);
mnt = do_kern_mount(name, 0, name, NULL);
mnt = vfs_kern_mount(type, 0, type->name, NULL);
if (IS_ERR(mnt))
return PTR_ERR(mnt);
spin_lock(&pin_fs_lock);
......
......@@ -147,11 +147,10 @@ u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
* Someone has sent us an SM_NOTIFY. Ensure we bind to the new port number,
* that we mark locks for reclaiming, and that we bump the pseudo NSM state.
*/
static inline
void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
static void nlmclnt_prepare_reclaim(struct nlm_host *host)
{
down_write(&host->h_rwsem);
host->h_monitored = 0;
host->h_nsmstate = newstate;
host->h_state++;
host->h_nextrebind = 0;
nlm_rebind_host(host);
......@@ -164,6 +163,13 @@ void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
dprintk("NLM: reclaiming locks for host %s", host->h_name);
}
static void nlmclnt_finish_reclaim(struct nlm_host *host)
{
host->h_reclaiming = 0;
up_write(&host->h_rwsem);
dprintk("NLM: done reclaiming locks for host %s", host->h_name);
}
/*
* Reclaim all locks on server host. We do this by spawning a separate
* reclaimer thread.
......@@ -171,12 +177,10 @@ void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
void
nlmclnt_recovery(struct nlm_host *host, u32 newstate)
{
if (host->h_reclaiming++) {
if (host->h_nsmstate == newstate)
return;
nlmclnt_prepare_reclaim(host, newstate);
} else {
nlmclnt_prepare_reclaim(host, newstate);
if (host->h_nsmstate == newstate)
return;
host->h_nsmstate = newstate;
if (!host->h_reclaiming++) {
nlm_get_host(host);
__module_get(THIS_MODULE);
if (kernel_thread(reclaimer, host, CLONE_KERNEL) < 0)
......@@ -190,6 +194,7 @@ reclaimer(void *ptr)
struct nlm_host *host = (struct nlm_host *) ptr;
struct nlm_wait *block;
struct file_lock *fl, *next;
u32 nsmstate;
daemonize("%s-reclaim", host->h_name);
allow_signal(SIGKILL);
......@@ -199,19 +204,25 @@ reclaimer(void *ptr)
lock_kernel();
lockd_up();
nlmclnt_prepare_reclaim(host);
/* First, reclaim all locks that have been marked. */
restart:
nsmstate = host->h_nsmstate;
list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
list_del_init(&fl->fl_u.nfs_fl.list);
if (signalled())
continue;
if (nlmclnt_reclaim(host, fl) == 0)
list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
goto restart;
if (nlmclnt_reclaim(host, fl) != 0)
continue;
list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
if (host->h_nsmstate != nsmstate) {
/* Argh! The server rebooted again! */
list_splice_init(&host->h_granted, &host->h_reclaim);
goto restart;
}
}
host->h_reclaiming = 0;
nlmclnt_finish_reclaim(host);
/* Now, wake up all processes that sleep on a blocked lock */
list_for_each_entry(block, &nlm_blocked, b_list) {
......
......@@ -508,7 +508,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
}
block = nlmclnt_prepare_block(host, fl);
again:
for(;;) {
/* Reboot protection */
fl->fl_u.nfs_fl.state = host->h_state;
status = nlmclnt_call(req, NLMPROC_LOCK);
if (status < 0)
goto out_unblock;
......@@ -531,10 +534,16 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
}
if (resp->status == NLM_LCK_GRANTED) {
fl->fl_u.nfs_fl.state = host->h_state;
down_read(&host->h_rwsem);
/* Check whether or not the server has rebooted */
if (fl->fl_u.nfs_fl.state != host->h_state) {
up_read(&host->h_rwsem);
goto again;
}
fl->fl_flags |= FL_SLEEP;
/* Ensure the resulting lock will get added to granted list */
do_vfs_lock(fl);
up_read(&host->h_rwsem);
}
status = nlm_stat_to_errno(resp->status);
out_unblock:
......@@ -596,6 +605,7 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl)
static int
nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
{
struct nlm_host *host = req->a_host;
struct nlm_res *resp = &req->a_res;
int status;
......@@ -604,7 +614,9 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
* request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
* case, we want to unlock.
*/
down_read(&host->h_rwsem);
do_vfs_lock(fl);
up_read(&host->h_rwsem);
if (req->a_flags & RPC_TASK_ASYNC)
return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
......
......@@ -112,11 +112,12 @@ nlm_lookup_host(int server, struct sockaddr_in *sin,
host->h_version = version;
host->h_proto = proto;
host->h_rpcclnt = NULL;
init_MUTEX(&host->h_sema);
mutex_init(&host->h_mutex);
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
host->h_expires = jiffies + NLM_HOST_EXPIRE;
atomic_set(&host->h_count, 1);
init_waitqueue_head(&host->h_gracewait);
init_rwsem(&host->h_rwsem);
host->h_state = 0; /* pseudo NSM state */
host->h_nsmstate = 0; /* real NSM state */
host->h_server = server;
......@@ -172,7 +173,7 @@ nlm_bind_host(struct nlm_host *host)
(unsigned)ntohl(host->h_addr.sin_addr.s_addr));
/* Lock host handle */
down(&host->h_sema);
mutex_lock(&host->h_mutex);
/* If we've already created an RPC client, check whether
* RPC rebind is required
......@@ -204,12 +205,12 @@ nlm_bind_host(struct nlm_host *host)
host->h_rpcclnt = clnt;
}
up(&host->h_sema);
mutex_unlock(&host->h_mutex);
return clnt;
forgetit:
printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
up(&host->h_sema);
mutex_unlock(&host->h_mutex);
return NULL;
}
......
......@@ -585,8 +585,8 @@ static int do_umount(struct vfsmount *mnt, int flags)
*/
lock_kernel();
if ((flags & MNT_FORCE) && sb->s_op->umount_begin)
sb->s_op->umount_begin(sb);
if (sb->s_op->umount_begin)
sb->s_op->umount_begin(mnt, flags);
unlock_kernel();
/*
......@@ -1171,6 +1171,40 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts,
}
}
/*
* go through the vfsmounts we've just consigned to the graveyard to
* - check that they're still dead
* - delete the vfsmount from the appropriate namespace under lock
* - dispose of the corpse
*/
static void expire_mount_list(struct list_head *graveyard, struct list_head *mounts)
{
struct namespace *namespace;
struct vfsmount *mnt;
while (!list_empty(graveyard)) {
LIST_HEAD(umounts);
mnt = list_entry(graveyard->next, struct vfsmount, mnt_expire);
list_del_init(&mnt->mnt_expire);
/* don't do anything if the namespace is dead - all the
* vfsmounts from it are going away anyway */
namespace = mnt->mnt_namespace;
if (!namespace || !namespace->root)
continue;
get_namespace(namespace);
spin_unlock(&vfsmount_lock);
down_write(&namespace_sem);
expire_mount(mnt, mounts, &umounts);
up_write(&namespace_sem);
release_mounts(&umounts);
mntput(mnt);
put_namespace(namespace);
spin_lock(&vfsmount_lock);
}
}
/*
* process a list of expirable mountpoints with the intent of discarding any
* mountpoints that aren't in use and haven't been touched since last we came
......@@ -1178,7 +1212,6 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts,
*/
void mark_mounts_for_expiry(struct list_head *mounts)
{
struct namespace *namespace;
struct vfsmount *mnt, *next;
LIST_HEAD(graveyard);
......@@ -1202,38 +1235,79 @@ void mark_mounts_for_expiry(struct list_head *mounts)
list_move(&mnt->mnt_expire, &graveyard);
}
/*
* go through the vfsmounts we've just consigned to the graveyard to
* - check that they're still dead
* - delete the vfsmount from the appropriate namespace under lock
* - dispose of the corpse
*/
while (!list_empty(&graveyard)) {
LIST_HEAD(umounts);
mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire);
list_del_init(&mnt->mnt_expire);
expire_mount_list(&graveyard, mounts);
/* don't do anything if the namespace is dead - all the
* vfsmounts from it are going away anyway */
namespace = mnt->mnt_namespace;
if (!namespace || !namespace->root)
spin_unlock(&vfsmount_lock);
}
EXPORT_SYMBOL_GPL(mark_mounts_for_expiry);
/*
* Ripoff of 'select_parent()'
*
* search the list of submounts for a given mountpoint, and move any
* shrinkable submounts to the 'graveyard' list.
*/
static int select_submounts(struct vfsmount *parent, struct list_head *graveyard)
{
struct vfsmount *this_parent = parent;
struct list_head *next;
int found = 0;
repeat:
next = this_parent->mnt_mounts.next;
resume:
while (next != &this_parent->mnt_mounts) {
struct list_head *tmp = next;
struct vfsmount *mnt = list_entry(tmp, struct vfsmount, mnt_child);
next = tmp->next;
if (!(mnt->mnt_flags & MNT_SHRINKABLE))
continue;
get_namespace(namespace);
/*
* Descend a level if the d_mounts list is non-empty.
*/
if (!list_empty(&mnt->mnt_mounts)) {
this_parent = mnt;
goto repeat;
}
spin_unlock(&vfsmount_lock);
down_write(&namespace_sem);
expire_mount(mnt, mounts, &umounts);
up_write(&namespace_sem);
release_mounts(&umounts);
mntput(mnt);
put_namespace(namespace);
spin_lock(&vfsmount_lock);
if (!propagate_mount_busy(mnt, 1)) {
mntget(mnt);
list_move_tail(&mnt->mnt_expire, graveyard);
found++;
}
}
/*
* All done at this level ... ascend and resume the search
*/
if (this_parent != parent) {
next = this_parent->mnt_child.next;
this_parent = this_parent->mnt_parent;
goto resume;
}
return found;
}
/*
* process a list of expirable mountpoints with the intent of discarding any
* submounts of a specific parent mountpoint
*/
void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts)
{
LIST_HEAD(graveyard);
int found;
spin_lock(&vfsmount_lock);
/* extract submounts of 'mountpoint' from the expiration list */
while ((found = select_submounts(mountpoint, &graveyard)) != 0)
expire_mount_list(&graveyard, mounts);
spin_unlock(&vfsmount_lock);
}
EXPORT_SYMBOL_GPL(mark_mounts_for_expiry);
EXPORT_SYMBOL_GPL(shrink_submounts);
/*
* Some copy_from_user() implementations do not return the exact number of
......
......@@ -4,14 +4,16 @@
obj-$(CONFIG_NFS_FS) += nfs.o
nfs-y := dir.o file.o inode.o nfs2xdr.o pagelist.o \
proc.o read.o symlink.o unlink.o write.o
nfs-y := dir.o file.o inode.o super.o nfs2xdr.o pagelist.o \
proc.o read.o symlink.o unlink.o write.o \
namespace.o
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
delegation.o idmap.o \
callback.o callback_xdr.o callback_proc.o
callback.o callback_xdr.o callback_proc.o \
nfs4namespace.o
nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
nfs-$(CONFIG_SYSCTL) += sysctl.o
nfs-objs := $(nfs-y)
......@@ -182,8 +182,6 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp)
/*
* Define NFS4 callback program
*/
extern struct svc_version nfs4_callback_version1;
static struct svc_version *nfs4_callback_version[] = {
[1] = &nfs4_callback_version1,
};
......
......@@ -202,7 +202,7 @@ static unsigned decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xd
status = decode_fh(xdr, &args->fh);
out:
dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
return 0;
return status;
}
static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
......
......@@ -528,7 +528,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
lock_kernel();
res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
res = nfs_revalidate_mapping(inode, filp->f_mapping);
if (res < 0) {
unlock_kernel();
return res;
......@@ -868,6 +868,17 @@ int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
return (nd->intent.open.flags & O_EXCL) != 0;
}
static inline int nfs_reval_fsid(struct inode *dir,
struct nfs_fh *fh, struct nfs_fattr *fattr)
{
struct nfs_server *server = NFS_SERVER(dir);
if (!nfs_fsid_equal(&server->fsid, &fattr->fsid))
/* Revalidate fsid on root dir */
return __nfs_revalidate_inode(server, dir->i_sb->s_root->d_inode);
return 0;
}
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
{
struct dentry *res;
......@@ -900,6 +911,11 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
res = ERR_PTR(error);
goto out_unlock;
}
error = nfs_reval_fsid(dir, &fhandle, &fattr);
if (error < 0) {
res = ERR_PTR(error);
goto out_unlock;
}
inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);
res = (struct dentry *)inode;
if (IS_ERR(res))
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment