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 ...
This commit is contained in:
commit
1d77062b14
Documentation/filesystems
drivers/usb/core
fs
9p
afs
binfmt_misc.ccifs
configfs
debugfs
fuse
libfs.clockd
namespace.cnfs
Makefilecallback.ccallback_xdr.cdir.cdirect.cfile.cidmap.cinode.cinternal.hnamespace.cnfs2xdr.cnfs3acl.cnfs3proc.cnfs3xdr.cnfs4_fs.hnfs4namespace.cnfs4proc.cnfs4xdr.cpagelist.cproc.cread.csuper.csymlink.csysctl.cwrite.c
super.cinclude/linux
mm
net/sunrpc
security
|
@ -19,7 +19,7 @@ following procedure:
|
||||||
|
|
||||||
(2) Have the follow_link() op do the following steps:
|
(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.
|
superblock and gain a vfsmount structure representing it.
|
||||||
|
|
||||||
(b) Copy the nameidata provided as an argument and substitute the dentry
|
(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;
|
ignore_mount = 1;
|
||||||
|
|
||||||
/* create the devices special file */
|
/* 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) {
|
if (retval) {
|
||||||
err ("Unable to get usbfs mount");
|
err ("Unable to get usbfs mount");
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
|
@ -256,11 +256,12 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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 = {
|
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 */
|
/* try and do the mount */
|
||||||
kdebug("--- attempting mount %s -o %s ---", devname, options);
|
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);
|
kdebug("--- mount result %p ---", mnt);
|
||||||
|
|
||||||
free_page((unsigned long) devname);
|
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 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,
|
.owner = THIS_MODULE,
|
||||||
.name = "afs",
|
.name = "afs",
|
||||||
.get_sb = afs_get_sb,
|
.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;
|
return sb->s_fs_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern struct file_system_type afs_fs_type;
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
#endif /* _LINUX_AFS_SUPER_H */
|
#endif /* _LINUX_AFS_SUPER_H */
|
||||||
|
|
|
@ -55,6 +55,7 @@ typedef struct {
|
||||||
} Node;
|
} Node;
|
||||||
|
|
||||||
static DEFINE_RWLOCK(entries_lock);
|
static DEFINE_RWLOCK(entries_lock);
|
||||||
|
static struct file_system_type bm_fs_type;
|
||||||
static struct vfsmount *bm_mnt;
|
static struct vfsmount *bm_mnt;
|
||||||
static int entry_count;
|
static int entry_count;
|
||||||
|
|
||||||
|
@ -637,7 +638,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
|
||||||
if (!inode)
|
if (!inode)
|
||||||
goto out2;
|
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) {
|
if (err) {
|
||||||
iput(inode);
|
iput(inode);
|
||||||
inode = NULL;
|
inode = NULL;
|
||||||
|
|
|
@ -403,12 +403,14 @@ static struct quotactl_ops cifs_quotactl_ops = {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
#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 cifs_sb_info *cifs_sb;
|
||||||
struct cifsTconInfo * tcon;
|
struct cifsTconInfo * tcon;
|
||||||
|
|
||||||
cifs_sb = CIFS_SB(sblock);
|
if (!(flags & MNT_FORCE))
|
||||||
|
return;
|
||||||
|
cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
|
||||||
if(cifs_sb == NULL)
|
if(cifs_sb == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ static struct file_system_type configfs_fs_type = {
|
||||||
|
|
||||||
int configfs_pin_fs(void)
|
int configfs_pin_fs(void)
|
||||||
{
|
{
|
||||||
return simple_pin_fs("configfs", &configfs_mount,
|
return simple_pin_fs(&configfs_fs_type, &configfs_mount,
|
||||||
&configfs_mnt_count);
|
&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);
|
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)
|
if (error)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
|
|
@ -198,9 +198,10 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
|
||||||
return inode;
|
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)
|
static void fuse_put_super(struct super_block *sb)
|
||||||
|
|
|
@ -424,13 +424,13 @@ out:
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(pin_fs_lock);
|
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;
|
struct vfsmount *mnt = NULL;
|
||||||
spin_lock(&pin_fs_lock);
|
spin_lock(&pin_fs_lock);
|
||||||
if (unlikely(!*mount)) {
|
if (unlikely(!*mount)) {
|
||||||
spin_unlock(&pin_fs_lock);
|
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))
|
if (IS_ERR(mnt))
|
||||||
return PTR_ERR(mnt);
|
return PTR_ERR(mnt);
|
||||||
spin_lock(&pin_fs_lock);
|
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,
|
* 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.
|
* that we mark locks for reclaiming, and that we bump the pseudo NSM state.
|
||||||
*/
|
*/
|
||||||
static inline
|
static void nlmclnt_prepare_reclaim(struct nlm_host *host)
|
||||||
void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
|
|
||||||
{
|
{
|
||||||
|
down_write(&host->h_rwsem);
|
||||||
host->h_monitored = 0;
|
host->h_monitored = 0;
|
||||||
host->h_nsmstate = newstate;
|
|
||||||
host->h_state++;
|
host->h_state++;
|
||||||
host->h_nextrebind = 0;
|
host->h_nextrebind = 0;
|
||||||
nlm_rebind_host(host);
|
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);
|
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
|
* Reclaim all locks on server host. We do this by spawning a separate
|
||||||
* reclaimer thread.
|
* reclaimer thread.
|
||||||
|
@ -171,12 +177,10 @@ void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
|
||||||
void
|
void
|
||||||
nlmclnt_recovery(struct nlm_host *host, u32 newstate)
|
nlmclnt_recovery(struct nlm_host *host, u32 newstate)
|
||||||
{
|
{
|
||||||
if (host->h_reclaiming++) {
|
if (host->h_nsmstate == newstate)
|
||||||
if (host->h_nsmstate == newstate)
|
return;
|
||||||
return;
|
host->h_nsmstate = newstate;
|
||||||
nlmclnt_prepare_reclaim(host, newstate);
|
if (!host->h_reclaiming++) {
|
||||||
} else {
|
|
||||||
nlmclnt_prepare_reclaim(host, newstate);
|
|
||||||
nlm_get_host(host);
|
nlm_get_host(host);
|
||||||
__module_get(THIS_MODULE);
|
__module_get(THIS_MODULE);
|
||||||
if (kernel_thread(reclaimer, host, CLONE_KERNEL) < 0)
|
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_host *host = (struct nlm_host *) ptr;
|
||||||
struct nlm_wait *block;
|
struct nlm_wait *block;
|
||||||
struct file_lock *fl, *next;
|
struct file_lock *fl, *next;
|
||||||
|
u32 nsmstate;
|
||||||
|
|
||||||
daemonize("%s-reclaim", host->h_name);
|
daemonize("%s-reclaim", host->h_name);
|
||||||
allow_signal(SIGKILL);
|
allow_signal(SIGKILL);
|
||||||
|
@ -199,19 +204,25 @@ reclaimer(void *ptr)
|
||||||
lock_kernel();
|
lock_kernel();
|
||||||
lockd_up();
|
lockd_up();
|
||||||
|
|
||||||
|
nlmclnt_prepare_reclaim(host);
|
||||||
/* First, reclaim all locks that have been marked. */
|
/* First, reclaim all locks that have been marked. */
|
||||||
restart:
|
restart:
|
||||||
|
nsmstate = host->h_nsmstate;
|
||||||
list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
|
list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
|
||||||
list_del_init(&fl->fl_u.nfs_fl.list);
|
list_del_init(&fl->fl_u.nfs_fl.list);
|
||||||
|
|
||||||
if (signalled())
|
if (signalled())
|
||||||
continue;
|
continue;
|
||||||
if (nlmclnt_reclaim(host, fl) == 0)
|
if (nlmclnt_reclaim(host, fl) != 0)
|
||||||
list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
|
continue;
|
||||||
goto restart;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
nlmclnt_finish_reclaim(host);
|
||||||
host->h_reclaiming = 0;
|
|
||||||
|
|
||||||
/* Now, wake up all processes that sleep on a blocked lock */
|
/* Now, wake up all processes that sleep on a blocked lock */
|
||||||
list_for_each_entry(block, &nlm_blocked, b_list) {
|
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);
|
block = nlmclnt_prepare_block(host, fl);
|
||||||
|
again:
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
/* Reboot protection */
|
||||||
|
fl->fl_u.nfs_fl.state = host->h_state;
|
||||||
status = nlmclnt_call(req, NLMPROC_LOCK);
|
status = nlmclnt_call(req, NLMPROC_LOCK);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
goto out_unblock;
|
goto out_unblock;
|
||||||
|
@ -531,10 +534,16 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resp->status == NLM_LCK_GRANTED) {
|
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;
|
fl->fl_flags |= FL_SLEEP;
|
||||||
/* Ensure the resulting lock will get added to granted list */
|
/* Ensure the resulting lock will get added to granted list */
|
||||||
do_vfs_lock(fl);
|
do_vfs_lock(fl);
|
||||||
|
up_read(&host->h_rwsem);
|
||||||
}
|
}
|
||||||
status = nlm_stat_to_errno(resp->status);
|
status = nlm_stat_to_errno(resp->status);
|
||||||
out_unblock:
|
out_unblock:
|
||||||
|
@ -596,6 +605,7 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl)
|
||||||
static int
|
static int
|
||||||
nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
|
nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
|
||||||
{
|
{
|
||||||
|
struct nlm_host *host = req->a_host;
|
||||||
struct nlm_res *resp = &req->a_res;
|
struct nlm_res *resp = &req->a_res;
|
||||||
int status;
|
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
|
* request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
|
||||||
* case, we want to unlock.
|
* case, we want to unlock.
|
||||||
*/
|
*/
|
||||||
|
down_read(&host->h_rwsem);
|
||||||
do_vfs_lock(fl);
|
do_vfs_lock(fl);
|
||||||
|
up_read(&host->h_rwsem);
|
||||||
|
|
||||||
if (req->a_flags & RPC_TASK_ASYNC)
|
if (req->a_flags & RPC_TASK_ASYNC)
|
||||||
return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
|
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_version = version;
|
||||||
host->h_proto = proto;
|
host->h_proto = proto;
|
||||||
host->h_rpcclnt = NULL;
|
host->h_rpcclnt = NULL;
|
||||||
init_MUTEX(&host->h_sema);
|
mutex_init(&host->h_mutex);
|
||||||
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
|
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
|
||||||
host->h_expires = jiffies + NLM_HOST_EXPIRE;
|
host->h_expires = jiffies + NLM_HOST_EXPIRE;
|
||||||
atomic_set(&host->h_count, 1);
|
atomic_set(&host->h_count, 1);
|
||||||
init_waitqueue_head(&host->h_gracewait);
|
init_waitqueue_head(&host->h_gracewait);
|
||||||
|
init_rwsem(&host->h_rwsem);
|
||||||
host->h_state = 0; /* pseudo NSM state */
|
host->h_state = 0; /* pseudo NSM state */
|
||||||
host->h_nsmstate = 0; /* real NSM state */
|
host->h_nsmstate = 0; /* real NSM state */
|
||||||
host->h_server = server;
|
host->h_server = server;
|
||||||
|
@ -172,7 +173,7 @@ nlm_bind_host(struct nlm_host *host)
|
||||||
(unsigned)ntohl(host->h_addr.sin_addr.s_addr));
|
(unsigned)ntohl(host->h_addr.sin_addr.s_addr));
|
||||||
|
|
||||||
/* Lock host handle */
|
/* Lock host handle */
|
||||||
down(&host->h_sema);
|
mutex_lock(&host->h_mutex);
|
||||||
|
|
||||||
/* If we've already created an RPC client, check whether
|
/* If we've already created an RPC client, check whether
|
||||||
* RPC rebind is required
|
* RPC rebind is required
|
||||||
|
@ -204,12 +205,12 @@ nlm_bind_host(struct nlm_host *host)
|
||||||
host->h_rpcclnt = clnt;
|
host->h_rpcclnt = clnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
up(&host->h_sema);
|
mutex_unlock(&host->h_mutex);
|
||||||
return clnt;
|
return clnt;
|
||||||
|
|
||||||
forgetit:
|
forgetit:
|
||||||
printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
|
printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
|
||||||
up(&host->h_sema);
|
mutex_unlock(&host->h_mutex);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
134
fs/namespace.c
134
fs/namespace.c
|
@ -585,8 +585,8 @@ static int do_umount(struct vfsmount *mnt, int flags)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
lock_kernel();
|
lock_kernel();
|
||||||
if ((flags & MNT_FORCE) && sb->s_op->umount_begin)
|
if (sb->s_op->umount_begin)
|
||||||
sb->s_op->umount_begin(sb);
|
sb->s_op->umount_begin(mnt, flags);
|
||||||
unlock_kernel();
|
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
|
* 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
|
* 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)
|
void mark_mounts_for_expiry(struct list_head *mounts)
|
||||||
{
|
{
|
||||||
struct namespace *namespace;
|
|
||||||
struct vfsmount *mnt, *next;
|
struct vfsmount *mnt, *next;
|
||||||
LIST_HEAD(graveyard);
|
LIST_HEAD(graveyard);
|
||||||
|
|
||||||
|
@ -1202,39 +1235,80 @@ void mark_mounts_for_expiry(struct list_head *mounts)
|
||||||
list_move(&mnt->mnt_expire, &graveyard);
|
list_move(&mnt->mnt_expire, &graveyard);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
expire_mount_list(&graveyard, 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
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock(&vfsmount_lock);
|
spin_unlock(&vfsmount_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(mark_mounts_for_expiry);
|
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;
|
||||||
|
/*
|
||||||
|
* Descend a level if the d_mounts list is non-empty.
|
||||||
|
*/
|
||||||
|
if (!list_empty(&mnt->mnt_mounts)) {
|
||||||
|
this_parent = mnt;
|
||||||
|
goto repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(shrink_submounts);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some copy_from_user() implementations do not return the exact number of
|
* Some copy_from_user() implementations do not return the exact number of
|
||||||
* bytes remaining to copy on a fault. But copy_mount_options() requires that.
|
* bytes remaining to copy on a fault. But copy_mount_options() requires that.
|
||||||
|
|
|
@ -4,14 +4,16 @@
|
||||||
|
|
||||||
obj-$(CONFIG_NFS_FS) += nfs.o
|
obj-$(CONFIG_NFS_FS) += nfs.o
|
||||||
|
|
||||||
nfs-y := dir.o file.o inode.o nfs2xdr.o pagelist.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
|
proc.o read.o symlink.o unlink.o write.o \
|
||||||
|
namespace.o
|
||||||
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
|
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
|
||||||
nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
|
nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
|
||||||
nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
|
nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
|
||||||
nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
|
nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
|
||||||
delegation.o idmap.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_NFS_DIRECTIO) += direct.o
|
||||||
nfs-$(CONFIG_SYSCTL) += sysctl.o
|
nfs-$(CONFIG_SYSCTL) += sysctl.o
|
||||||
nfs-objs := $(nfs-y)
|
nfs-objs := $(nfs-y)
|
||||||
|
|
|
@ -182,8 +182,6 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp)
|
||||||
/*
|
/*
|
||||||
* Define NFS4 callback program
|
* Define NFS4 callback program
|
||||||
*/
|
*/
|
||||||
extern struct svc_version nfs4_callback_version1;
|
|
||||||
|
|
||||||
static struct svc_version *nfs4_callback_version[] = {
|
static struct svc_version *nfs4_callback_version[] = {
|
||||||
[1] = &nfs4_callback_version1,
|
[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);
|
status = decode_fh(xdr, &args->fh);
|
||||||
out:
|
out:
|
||||||
dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
|
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)
|
static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
|
||||||
|
|
18
fs/nfs/dir.c
18
fs/nfs/dir.c
|
@ -528,7 +528,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
|
|
||||||
lock_kernel();
|
lock_kernel();
|
||||||
|
|
||||||
res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
|
res = nfs_revalidate_mapping(inode, filp->f_mapping);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
unlock_kernel();
|
unlock_kernel();
|
||||||
return res;
|
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;
|
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)
|
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
|
||||||
{
|
{
|
||||||
struct dentry *res;
|
struct dentry *res;
|
||||||
|
@ -900,6 +911,11 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
|
||||||
res = ERR_PTR(error);
|
res = ERR_PTR(error);
|
||||||
goto out_unlock;
|
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);
|
inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);
|
||||||
res = (struct dentry *)inode;
|
res = (struct dentry *)inode;
|
||||||
if (IS_ERR(res))
|
if (IS_ERR(res))
|
||||||
|
|
|
@ -892,7 +892,7 @@ out:
|
||||||
* nfs_init_directcache - create a slab cache for nfs_direct_req structures
|
* nfs_init_directcache - create a slab cache for nfs_direct_req structures
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int nfs_init_directcache(void)
|
int __init nfs_init_directcache(void)
|
||||||
{
|
{
|
||||||
nfs_direct_cachep = kmem_cache_create("nfs_direct_cache",
|
nfs_direct_cachep = kmem_cache_create("nfs_direct_cache",
|
||||||
sizeof(struct nfs_direct_req),
|
sizeof(struct nfs_direct_req),
|
||||||
|
@ -906,10 +906,10 @@ int nfs_init_directcache(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nfs_init_directcache - destroy the slab cache for nfs_direct_req structures
|
* nfs_destroy_directcache - destroy the slab cache for nfs_direct_req structures
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void nfs_destroy_directcache(void)
|
void __exit nfs_destroy_directcache(void)
|
||||||
{
|
{
|
||||||
if (kmem_cache_destroy(nfs_direct_cachep))
|
if (kmem_cache_destroy(nfs_direct_cachep))
|
||||||
printk(KERN_INFO "nfs_direct_cache: not all structures were freed\n");
|
printk(KERN_INFO "nfs_direct_cache: not all structures were freed\n");
|
||||||
|
|
|
@ -126,23 +126,6 @@ nfs_file_release(struct inode *inode, struct file *filp)
|
||||||
return NFS_PROTO(inode)->file_release(inode, filp);
|
return NFS_PROTO(inode)->file_release(inode, filp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* nfs_revalidate_file - Revalidate the page cache & related metadata
|
|
||||||
* @inode - pointer to inode struct
|
|
||||||
* @file - pointer to file
|
|
||||||
*/
|
|
||||||
static int nfs_revalidate_file(struct inode *inode, struct file *filp)
|
|
||||||
{
|
|
||||||
struct nfs_inode *nfsi = NFS_I(inode);
|
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
if ((nfsi->cache_validity & (NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_ATTR))
|
|
||||||
|| nfs_attribute_timeout(inode))
|
|
||||||
retval = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
|
|
||||||
nfs_revalidate_mapping(inode, filp->f_mapping);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nfs_revalidate_size - Revalidate the file size
|
* nfs_revalidate_size - Revalidate the file size
|
||||||
* @inode - pointer to inode struct
|
* @inode - pointer to inode struct
|
||||||
|
@ -228,7 +211,7 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos)
|
||||||
dentry->d_parent->d_name.name, dentry->d_name.name,
|
dentry->d_parent->d_name.name, dentry->d_name.name,
|
||||||
(unsigned long) count, (unsigned long) pos);
|
(unsigned long) count, (unsigned long) pos);
|
||||||
|
|
||||||
result = nfs_revalidate_file(inode, iocb->ki_filp);
|
result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
|
||||||
nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, count);
|
nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, count);
|
||||||
if (!result)
|
if (!result)
|
||||||
result = generic_file_aio_read(iocb, buf, count, pos);
|
result = generic_file_aio_read(iocb, buf, count, pos);
|
||||||
|
@ -247,7 +230,7 @@ nfs_file_sendfile(struct file *filp, loff_t *ppos, size_t count,
|
||||||
dentry->d_parent->d_name.name, dentry->d_name.name,
|
dentry->d_parent->d_name.name, dentry->d_name.name,
|
||||||
(unsigned long) count, (unsigned long long) *ppos);
|
(unsigned long) count, (unsigned long long) *ppos);
|
||||||
|
|
||||||
res = nfs_revalidate_file(inode, filp);
|
res = nfs_revalidate_mapping(inode, filp->f_mapping);
|
||||||
if (!res)
|
if (!res)
|
||||||
res = generic_file_sendfile(filp, ppos, count, actor, target);
|
res = generic_file_sendfile(filp, ppos, count, actor, target);
|
||||||
return res;
|
return res;
|
||||||
|
@ -263,7 +246,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
|
||||||
dfprintk(VFS, "nfs: mmap(%s/%s)\n",
|
dfprintk(VFS, "nfs: mmap(%s/%s)\n",
|
||||||
dentry->d_parent->d_name.name, dentry->d_name.name);
|
dentry->d_parent->d_name.name, dentry->d_name.name);
|
||||||
|
|
||||||
status = nfs_revalidate_file(inode, file);
|
status = nfs_revalidate_mapping(inode, file->f_mapping);
|
||||||
if (!status)
|
if (!status)
|
||||||
status = generic_file_mmap(file, vma);
|
status = generic_file_mmap(file, vma);
|
||||||
return status;
|
return status;
|
||||||
|
@ -320,7 +303,11 @@ static int nfs_commit_write(struct file *file, struct page *page, unsigned offse
|
||||||
|
|
||||||
static void nfs_invalidate_page(struct page *page, unsigned long offset)
|
static void nfs_invalidate_page(struct page *page, unsigned long offset)
|
||||||
{
|
{
|
||||||
/* FIXME: we really should cancel any unstarted writes on this page */
|
struct inode *inode = page->mapping->host;
|
||||||
|
|
||||||
|
/* Cancel any unstarted writes on this page */
|
||||||
|
if (offset == 0)
|
||||||
|
nfs_sync_inode_wait(inode, page->index, 1, FLUSH_INVALIDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nfs_release_page(struct page *page, gfp_t gfp)
|
static int nfs_release_page(struct page *page, gfp_t gfp)
|
||||||
|
@ -373,7 +360,6 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t
|
||||||
if (result)
|
if (result)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
|
|
||||||
|
|
||||||
result = count;
|
result = count;
|
||||||
if (!count)
|
if (!count)
|
||||||
|
|
|
@ -47,7 +47,6 @@
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/sunrpc/rpc_pipe_fs.h>
|
#include <linux/sunrpc/rpc_pipe_fs.h>
|
||||||
|
|
||||||
#include <linux/nfs_fs_sb.h>
|
|
||||||
#include <linux/nfs_fs.h>
|
#include <linux/nfs_fs.h>
|
||||||
|
|
||||||
#include <linux/nfs_idmap.h>
|
#include <linux/nfs_idmap.h>
|
||||||
|
|
1317
fs/nfs/inode.c
1317
fs/nfs/inode.c
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,186 @@
|
||||||
|
/*
|
||||||
|
* NFS internal definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/mount.h>
|
||||||
|
|
||||||
|
struct nfs_clone_mount {
|
||||||
|
const struct super_block *sb;
|
||||||
|
const struct dentry *dentry;
|
||||||
|
struct nfs_fh *fh;
|
||||||
|
struct nfs_fattr *fattr;
|
||||||
|
char *hostname;
|
||||||
|
char *mnt_path;
|
||||||
|
struct sockaddr_in *addr;
|
||||||
|
rpc_authflavor_t authflavor;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* namespace-nfs4.c */
|
||||||
|
#ifdef CONFIG_NFS_V4
|
||||||
|
extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry);
|
||||||
|
#else
|
||||||
|
static inline
|
||||||
|
struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry)
|
||||||
|
{
|
||||||
|
return ERR_PTR(-ENOENT);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* callback_xdr.c */
|
||||||
|
extern struct svc_version nfs4_callback_version1;
|
||||||
|
|
||||||
|
/* pagelist.c */
|
||||||
|
extern int __init nfs_init_nfspagecache(void);
|
||||||
|
extern void __exit nfs_destroy_nfspagecache(void);
|
||||||
|
extern int __init nfs_init_readpagecache(void);
|
||||||
|
extern void __exit nfs_destroy_readpagecache(void);
|
||||||
|
extern int __init nfs_init_writepagecache(void);
|
||||||
|
extern void __exit nfs_destroy_writepagecache(void);
|
||||||
|
|
||||||
|
#ifdef CONFIG_NFS_DIRECTIO
|
||||||
|
extern int __init nfs_init_directcache(void);
|
||||||
|
extern void __exit nfs_destroy_directcache(void);
|
||||||
|
#else
|
||||||
|
#define nfs_init_directcache() (0)
|
||||||
|
#define nfs_destroy_directcache() do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* nfs2xdr.c */
|
||||||
|
extern struct rpc_procinfo nfs_procedures[];
|
||||||
|
extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
|
||||||
|
|
||||||
|
/* nfs3xdr.c */
|
||||||
|
extern struct rpc_procinfo nfs3_procedures[];
|
||||||
|
extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
|
||||||
|
|
||||||
|
/* nfs4xdr.c */
|
||||||
|
extern int nfs_stat_to_errno(int);
|
||||||
|
extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
|
||||||
|
|
||||||
|
/* nfs4proc.c */
|
||||||
|
#ifdef CONFIG_NFS_V4
|
||||||
|
extern struct rpc_procinfo nfs4_procedures[];
|
||||||
|
|
||||||
|
extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
|
||||||
|
struct nfs4_fs_locations *fs_locations,
|
||||||
|
struct page *page);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* inode.c */
|
||||||
|
extern struct inode *nfs_alloc_inode(struct super_block *sb);
|
||||||
|
extern void nfs_destroy_inode(struct inode *);
|
||||||
|
extern int nfs_write_inode(struct inode *,int);
|
||||||
|
extern void nfs_clear_inode(struct inode *);
|
||||||
|
#ifdef CONFIG_NFS_V4
|
||||||
|
extern void nfs4_clear_inode(struct inode *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* super.c */
|
||||||
|
extern struct file_system_type nfs_referral_nfs4_fs_type;
|
||||||
|
extern struct file_system_type clone_nfs_fs_type;
|
||||||
|
#ifdef CONFIG_NFS_V4
|
||||||
|
extern struct file_system_type clone_nfs4_fs_type;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_PROC_FS
|
||||||
|
extern struct rpc_stat nfs_rpcstat;
|
||||||
|
#endif
|
||||||
|
extern int __init register_nfs_fs(void);
|
||||||
|
extern void __exit unregister_nfs_fs(void);
|
||||||
|
|
||||||
|
/* namespace.c */
|
||||||
|
extern char *nfs_path(const char *base, const struct dentry *dentry,
|
||||||
|
char *buffer, ssize_t buflen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine the mount path as a string
|
||||||
|
*/
|
||||||
|
static inline char *
|
||||||
|
nfs4_path(const struct dentry *dentry, char *buffer, ssize_t buflen)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_NFS_V4
|
||||||
|
return nfs_path(NFS_SB(dentry->d_sb)->mnt_path, dentry, buffer, buflen);
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine the device name as a string
|
||||||
|
*/
|
||||||
|
static inline char *nfs_devname(const struct vfsmount *mnt_parent,
|
||||||
|
const struct dentry *dentry,
|
||||||
|
char *buffer, ssize_t buflen)
|
||||||
|
{
|
||||||
|
return nfs_path(mnt_parent->mnt_devname, dentry, buffer, buflen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine the actual block size (and log2 thereof)
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
unsigned long nfs_block_bits(unsigned long bsize, unsigned char *nrbitsp)
|
||||||
|
{
|
||||||
|
/* make sure blocksize is a power of two */
|
||||||
|
if ((bsize & (bsize - 1)) || nrbitsp) {
|
||||||
|
unsigned char nrbits;
|
||||||
|
|
||||||
|
for (nrbits = 31; nrbits && !(bsize & (1 << nrbits)); nrbits--)
|
||||||
|
;
|
||||||
|
bsize = 1 << nrbits;
|
||||||
|
if (nrbitsp)
|
||||||
|
*nrbitsp = nrbits;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the number of 512byte blocks used.
|
||||||
|
*/
|
||||||
|
static inline unsigned long nfs_calc_block_size(u64 tsize)
|
||||||
|
{
|
||||||
|
loff_t used = (tsize + 511) >> 9;
|
||||||
|
return (used > ULONG_MAX) ? ULONG_MAX : used;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute and set NFS server blocksize
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
unsigned long nfs_block_size(unsigned long bsize, unsigned char *nrbitsp)
|
||||||
|
{
|
||||||
|
if (bsize < NFS_MIN_FILE_IO_SIZE)
|
||||||
|
bsize = NFS_DEF_FILE_IO_SIZE;
|
||||||
|
else if (bsize >= NFS_MAX_FILE_IO_SIZE)
|
||||||
|
bsize = NFS_MAX_FILE_IO_SIZE;
|
||||||
|
|
||||||
|
return nfs_block_bits(bsize, nrbitsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine the maximum file size for a superblock
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
void nfs_super_set_maxbytes(struct super_block *sb, __u64 maxfilesize)
|
||||||
|
{
|
||||||
|
sb->s_maxbytes = (loff_t)maxfilesize;
|
||||||
|
if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0)
|
||||||
|
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the string represents a "valid" IPv4 address
|
||||||
|
*/
|
||||||
|
static inline int valid_ipaddr4(const char *buf)
|
||||||
|
{
|
||||||
|
int rc, count, in[4];
|
||||||
|
|
||||||
|
rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
|
||||||
|
if (rc != 4)
|
||||||
|
return -EINVAL;
|
||||||
|
for (count = 0; count < 4; count++) {
|
||||||
|
if (in[count] > 255)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,229 @@
|
||||||
|
/*
|
||||||
|
* linux/fs/nfs/namespace.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
|
||||||
|
*
|
||||||
|
* NFS namespace
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/config.h>
|
||||||
|
|
||||||
|
#include <linux/dcache.h>
|
||||||
|
#include <linux/mount.h>
|
||||||
|
#include <linux/namei.h>
|
||||||
|
#include <linux/nfs_fs.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/sunrpc/clnt.h>
|
||||||
|
#include <linux/vfs.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#define NFSDBG_FACILITY NFSDBG_VFS
|
||||||
|
|
||||||
|
static void nfs_expire_automounts(void *list);
|
||||||
|
|
||||||
|
LIST_HEAD(nfs_automount_list);
|
||||||
|
static DECLARE_WORK(nfs_automount_task, nfs_expire_automounts, &nfs_automount_list);
|
||||||
|
int nfs_mountpoint_expiry_timeout = 500 * HZ;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nfs_path - reconstruct the path given an arbitrary dentry
|
||||||
|
* @base - arbitrary string to prepend to the 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.
|
||||||
|
*
|
||||||
|
* This is mainly for use in figuring out the path on the
|
||||||
|
* server side when automounting on top of an existing partition.
|
||||||
|
*/
|
||||||
|
char *nfs_path(const char *base, const struct dentry *dentry,
|
||||||
|
char *buffer, ssize_t buflen)
|
||||||
|
{
|
||||||
|
char *end = buffer+buflen;
|
||||||
|
int namelen;
|
||||||
|
|
||||||
|
*--end = '\0';
|
||||||
|
buflen--;
|
||||||
|
spin_lock(&dcache_lock);
|
||||||
|
while (!IS_ROOT(dentry)) {
|
||||||
|
namelen = dentry->d_name.len;
|
||||||
|
buflen -= namelen + 1;
|
||||||
|
if (buflen < 0)
|
||||||
|
goto Elong;
|
||||||
|
end -= namelen;
|
||||||
|
memcpy(end, dentry->d_name.name, namelen);
|
||||||
|
*--end = '/';
|
||||||
|
dentry = dentry->d_parent;
|
||||||
|
}
|
||||||
|
spin_unlock(&dcache_lock);
|
||||||
|
namelen = strlen(base);
|
||||||
|
/* Strip off excess slashes in base string */
|
||||||
|
while (namelen > 0 && base[namelen - 1] == '/')
|
||||||
|
namelen--;
|
||||||
|
buflen -= namelen;
|
||||||
|
if (buflen < 0)
|
||||||
|
goto Elong;
|
||||||
|
end -= namelen;
|
||||||
|
memcpy(end, base, namelen);
|
||||||
|
return end;
|
||||||
|
Elong:
|
||||||
|
return ERR_PTR(-ENAMETOOLONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nfs_follow_mountpoint - handle crossing a mountpoint on the server
|
||||||
|
* @dentry - dentry of mountpoint
|
||||||
|
* @nd - nameidata info
|
||||||
|
*
|
||||||
|
* When we encounter a mountpoint on the server, we want to set up
|
||||||
|
* a mountpoint on the client too, to prevent inode numbers from
|
||||||
|
* colliding, and to allow "df" to work properly.
|
||||||
|
* On NFSv4, we also want to allow for the fact that different
|
||||||
|
* filesystems may be migrated to different servers in a failover
|
||||||
|
* situation, and that different filesystems may want to use
|
||||||
|
* different security flavours.
|
||||||
|
*/
|
||||||
|
static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
|
||||||
|
{
|
||||||
|
struct vfsmount *mnt;
|
||||||
|
struct nfs_server *server = NFS_SERVER(dentry->d_inode);
|
||||||
|
struct dentry *parent;
|
||||||
|
struct nfs_fh fh;
|
||||||
|
struct nfs_fattr fattr;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
BUG_ON(IS_ROOT(dentry));
|
||||||
|
dprintk("%s: enter\n", __FUNCTION__);
|
||||||
|
dput(nd->dentry);
|
||||||
|
nd->dentry = dget(dentry);
|
||||||
|
if (d_mountpoint(nd->dentry))
|
||||||
|
goto out_follow;
|
||||||
|
/* Look it up again */
|
||||||
|
parent = dget_parent(nd->dentry);
|
||||||
|
err = server->rpc_ops->lookup(parent->d_inode, &nd->dentry->d_name, &fh, &fattr);
|
||||||
|
dput(parent);
|
||||||
|
if (err != 0)
|
||||||
|
goto out_err;
|
||||||
|
|
||||||
|
if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL)
|
||||||
|
mnt = nfs_do_refmount(nd->mnt, nd->dentry);
|
||||||
|
else
|
||||||
|
mnt = nfs_do_submount(nd->mnt, nd->dentry, &fh, &fattr);
|
||||||
|
err = PTR_ERR(mnt);
|
||||||
|
if (IS_ERR(mnt))
|
||||||
|
goto out_err;
|
||||||
|
|
||||||
|
mntget(mnt);
|
||||||
|
err = do_add_mount(mnt, nd, nd->mnt->mnt_flags|MNT_SHRINKABLE, &nfs_automount_list);
|
||||||
|
if (err < 0) {
|
||||||
|
mntput(mnt);
|
||||||
|
if (err == -EBUSY)
|
||||||
|
goto out_follow;
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
mntput(nd->mnt);
|
||||||
|
dput(nd->dentry);
|
||||||
|
nd->mnt = mnt;
|
||||||
|
nd->dentry = dget(mnt->mnt_root);
|
||||||
|
schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
|
||||||
|
out:
|
||||||
|
dprintk("%s: done, returned %d\n", __FUNCTION__, err);
|
||||||
|
return ERR_PTR(err);
|
||||||
|
out_err:
|
||||||
|
path_release(nd);
|
||||||
|
goto out;
|
||||||
|
out_follow:
|
||||||
|
while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
|
||||||
|
;
|
||||||
|
err = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct inode_operations nfs_mountpoint_inode_operations = {
|
||||||
|
.follow_link = nfs_follow_mountpoint,
|
||||||
|
.getattr = nfs_getattr,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct inode_operations nfs_referral_inode_operations = {
|
||||||
|
.follow_link = nfs_follow_mountpoint,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void nfs_expire_automounts(void *data)
|
||||||
|
{
|
||||||
|
struct list_head *list = (struct list_head *)data;
|
||||||
|
|
||||||
|
mark_mounts_for_expiry(list);
|
||||||
|
if (!list_empty(list))
|
||||||
|
schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfs_release_automount_timer(void)
|
||||||
|
{
|
||||||
|
if (list_empty(&nfs_automount_list)) {
|
||||||
|
cancel_delayed_work(&nfs_automount_task);
|
||||||
|
flush_scheduled_work();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clone a mountpoint of the appropriate type
|
||||||
|
*/
|
||||||
|
static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, char *devname,
|
||||||
|
struct nfs_clone_mount *mountdata)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_NFS_V4
|
||||||
|
struct vfsmount *mnt = NULL;
|
||||||
|
switch (server->rpc_ops->version) {
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
mnt = vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
mnt = vfs_kern_mount(&clone_nfs4_fs_type, 0, devname, mountdata);
|
||||||
|
}
|
||||||
|
return mnt;
|
||||||
|
#else
|
||||||
|
return vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
|
||||||
|
const struct dentry *dentry, struct nfs_fh *fh,
|
||||||
|
struct nfs_fattr *fattr)
|
||||||
|
{
|
||||||
|
struct nfs_clone_mount mountdata = {
|
||||||
|
.sb = mnt_parent->mnt_sb,
|
||||||
|
.dentry = dentry,
|
||||||
|
.fh = fh,
|
||||||
|
.fattr = fattr,
|
||||||
|
};
|
||||||
|
struct vfsmount *mnt = ERR_PTR(-ENOMEM);
|
||||||
|
char *page = (char *) __get_free_page(GFP_USER);
|
||||||
|
char *devname;
|
||||||
|
|
||||||
|
dprintk("%s: submounting on %s/%s\n", __FUNCTION__,
|
||||||
|
dentry->d_parent->d_name.name,
|
||||||
|
dentry->d_name.name);
|
||||||
|
if (page == NULL)
|
||||||
|
goto out;
|
||||||
|
devname = nfs_devname(mnt_parent, 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);
|
||||||
|
free_page:
|
||||||
|
free_page((unsigned long)page);
|
||||||
|
out:
|
||||||
|
dprintk("%s: done\n", __FUNCTION__);
|
||||||
|
return mnt;
|
||||||
|
}
|
|
@ -23,12 +23,13 @@
|
||||||
#include <linux/nfs.h>
|
#include <linux/nfs.h>
|
||||||
#include <linux/nfs2.h>
|
#include <linux/nfs2.h>
|
||||||
#include <linux/nfs_fs.h>
|
#include <linux/nfs_fs.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
#define NFSDBG_FACILITY NFSDBG_XDR
|
#define NFSDBG_FACILITY NFSDBG_XDR
|
||||||
/* #define NFS_PARANOIA 1 */
|
/* #define NFS_PARANOIA 1 */
|
||||||
|
|
||||||
extern int nfs_stat_to_errno(int stat);
|
|
||||||
|
|
||||||
/* Mapping from NFS error code to "errno" error code. */
|
/* Mapping from NFS error code to "errno" error code. */
|
||||||
#define errno_NFSERR_IO EIO
|
#define errno_NFSERR_IO EIO
|
||||||
|
|
||||||
|
@ -131,7 +132,8 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
|
||||||
fattr->du.nfs2.blocksize = ntohl(*p++);
|
fattr->du.nfs2.blocksize = ntohl(*p++);
|
||||||
rdev = ntohl(*p++);
|
rdev = ntohl(*p++);
|
||||||
fattr->du.nfs2.blocks = ntohl(*p++);
|
fattr->du.nfs2.blocks = ntohl(*p++);
|
||||||
fattr->fsid_u.nfs3 = ntohl(*p++);
|
fattr->fsid.major = ntohl(*p++);
|
||||||
|
fattr->fsid.minor = 0;
|
||||||
fattr->fileid = ntohl(*p++);
|
fattr->fileid = ntohl(*p++);
|
||||||
p = xdr_decode_time(p, &fattr->atime);
|
p = xdr_decode_time(p, &fattr->atime);
|
||||||
p = xdr_decode_time(p, &fattr->mtime);
|
p = xdr_decode_time(p, &fattr->mtime);
|
||||||
|
|
|
@ -172,8 +172,10 @@ static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl,
|
||||||
inode->i_ino, acl, dfacl);
|
inode->i_ino, acl, dfacl);
|
||||||
spin_lock(&inode->i_lock);
|
spin_lock(&inode->i_lock);
|
||||||
__nfs3_forget_cached_acls(NFS_I(inode));
|
__nfs3_forget_cached_acls(NFS_I(inode));
|
||||||
nfsi->acl_access = posix_acl_dup(acl);
|
if (!IS_ERR(acl))
|
||||||
nfsi->acl_default = posix_acl_dup(dfacl);
|
nfsi->acl_access = posix_acl_dup(acl);
|
||||||
|
if (!IS_ERR(dfacl))
|
||||||
|
nfsi->acl_default = posix_acl_dup(dfacl);
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +256,9 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
|
||||||
res.acl_access = NULL;
|
res.acl_access = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nfs3_cache_acls(inode, res.acl_access, res.acl_default);
|
nfs3_cache_acls(inode,
|
||||||
|
(res.mask & NFS_ACL) ? res.acl_access : ERR_PTR(-EINVAL),
|
||||||
|
(res.mask & NFS_DFACL) ? res.acl_default : ERR_PTR(-EINVAL));
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case ACL_TYPE_ACCESS:
|
case ACL_TYPE_ACCESS:
|
||||||
|
@ -329,6 +333,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 0:
|
case 0:
|
||||||
status = nfs_refresh_inode(inode, &fattr);
|
status = nfs_refresh_inode(inode, &fattr);
|
||||||
|
nfs3_cache_acls(inode, acl, dfacl);
|
||||||
break;
|
break;
|
||||||
case -EPFNOSUPPORT:
|
case -EPFNOSUPPORT:
|
||||||
case -EPROTONOSUPPORT:
|
case -EPROTONOSUPPORT:
|
||||||
|
|
|
@ -20,11 +20,10 @@
|
||||||
#include <linux/nfs_mount.h>
|
#include <linux/nfs_mount.h>
|
||||||
|
|
||||||
#include "iostat.h"
|
#include "iostat.h"
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
#define NFSDBG_FACILITY NFSDBG_PROC
|
#define NFSDBG_FACILITY NFSDBG_PROC
|
||||||
|
|
||||||
extern struct rpc_procinfo nfs3_procedures[];
|
|
||||||
|
|
||||||
/* A wrapper to handle the EJUKEBOX error message */
|
/* A wrapper to handle the EJUKEBOX error message */
|
||||||
static int
|
static int
|
||||||
nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
|
nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
|
||||||
|
@ -809,8 +808,6 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
|
|
||||||
|
|
||||||
static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data)
|
static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data)
|
||||||
{
|
{
|
||||||
if (nfs3_async_handle_jukebox(task, data->inode))
|
if (nfs3_async_handle_jukebox(task, data->inode))
|
||||||
|
|
|
@ -22,14 +22,13 @@
|
||||||
#include <linux/nfs3.h>
|
#include <linux/nfs3.h>
|
||||||
#include <linux/nfs_fs.h>
|
#include <linux/nfs_fs.h>
|
||||||
#include <linux/nfsacl.h>
|
#include <linux/nfsacl.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
#define NFSDBG_FACILITY NFSDBG_XDR
|
#define NFSDBG_FACILITY NFSDBG_XDR
|
||||||
|
|
||||||
/* Mapping from NFS error code to "errno" error code. */
|
/* Mapping from NFS error code to "errno" error code. */
|
||||||
#define errno_NFSERR_IO EIO
|
#define errno_NFSERR_IO EIO
|
||||||
|
|
||||||
extern int nfs_stat_to_errno(int);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Declare the space requirements for NFS arguments and replies as
|
* Declare the space requirements for NFS arguments and replies as
|
||||||
* number of 32bit-words
|
* number of 32bit-words
|
||||||
|
@ -166,7 +165,8 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
|
||||||
if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
|
if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
|
||||||
fattr->rdev = 0;
|
fattr->rdev = 0;
|
||||||
|
|
||||||
p = xdr_decode_hyper(p, &fattr->fsid_u.nfs3);
|
p = xdr_decode_hyper(p, &fattr->fsid.major);
|
||||||
|
fattr->fsid.minor = 0;
|
||||||
p = xdr_decode_hyper(p, &fattr->fileid);
|
p = xdr_decode_hyper(p, &fattr->fileid);
|
||||||
p = xdr_decode_time3(p, &fattr->atime);
|
p = xdr_decode_time3(p, &fattr->atime);
|
||||||
p = xdr_decode_time3(p, &fattr->mtime);
|
p = xdr_decode_time3(p, &fattr->mtime);
|
||||||
|
|
|
@ -217,6 +217,9 @@ extern int nfs4_proc_renew(struct nfs4_client *, struct rpc_cred *);
|
||||||
extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state);
|
extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state);
|
||||||
extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
|
extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
|
||||||
extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
|
extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
|
||||||
|
extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
|
||||||
|
extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
|
||||||
|
struct nfs4_fs_locations *fs_locations, struct page *page);
|
||||||
|
|
||||||
extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops;
|
extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops;
|
||||||
extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops;
|
extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops;
|
||||||
|
@ -225,6 +228,7 @@ extern const u32 nfs4_fattr_bitmap[2];
|
||||||
extern const u32 nfs4_statfs_bitmap[2];
|
extern const u32 nfs4_statfs_bitmap[2];
|
||||||
extern const u32 nfs4_pathconf_bitmap[2];
|
extern const u32 nfs4_pathconf_bitmap[2];
|
||||||
extern const u32 nfs4_fsinfo_bitmap[2];
|
extern const u32 nfs4_fsinfo_bitmap[2];
|
||||||
|
extern const u32 nfs4_fs_locations_bitmap[2];
|
||||||
|
|
||||||
/* nfs4renewd.c */
|
/* nfs4renewd.c */
|
||||||
extern void nfs4_schedule_state_renewal(struct nfs4_client *);
|
extern void nfs4_schedule_state_renewal(struct nfs4_client *);
|
||||||
|
|
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
* linux/fs/nfs/nfs4namespace.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
|
||||||
|
*
|
||||||
|
* NFSv4 namespace
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/config.h>
|
||||||
|
|
||||||
|
#include <linux/dcache.h>
|
||||||
|
#include <linux/mount.h>
|
||||||
|
#include <linux/namei.h>
|
||||||
|
#include <linux/nfs_fs.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/sunrpc/clnt.h>
|
||||||
|
#include <linux/vfs.h>
|
||||||
|
#include <linux/inet.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#define NFSDBG_FACILITY NFSDBG_VFS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if fs_root is valid
|
||||||
|
*/
|
||||||
|
static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname,
|
||||||
|
char *buffer, ssize_t buflen)
|
||||||
|
{
|
||||||
|
char *end = buffer + buflen;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
*--end = '\0';
|
||||||
|
buflen--;
|
||||||
|
|
||||||
|
n = pathname->ncomponents;
|
||||||
|
while (--n >= 0) {
|
||||||
|
struct nfs4_string *component = &pathname->components[n];
|
||||||
|
buflen -= component->len + 1;
|
||||||
|
if (buflen < 0)
|
||||||
|
goto Elong;
|
||||||
|
end -= component->len;
|
||||||
|
memcpy(end, component->data, component->len);
|
||||||
|
*--end = '/';
|
||||||
|
}
|
||||||
|
return end;
|
||||||
|
Elong:
|
||||||
|
return ERR_PTR(-ENAMETOOLONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nfs_follow_referral - set up mountpoint when hitting a referral on moved error
|
||||||
|
* @mnt_parent - mountpoint of parent directory
|
||||||
|
* @dentry - parent directory
|
||||||
|
* @fspath - fs path returned in fs_locations
|
||||||
|
* @mntpath - mount path to new server
|
||||||
|
* @hostname - hostname of new server
|
||||||
|
* @addr - host addr of new server
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
|
||||||
|
const struct dentry *dentry,
|
||||||
|
struct nfs4_fs_locations *locations)
|
||||||
|
{
|
||||||
|
struct vfsmount *mnt = ERR_PTR(-ENOENT);
|
||||||
|
struct nfs_clone_mount mountdata = {
|
||||||
|
.sb = mnt_parent->mnt_sb,
|
||||||
|
.dentry = dentry,
|
||||||
|
.authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor,
|
||||||
|
};
|
||||||
|
char *page, *page2;
|
||||||
|
char *path, *fs_path;
|
||||||
|
char *devname;
|
||||||
|
int loc, s;
|
||||||
|
|
||||||
|
if (locations == NULL || locations->nlocations <= 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
dprintk("%s: referral at %s/%s\n", __FUNCTION__,
|
||||||
|
dentry->d_parent->d_name.name, dentry->d_name.name);
|
||||||
|
|
||||||
|
/* Ensure fs path is a prefix of current dentry path */
|
||||||
|
page = (char *) __get_free_page(GFP_USER);
|
||||||
|
if (page == NULL)
|
||||||
|
goto out;
|
||||||
|
page2 = (char *) __get_free_page(GFP_USER);
|
||||||
|
if (page2 == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
path = nfs4_path(dentry, page, PAGE_SIZE);
|
||||||
|
if (IS_ERR(path))
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
|
fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
|
||||||
|
if (IS_ERR(fs_path))
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
|
if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
|
||||||
|
dprintk("%s: path %s does not begin with fsroot %s\n", __FUNCTION__, path, fs_path);
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE);
|
||||||
|
if (IS_ERR(devname)) {
|
||||||
|
mnt = (struct vfsmount *)devname;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
loc = 0;
|
||||||
|
while (loc < locations->nlocations && IS_ERR(mnt)) {
|
||||||
|
struct nfs4_fs_location *location = &locations->locations[loc];
|
||||||
|
char *mnt_path;
|
||||||
|
|
||||||
|
if (location == NULL || location->nservers <= 0 ||
|
||||||
|
location->rootpath.ncomponents == 0) {
|
||||||
|
loc++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE);
|
||||||
|
if (IS_ERR(mnt_path)) {
|
||||||
|
loc++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mountdata.mnt_path = mnt_path;
|
||||||
|
|
||||||
|
s = 0;
|
||||||
|
while (s < location->nservers) {
|
||||||
|
struct sockaddr_in addr = {};
|
||||||
|
|
||||||
|
if (location->servers[s].len <= 0 ||
|
||||||
|
valid_ipaddr4(location->servers[s].data) < 0) {
|
||||||
|
s++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
mountdata.hostname = location->servers[s].data;
|
||||||
|
addr.sin_addr.s_addr = in_aton(mountdata.hostname);
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(NFS_PORT);
|
||||||
|
mountdata.addr = &addr;
|
||||||
|
|
||||||
|
mnt = vfs_kern_mount(&nfs_referral_nfs4_fs_type, 0, devname, &mountdata);
|
||||||
|
if (!IS_ERR(mnt)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
loc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_free:
|
||||||
|
free_page((unsigned long)page);
|
||||||
|
free_page((unsigned long)page2);
|
||||||
|
out:
|
||||||
|
dprintk("%s: done\n", __FUNCTION__);
|
||||||
|
return mnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nfs_do_refmount - handle crossing a referral on server
|
||||||
|
* @dentry - dentry of referral
|
||||||
|
* @nd - nameidata info
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry)
|
||||||
|
{
|
||||||
|
struct vfsmount *mnt = ERR_PTR(-ENOENT);
|
||||||
|
struct dentry *parent;
|
||||||
|
struct nfs4_fs_locations *fs_locations = NULL;
|
||||||
|
struct page *page;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* BUG_ON(IS_ROOT(dentry)); */
|
||||||
|
dprintk("%s: enter\n", __FUNCTION__);
|
||||||
|
|
||||||
|
page = alloc_page(GFP_KERNEL);
|
||||||
|
if (page == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
|
||||||
|
if (fs_locations == NULL)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
|
/* Get locations */
|
||||||
|
parent = dget_parent(dentry);
|
||||||
|
dprintk("%s: getting locations for %s/%s\n", __FUNCTION__, parent->d_name.name, dentry->d_name.name);
|
||||||
|
err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page);
|
||||||
|
dput(parent);
|
||||||
|
if (err != 0 || fs_locations->nlocations <= 0 ||
|
||||||
|
fs_locations->fs_path.ncomponents <= 0)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
|
mnt = nfs_follow_referral(mnt_parent, dentry, fs_locations);
|
||||||
|
out_free:
|
||||||
|
__free_page(page);
|
||||||
|
kfree(fs_locations);
|
||||||
|
out:
|
||||||
|
dprintk("%s: done\n", __FUNCTION__);
|
||||||
|
return mnt;
|
||||||
|
}
|
|
@ -65,8 +65,6 @@ static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *)
|
||||||
static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
|
static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
|
||||||
static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
|
static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
|
||||||
static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp);
|
static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp);
|
||||||
extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
|
|
||||||
extern struct rpc_procinfo nfs4_procedures[];
|
|
||||||
|
|
||||||
/* Prevent leaks of NFSv4 errors into userland */
|
/* Prevent leaks of NFSv4 errors into userland */
|
||||||
int nfs4_map_errors(int err)
|
int nfs4_map_errors(int err)
|
||||||
|
@ -121,6 +119,25 @@ const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const u32 nfs4_fs_locations_bitmap[2] = {
|
||||||
|
FATTR4_WORD0_TYPE
|
||||||
|
| FATTR4_WORD0_CHANGE
|
||||||
|
| FATTR4_WORD0_SIZE
|
||||||
|
| FATTR4_WORD0_FSID
|
||||||
|
| FATTR4_WORD0_FILEID
|
||||||
|
| FATTR4_WORD0_FS_LOCATIONS,
|
||||||
|
FATTR4_WORD1_MODE
|
||||||
|
| FATTR4_WORD1_NUMLINKS
|
||||||
|
| FATTR4_WORD1_OWNER
|
||||||
|
| FATTR4_WORD1_OWNER_GROUP
|
||||||
|
| FATTR4_WORD1_RAWDEV
|
||||||
|
| FATTR4_WORD1_SPACE_USED
|
||||||
|
| FATTR4_WORD1_TIME_ACCESS
|
||||||
|
| FATTR4_WORD1_TIME_METADATA
|
||||||
|
| FATTR4_WORD1_TIME_MODIFY
|
||||||
|
| FATTR4_WORD1_MOUNTED_ON_FILEID
|
||||||
|
};
|
||||||
|
|
||||||
static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry,
|
static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry,
|
||||||
struct nfs4_readdir_arg *readdir)
|
struct nfs4_readdir_arg *readdir)
|
||||||
{
|
{
|
||||||
|
@ -185,15 +202,15 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp
|
||||||
spin_unlock(&clp->cl_lock);
|
spin_unlock(&clp->cl_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinfo)
|
static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
|
||||||
{
|
{
|
||||||
struct nfs_inode *nfsi = NFS_I(inode);
|
struct nfs_inode *nfsi = NFS_I(dir);
|
||||||
|
|
||||||
spin_lock(&inode->i_lock);
|
spin_lock(&dir->i_lock);
|
||||||
nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
|
nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA;
|
||||||
if (cinfo->before == nfsi->change_attr && cinfo->atomic)
|
if (cinfo->before == nfsi->change_attr && cinfo->atomic)
|
||||||
nfsi->change_attr = cinfo->after;
|
nfsi->change_attr = cinfo->after;
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&dir->i_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nfs4_opendata {
|
struct nfs4_opendata {
|
||||||
|
@ -1331,7 +1348,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
|
int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
|
||||||
{
|
{
|
||||||
struct nfs4_exception exception = { };
|
struct nfs4_exception exception = { };
|
||||||
int err;
|
int err;
|
||||||
|
@ -1443,6 +1460,50 @@ out:
|
||||||
return nfs4_map_errors(status);
|
return nfs4_map_errors(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get locations and (maybe) other attributes of a referral.
|
||||||
|
* Note that we'll actually follow the referral later when
|
||||||
|
* we detect fsid mismatch in inode revalidation
|
||||||
|
*/
|
||||||
|
static int nfs4_get_referral(struct inode *dir, struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle)
|
||||||
|
{
|
||||||
|
int status = -ENOMEM;
|
||||||
|
struct page *page = NULL;
|
||||||
|
struct nfs4_fs_locations *locations = NULL;
|
||||||
|
struct dentry dentry = {};
|
||||||
|
|
||||||
|
page = alloc_page(GFP_KERNEL);
|
||||||
|
if (page == NULL)
|
||||||
|
goto out;
|
||||||
|
locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
|
||||||
|
if (locations == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
dentry.d_name.name = name->name;
|
||||||
|
dentry.d_name.len = name->len;
|
||||||
|
status = nfs4_proc_fs_locations(dir, &dentry, locations, page);
|
||||||
|
if (status != 0)
|
||||||
|
goto out;
|
||||||
|
/* Make sure server returned a different fsid for the referral */
|
||||||
|
if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) {
|
||||||
|
dprintk("%s: server did not return a different fsid for a referral at %s\n", __FUNCTION__, name->name);
|
||||||
|
status = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr));
|
||||||
|
fattr->valid |= NFS_ATTR_FATTR_V4_REFERRAL;
|
||||||
|
if (!fattr->mode)
|
||||||
|
fattr->mode = S_IFDIR;
|
||||||
|
memset(fhandle, 0, sizeof(struct nfs_fh));
|
||||||
|
out:
|
||||||
|
if (page)
|
||||||
|
__free_page(page);
|
||||||
|
if (locations)
|
||||||
|
kfree(locations);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
|
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
|
||||||
{
|
{
|
||||||
struct nfs4_getattr_arg args = {
|
struct nfs4_getattr_arg args = {
|
||||||
|
@ -1547,6 +1608,8 @@ static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name,
|
||||||
|
|
||||||
dprintk("NFS call lookup %s\n", name->name);
|
dprintk("NFS call lookup %s\n", name->name);
|
||||||
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
|
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
|
||||||
|
if (status == -NFS4ERR_MOVED)
|
||||||
|
status = nfs4_get_referral(dir, name, fattr, fhandle);
|
||||||
dprintk("NFS reply lookup: %d\n", status);
|
dprintk("NFS reply lookup: %d\n", status);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -2008,7 +2071,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
|
||||||
if (!status) {
|
if (!status) {
|
||||||
update_changeattr(dir, &res.cinfo);
|
update_changeattr(dir, &res.cinfo);
|
||||||
nfs_post_op_update_inode(dir, res.dir_attr);
|
nfs_post_op_update_inode(dir, res.dir_attr);
|
||||||
nfs_refresh_inode(inode, res.fattr);
|
nfs_post_op_update_inode(inode, res.fattr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
@ -3570,6 +3633,36 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
|
||||||
|
struct nfs4_fs_locations *fs_locations, struct page *page)
|
||||||
|
{
|
||||||
|
struct nfs_server *server = NFS_SERVER(dir);
|
||||||
|
u32 bitmask[2] = {
|
||||||
|
[0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
|
||||||
|
[1] = FATTR4_WORD1_MOUNTED_ON_FILEID,
|
||||||
|
};
|
||||||
|
struct nfs4_fs_locations_arg args = {
|
||||||
|
.dir_fh = NFS_FH(dir),
|
||||||
|
.name = &dentry->d_name,
|
||||||
|
.page = page,
|
||||||
|
.bitmask = bitmask,
|
||||||
|
};
|
||||||
|
struct rpc_message msg = {
|
||||||
|
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
|
||||||
|
.rpc_argp = &args,
|
||||||
|
.rpc_resp = fs_locations,
|
||||||
|
};
|
||||||
|
int status;
|
||||||
|
|
||||||
|
dprintk("%s: start\n", __FUNCTION__);
|
||||||
|
fs_locations->fattr.valid = 0;
|
||||||
|
fs_locations->server = server;
|
||||||
|
fs_locations->nlocations = 0;
|
||||||
|
status = rpc_call_sync(server->client, &msg, 0);
|
||||||
|
dprintk("%s: returned status = %d\n", __FUNCTION__, status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = {
|
struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = {
|
||||||
.recover_open = nfs4_open_reclaim,
|
.recover_open = nfs4_open_reclaim,
|
||||||
.recover_lock = nfs4_lock_reclaim,
|
.recover_lock = nfs4_lock_reclaim,
|
||||||
|
|
218
fs/nfs/nfs4xdr.c
218
fs/nfs/nfs4xdr.c
|
@ -411,6 +411,15 @@ static int nfs_stat_to_errno(int);
|
||||||
#define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \
|
#define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \
|
||||||
decode_putfh_maxsz + \
|
decode_putfh_maxsz + \
|
||||||
op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
|
op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
|
||||||
|
#define NFS4_enc_fs_locations_sz \
|
||||||
|
(compound_encode_hdr_maxsz + \
|
||||||
|
encode_putfh_maxsz + \
|
||||||
|
encode_getattr_maxsz)
|
||||||
|
#define NFS4_dec_fs_locations_sz \
|
||||||
|
(compound_decode_hdr_maxsz + \
|
||||||
|
decode_putfh_maxsz + \
|
||||||
|
op_decode_hdr_maxsz + \
|
||||||
|
nfs4_fattr_bitmap_maxsz)
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
unsigned int mode;
|
unsigned int mode;
|
||||||
|
@ -722,6 +731,13 @@ static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask)
|
||||||
bitmask[1] & nfs4_fsinfo_bitmap[1]);
|
bitmask[1] & nfs4_fsinfo_bitmap[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask)
|
||||||
|
{
|
||||||
|
return encode_getattr_two(xdr,
|
||||||
|
bitmask[0] & nfs4_fs_locations_bitmap[0],
|
||||||
|
bitmask[1] & nfs4_fs_locations_bitmap[1]);
|
||||||
|
}
|
||||||
|
|
||||||
static int encode_getfh(struct xdr_stream *xdr)
|
static int encode_getfh(struct xdr_stream *xdr)
|
||||||
{
|
{
|
||||||
uint32_t *p;
|
uint32_t *p;
|
||||||
|
@ -2002,6 +2018,38 @@ out:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encode FS_LOCATIONS request
|
||||||
|
*/
|
||||||
|
static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations_arg *args)
|
||||||
|
{
|
||||||
|
struct xdr_stream xdr;
|
||||||
|
struct compound_hdr hdr = {
|
||||||
|
.nops = 3,
|
||||||
|
};
|
||||||
|
struct rpc_auth *auth = req->rq_task->tk_auth;
|
||||||
|
int replen;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
||||||
|
encode_compound_hdr(&xdr, &hdr);
|
||||||
|
if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
|
||||||
|
goto out;
|
||||||
|
if ((status = encode_lookup(&xdr, args->name)) != 0)
|
||||||
|
goto out;
|
||||||
|
if ((status = encode_fs_locations(&xdr, args->bitmask)) != 0)
|
||||||
|
goto out;
|
||||||
|
/* set up reply
|
||||||
|
* toplevel_status + OP_PUTFH + status
|
||||||
|
* + OP_LOOKUP + status + OP_GETATTR + status = 7
|
||||||
|
*/
|
||||||
|
replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
|
||||||
|
xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page,
|
||||||
|
0, PAGE_SIZE);
|
||||||
|
out:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* START OF "GENERIC" DECODE ROUTINES.
|
* START OF "GENERIC" DECODE ROUTINES.
|
||||||
* These may look a little ugly since they are imported from a "generic"
|
* These may look a little ugly since they are imported from a "generic"
|
||||||
|
@ -2036,7 +2084,7 @@ out:
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static int decode_opaque_inline(struct xdr_stream *xdr, uint32_t *len, char **string)
|
static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
|
||||||
{
|
{
|
||||||
uint32_t *p;
|
uint32_t *p;
|
||||||
|
|
||||||
|
@ -2087,7 +2135,7 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
|
||||||
static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp)
|
static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp)
|
||||||
{
|
{
|
||||||
uint32_t *p;
|
uint32_t *p;
|
||||||
uint32_t strlen;
|
unsigned int strlen;
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
READ_BUF(12);
|
READ_BUF(12);
|
||||||
|
@ -2217,7 +2265,7 @@ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fsid *fsid)
|
static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
|
||||||
{
|
{
|
||||||
uint32_t *p;
|
uint32_t *p;
|
||||||
|
|
||||||
|
@ -2285,6 +2333,22 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
|
||||||
|
{
|
||||||
|
uint32_t *p;
|
||||||
|
|
||||||
|
*fileid = 0;
|
||||||
|
if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
|
||||||
|
return -EIO;
|
||||||
|
if (likely(bitmap[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) {
|
||||||
|
READ_BUF(8);
|
||||||
|
READ64(*fileid);
|
||||||
|
bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
|
||||||
|
}
|
||||||
|
dprintk("%s: fileid=%Lu\n", __FUNCTION__, (unsigned long long)*fileid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
|
static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
|
||||||
{
|
{
|
||||||
uint32_t *p;
|
uint32_t *p;
|
||||||
|
@ -2336,6 +2400,116 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
uint32_t *p;
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(n);
|
||||||
|
if (n < 0)
|
||||||
|
goto out_eio;
|
||||||
|
if (n == 0)
|
||||||
|
goto root_path;
|
||||||
|
dprintk("path ");
|
||||||
|
path->ncomponents = 0;
|
||||||
|
while (path->ncomponents < n) {
|
||||||
|
struct nfs4_string *component = &path->components[path->ncomponents];
|
||||||
|
status = decode_opaque_inline(xdr, &component->len, &component->data);
|
||||||
|
if (unlikely(status != 0))
|
||||||
|
goto out_eio;
|
||||||
|
if (path->ncomponents != n)
|
||||||
|
dprintk("/");
|
||||||
|
dprintk("%s", component->data);
|
||||||
|
if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS)
|
||||||
|
path->ncomponents++;
|
||||||
|
else {
|
||||||
|
dprintk("cannot parse %d components in path\n", n);
|
||||||
|
goto out_eio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
dprintk("\n");
|
||||||
|
return status;
|
||||||
|
root_path:
|
||||||
|
/* a root pathname is sent as a zero component4 */
|
||||||
|
path->ncomponents = 1;
|
||||||
|
path->components[0].len=0;
|
||||||
|
path->components[0].data=NULL;
|
||||||
|
dprintk("path /\n");
|
||||||
|
goto out;
|
||||||
|
out_eio:
|
||||||
|
dprintk(" status %d", status);
|
||||||
|
status = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
uint32_t *p;
|
||||||
|
int status = -EIO;
|
||||||
|
|
||||||
|
if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U)))
|
||||||
|
goto out;
|
||||||
|
status = 0;
|
||||||
|
if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
|
||||||
|
goto out;
|
||||||
|
dprintk("%s: fsroot ", __FUNCTION__);
|
||||||
|
status = decode_pathname(xdr, &res->fs_path);
|
||||||
|
if (unlikely(status != 0))
|
||||||
|
goto out;
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(n);
|
||||||
|
if (n <= 0)
|
||||||
|
goto out_eio;
|
||||||
|
res->nlocations = 0;
|
||||||
|
while (res->nlocations < n) {
|
||||||
|
int m;
|
||||||
|
struct nfs4_fs_location *loc = &res->locations[res->nlocations];
|
||||||
|
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(m);
|
||||||
|
if (m <= 0)
|
||||||
|
goto out_eio;
|
||||||
|
|
||||||
|
loc->nservers = 0;
|
||||||
|
dprintk("%s: servers ", __FUNCTION__);
|
||||||
|
while (loc->nservers < m) {
|
||||||
|
struct nfs4_string *server = &loc->servers[loc->nservers];
|
||||||
|
status = decode_opaque_inline(xdr, &server->len, &server->data);
|
||||||
|
if (unlikely(status != 0))
|
||||||
|
goto out_eio;
|
||||||
|
dprintk("%s ", server->data);
|
||||||
|
if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS)
|
||||||
|
loc->nservers++;
|
||||||
|
else {
|
||||||
|
int i;
|
||||||
|
dprintk("%s: using first %d of %d servers returned for location %d\n", __FUNCTION__, NFS4_FS_LOCATION_MAXSERVERS, m, res->nlocations);
|
||||||
|
for (i = loc->nservers; i < m; i++) {
|
||||||
|
int len;
|
||||||
|
char *data;
|
||||||
|
status = decode_opaque_inline(xdr, &len, &data);
|
||||||
|
if (unlikely(status != 0))
|
||||||
|
goto out_eio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
status = decode_pathname(xdr, &loc->rootpath);
|
||||||
|
if (unlikely(status != 0))
|
||||||
|
goto out_eio;
|
||||||
|
if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
|
||||||
|
res->nlocations++;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
dprintk("%s: fs_locations done, error = %d\n", __FUNCTION__, status);
|
||||||
|
return status;
|
||||||
|
out_eio:
|
||||||
|
status = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
|
static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
|
||||||
{
|
{
|
||||||
uint32_t *p;
|
uint32_t *p;
|
||||||
|
@ -2841,6 +3015,7 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
|
||||||
bitmap[2] = {0},
|
bitmap[2] = {0},
|
||||||
type;
|
type;
|
||||||
int status, fmode = 0;
|
int status, fmode = 0;
|
||||||
|
uint64_t fileid;
|
||||||
|
|
||||||
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
|
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
|
||||||
goto xdr_error;
|
goto xdr_error;
|
||||||
|
@ -2863,10 +3038,14 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
|
||||||
goto xdr_error;
|
goto xdr_error;
|
||||||
if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0)
|
if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0)
|
||||||
goto xdr_error;
|
goto xdr_error;
|
||||||
if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid_u.nfs4)) != 0)
|
if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid)) != 0)
|
||||||
goto xdr_error;
|
goto xdr_error;
|
||||||
if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
|
if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
|
||||||
goto xdr_error;
|
goto xdr_error;
|
||||||
|
if ((status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
|
||||||
|
struct nfs4_fs_locations,
|
||||||
|
fattr))) != 0)
|
||||||
|
goto xdr_error;
|
||||||
if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
|
if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
|
||||||
goto xdr_error;
|
goto xdr_error;
|
||||||
fattr->mode |= fmode;
|
fattr->mode |= fmode;
|
||||||
|
@ -2886,6 +3065,10 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
|
||||||
goto xdr_error;
|
goto xdr_error;
|
||||||
if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0)
|
if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0)
|
||||||
goto xdr_error;
|
goto xdr_error;
|
||||||
|
if ((status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid)) != 0)
|
||||||
|
goto xdr_error;
|
||||||
|
if (fattr->fileid == 0 && fileid != 0)
|
||||||
|
fattr->fileid = fileid;
|
||||||
if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
|
if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
|
||||||
fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
|
fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
|
||||||
xdr_error:
|
xdr_error:
|
||||||
|
@ -3350,8 +3533,7 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
|
||||||
attrlen, recvd);
|
attrlen, recvd);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (attrlen <= *acl_len)
|
xdr_read_pages(xdr, attrlen);
|
||||||
xdr_read_pages(xdr, attrlen);
|
|
||||||
*acl_len = attrlen;
|
*acl_len = attrlen;
|
||||||
} else
|
} else
|
||||||
status = -EOPNOTSUPP;
|
status = -EOPNOTSUPP;
|
||||||
|
@ -4211,6 +4393,29 @@ out:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FS_LOCATIONS request
|
||||||
|
*/
|
||||||
|
static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations *res)
|
||||||
|
{
|
||||||
|
struct xdr_stream xdr;
|
||||||
|
struct compound_hdr hdr;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
|
||||||
|
status = decode_compound_hdr(&xdr, &hdr);
|
||||||
|
if (status != 0)
|
||||||
|
goto out;
|
||||||
|
if ((status = decode_putfh(&xdr)) != 0)
|
||||||
|
goto out;
|
||||||
|
if ((status = decode_lookup(&xdr)) != 0)
|
||||||
|
goto out;
|
||||||
|
xdr_enter_page(&xdr, PAGE_SIZE);
|
||||||
|
status = decode_getfattr(&xdr, &res->fattr, res->server);
|
||||||
|
out:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
|
uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
|
||||||
{
|
{
|
||||||
uint32_t bitmap[2] = {0};
|
uint32_t bitmap[2] = {0};
|
||||||
|
@ -4382,6 +4587,7 @@ struct rpc_procinfo nfs4_procedures[] = {
|
||||||
PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn),
|
PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn),
|
||||||
PROC(GETACL, enc_getacl, dec_getacl),
|
PROC(GETACL, enc_getacl, dec_getacl),
|
||||||
PROC(SETACL, enc_setacl, dec_setacl),
|
PROC(SETACL, enc_setacl, dec_setacl),
|
||||||
|
PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rpc_version nfs_version4 = {
|
struct rpc_version nfs_version4 = {
|
||||||
|
|
|
@ -325,6 +325,7 @@ out:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nfs_scan_list - Scan a list for matching requests
|
* nfs_scan_list - Scan a list for matching requests
|
||||||
|
* @nfsi: NFS inode
|
||||||
* @head: One of the NFS inode request lists
|
* @head: One of the NFS inode request lists
|
||||||
* @dst: Destination list
|
* @dst: Destination list
|
||||||
* @idx_start: lower bound of page->index to scan
|
* @idx_start: lower bound of page->index to scan
|
||||||
|
@ -336,14 +337,15 @@ out:
|
||||||
* The requests are *not* checked to ensure that they form a contiguous set.
|
* The requests are *not* checked to ensure that they form a contiguous set.
|
||||||
* You must be holding the inode's req_lock when calling this function
|
* You must be holding the inode's req_lock when calling this function
|
||||||
*/
|
*/
|
||||||
int
|
int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head,
|
||||||
nfs_scan_list(struct list_head *head, struct list_head *dst,
|
struct list_head *dst, unsigned long idx_start,
|
||||||
unsigned long idx_start, unsigned int npages)
|
unsigned int npages)
|
||||||
{
|
{
|
||||||
struct list_head *pos, *tmp;
|
struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
|
||||||
struct nfs_page *req;
|
struct nfs_page *req;
|
||||||
unsigned long idx_end;
|
unsigned long idx_end;
|
||||||
int res;
|
int found, i;
|
||||||
|
int res;
|
||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
if (npages == 0)
|
if (npages == 0)
|
||||||
|
@ -351,25 +353,32 @@ nfs_scan_list(struct list_head *head, struct list_head *dst,
|
||||||
else
|
else
|
||||||
idx_end = idx_start + npages - 1;
|
idx_end = idx_start + npages - 1;
|
||||||
|
|
||||||
list_for_each_safe(pos, tmp, head) {
|
for (;;) {
|
||||||
|
found = radix_tree_gang_lookup(&nfsi->nfs_page_tree,
|
||||||
req = nfs_list_entry(pos);
|
(void **)&pgvec[0], idx_start,
|
||||||
|
NFS_SCAN_MAXENTRIES);
|
||||||
if (req->wb_index < idx_start)
|
if (found <= 0)
|
||||||
continue;
|
|
||||||
if (req->wb_index > idx_end)
|
|
||||||
break;
|
break;
|
||||||
|
for (i = 0; i < found; i++) {
|
||||||
|
req = pgvec[i];
|
||||||
|
if (req->wb_index > idx_end)
|
||||||
|
goto out;
|
||||||
|
idx_start = req->wb_index + 1;
|
||||||
|
if (req->wb_list_head != head)
|
||||||
|
continue;
|
||||||
|
if (nfs_set_page_writeback_locked(req)) {
|
||||||
|
nfs_list_remove_request(req);
|
||||||
|
nfs_list_add_request(req, dst);
|
||||||
|
res++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!nfs_set_page_writeback_locked(req))
|
|
||||||
continue;
|
|
||||||
nfs_list_remove_request(req);
|
|
||||||
nfs_list_add_request(req, dst);
|
|
||||||
res++;
|
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nfs_init_nfspagecache(void)
|
int __init nfs_init_nfspagecache(void)
|
||||||
{
|
{
|
||||||
nfs_page_cachep = kmem_cache_create("nfs_page",
|
nfs_page_cachep = kmem_cache_create("nfs_page",
|
||||||
sizeof(struct nfs_page),
|
sizeof(struct nfs_page),
|
||||||
|
@ -381,7 +390,7 @@ int nfs_init_nfspagecache(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfs_destroy_nfspagecache(void)
|
void __exit nfs_destroy_nfspagecache(void)
|
||||||
{
|
{
|
||||||
if (kmem_cache_destroy(nfs_page_cachep))
|
if (kmem_cache_destroy(nfs_page_cachep))
|
||||||
printk(KERN_INFO "nfs_page: not all structures were freed\n");
|
printk(KERN_INFO "nfs_page: not all structures were freed\n");
|
||||||
|
|
|
@ -44,11 +44,10 @@
|
||||||
#include <linux/nfs_page.h>
|
#include <linux/nfs_page.h>
|
||||||
#include <linux/lockd/bind.h>
|
#include <linux/lockd/bind.h>
|
||||||
#include <linux/smp_lock.h>
|
#include <linux/smp_lock.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
#define NFSDBG_FACILITY NFSDBG_PROC
|
#define NFSDBG_FACILITY NFSDBG_PROC
|
||||||
|
|
||||||
extern struct rpc_procinfo nfs_procedures[];
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bare-bones access to getattr: this is for nfs_read_super.
|
* Bare-bones access to getattr: this is for nfs_read_super.
|
||||||
*/
|
*/
|
||||||
|
@ -611,8 +610,6 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
|
|
||||||
|
|
||||||
static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
|
static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
|
||||||
{
|
{
|
||||||
if (task->tk_status >= 0) {
|
if (task->tk_status >= 0) {
|
||||||
|
|
122
fs/nfs/read.c
122
fs/nfs/read.c
|
@ -51,14 +51,11 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
|
||||||
if (p) {
|
if (p) {
|
||||||
memset(p, 0, sizeof(*p));
|
memset(p, 0, sizeof(*p));
|
||||||
INIT_LIST_HEAD(&p->pages);
|
INIT_LIST_HEAD(&p->pages);
|
||||||
if (pagecount < NFS_PAGEVEC_SIZE)
|
if (pagecount <= ARRAY_SIZE(p->page_array))
|
||||||
p->pagevec = &p->page_array[0];
|
p->pagevec = p->page_array;
|
||||||
else {
|
else {
|
||||||
size_t size = ++pagecount * sizeof(struct page *);
|
p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
|
||||||
p->pagevec = kmalloc(size, GFP_NOFS);
|
if (!p->pagevec) {
|
||||||
if (p->pagevec) {
|
|
||||||
memset(p->pagevec, 0, size);
|
|
||||||
} else {
|
|
||||||
mempool_free(p, nfs_rdata_mempool);
|
mempool_free(p, nfs_rdata_mempool);
|
||||||
p = NULL;
|
p = NULL;
|
||||||
}
|
}
|
||||||
|
@ -104,6 +101,28 @@ int nfs_return_empty_page(struct page *page)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data)
|
||||||
|
{
|
||||||
|
unsigned int remainder = data->args.count - data->res.count;
|
||||||
|
unsigned int base = data->args.pgbase + data->res.count;
|
||||||
|
unsigned int pglen;
|
||||||
|
struct page **pages;
|
||||||
|
|
||||||
|
if (data->res.eof == 0 || remainder == 0)
|
||||||
|
return;
|
||||||
|
/*
|
||||||
|
* Note: "remainder" can never be negative, since we check for
|
||||||
|
* this in the XDR code.
|
||||||
|
*/
|
||||||
|
pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
|
||||||
|
base &= ~PAGE_CACHE_MASK;
|
||||||
|
pglen = PAGE_CACHE_SIZE - base;
|
||||||
|
if (pglen < remainder)
|
||||||
|
memclear_highpage_flush(*pages, base, pglen);
|
||||||
|
else
|
||||||
|
memclear_highpage_flush(*pages, base, remainder);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read a page synchronously.
|
* Read a page synchronously.
|
||||||
*/
|
*/
|
||||||
|
@ -177,11 +196,9 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode,
|
||||||
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
|
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
|
|
||||||
if (count)
|
nfs_readpage_truncate_uninitialised_page(rdata);
|
||||||
memclear_highpage_flush(page, rdata->args.pgbase, count);
|
if (rdata->res.eof || rdata->res.count == rdata->args.count)
|
||||||
SetPageUptodate(page);
|
SetPageUptodate(page);
|
||||||
if (PageError(page))
|
|
||||||
ClearPageError(page);
|
|
||||||
result = 0;
|
result = 0;
|
||||||
|
|
||||||
io_error:
|
io_error:
|
||||||
|
@ -436,20 +453,12 @@ static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata)
|
||||||
struct nfs_page *req = data->req;
|
struct nfs_page *req = data->req;
|
||||||
struct page *page = req->wb_page;
|
struct page *page = req->wb_page;
|
||||||
|
|
||||||
|
if (likely(task->tk_status >= 0))
|
||||||
|
nfs_readpage_truncate_uninitialised_page(data);
|
||||||
|
else
|
||||||
|
SetPageError(page);
|
||||||
if (nfs_readpage_result(task, data) != 0)
|
if (nfs_readpage_result(task, data) != 0)
|
||||||
return;
|
return;
|
||||||
if (task->tk_status >= 0) {
|
|
||||||
unsigned int request = data->args.count;
|
|
||||||
unsigned int result = data->res.count;
|
|
||||||
|
|
||||||
if (result < request) {
|
|
||||||
memclear_highpage_flush(page,
|
|
||||||
data->args.pgbase + result,
|
|
||||||
request - result);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
SetPageError(page);
|
|
||||||
|
|
||||||
if (atomic_dec_and_test(&req->wb_complete)) {
|
if (atomic_dec_and_test(&req->wb_complete)) {
|
||||||
if (!PageError(page))
|
if (!PageError(page))
|
||||||
SetPageUptodate(page);
|
SetPageUptodate(page);
|
||||||
|
@ -462,6 +471,40 @@ static const struct rpc_call_ops nfs_read_partial_ops = {
|
||||||
.rpc_release = nfs_readdata_release,
|
.rpc_release = nfs_readdata_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data)
|
||||||
|
{
|
||||||
|
unsigned int count = data->res.count;
|
||||||
|
unsigned int base = data->args.pgbase;
|
||||||
|
struct page **pages;
|
||||||
|
|
||||||
|
if (unlikely(count == 0))
|
||||||
|
return;
|
||||||
|
pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
|
||||||
|
base &= ~PAGE_CACHE_MASK;
|
||||||
|
count += base;
|
||||||
|
for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
|
||||||
|
SetPageUptodate(*pages);
|
||||||
|
/*
|
||||||
|
* Was this an eof or a short read? If the latter, don't mark the page
|
||||||
|
* as uptodate yet.
|
||||||
|
*/
|
||||||
|
if (count > 0 && (data->res.eof || data->args.count == data->res.count))
|
||||||
|
SetPageUptodate(*pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs_readpage_set_pages_error(struct nfs_read_data *data)
|
||||||
|
{
|
||||||
|
unsigned int count = data->args.count;
|
||||||
|
unsigned int base = data->args.pgbase;
|
||||||
|
struct page **pages;
|
||||||
|
|
||||||
|
pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
|
||||||
|
base &= ~PAGE_CACHE_MASK;
|
||||||
|
count += base;
|
||||||
|
for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
|
||||||
|
SetPageError(*pages);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the callback from RPC telling us whether a reply was
|
* This is the callback from RPC telling us whether a reply was
|
||||||
* received or some error occurred (timeout or socket shutdown).
|
* received or some error occurred (timeout or socket shutdown).
|
||||||
|
@ -469,27 +512,24 @@ static const struct rpc_call_ops nfs_read_partial_ops = {
|
||||||
static void nfs_readpage_result_full(struct rpc_task *task, void *calldata)
|
static void nfs_readpage_result_full(struct rpc_task *task, void *calldata)
|
||||||
{
|
{
|
||||||
struct nfs_read_data *data = calldata;
|
struct nfs_read_data *data = calldata;
|
||||||
unsigned int count = data->res.count;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: nfs_readpage_result may change the values of
|
||||||
|
* data->args. In the multi-page case, we therefore need
|
||||||
|
* to ensure that we call the next nfs_readpage_set_page_uptodate()
|
||||||
|
* first in the multi-page case.
|
||||||
|
*/
|
||||||
|
if (likely(task->tk_status >= 0)) {
|
||||||
|
nfs_readpage_truncate_uninitialised_page(data);
|
||||||
|
nfs_readpage_set_pages_uptodate(data);
|
||||||
|
} else
|
||||||
|
nfs_readpage_set_pages_error(data);
|
||||||
if (nfs_readpage_result(task, data) != 0)
|
if (nfs_readpage_result(task, data) != 0)
|
||||||
return;
|
return;
|
||||||
while (!list_empty(&data->pages)) {
|
while (!list_empty(&data->pages)) {
|
||||||
struct nfs_page *req = nfs_list_entry(data->pages.next);
|
struct nfs_page *req = nfs_list_entry(data->pages.next);
|
||||||
struct page *page = req->wb_page;
|
|
||||||
nfs_list_remove_request(req);
|
|
||||||
|
|
||||||
if (task->tk_status >= 0) {
|
nfs_list_remove_request(req);
|
||||||
if (count < PAGE_CACHE_SIZE) {
|
|
||||||
if (count < req->wb_bytes)
|
|
||||||
memclear_highpage_flush(page,
|
|
||||||
req->wb_pgbase + count,
|
|
||||||
req->wb_bytes - count);
|
|
||||||
count = 0;
|
|
||||||
} else
|
|
||||||
count -= PAGE_CACHE_SIZE;
|
|
||||||
SetPageUptodate(page);
|
|
||||||
} else
|
|
||||||
SetPageError(page);
|
|
||||||
nfs_readpage_release(req);
|
nfs_readpage_release(req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -654,7 +694,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nfs_init_readpagecache(void)
|
int __init nfs_init_readpagecache(void)
|
||||||
{
|
{
|
||||||
nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
|
nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
|
||||||
sizeof(struct nfs_read_data),
|
sizeof(struct nfs_read_data),
|
||||||
|
@ -671,7 +711,7 @@ int nfs_init_readpagecache(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfs_destroy_readpagecache(void)
|
void __exit nfs_destroy_readpagecache(void)
|
||||||
{
|
{
|
||||||
mempool_destroy(nfs_rdata_mempool);
|
mempool_destroy(nfs_rdata_mempool);
|
||||||
if (kmem_cache_destroy(nfs_rdata_cachep))
|
if (kmem_cache_destroy(nfs_rdata_cachep))
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -52,7 +52,7 @@ static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||||
{
|
{
|
||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
void *err = ERR_PTR(nfs_revalidate_inode(NFS_SERVER(inode), inode));
|
void *err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping));
|
||||||
if (err)
|
if (err)
|
||||||
goto read_failed;
|
goto read_failed;
|
||||||
page = read_cache_page(&inode->i_data, 0,
|
page = read_cache_page(&inode->i_data, 0,
|
||||||
|
@ -75,22 +75,13 @@ read_failed:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
|
|
||||||
{
|
|
||||||
if (cookie) {
|
|
||||||
struct page *page = cookie;
|
|
||||||
kunmap(page);
|
|
||||||
page_cache_release(page);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* symlinks can't do much...
|
* symlinks can't do much...
|
||||||
*/
|
*/
|
||||||
struct inode_operations nfs_symlink_inode_operations = {
|
struct inode_operations nfs_symlink_inode_operations = {
|
||||||
.readlink = generic_readlink,
|
.readlink = generic_readlink,
|
||||||
.follow_link = nfs_follow_link,
|
.follow_link = nfs_follow_link,
|
||||||
.put_link = nfs_put_link,
|
.put_link = page_put_link,
|
||||||
.getattr = nfs_getattr,
|
.getattr = nfs_getattr,
|
||||||
.setattr = nfs_setattr,
|
.setattr = nfs_setattr,
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/nfs4.h>
|
#include <linux/nfs4.h>
|
||||||
#include <linux/nfs_idmap.h>
|
#include <linux/nfs_idmap.h>
|
||||||
|
#include <linux/nfs_fs.h>
|
||||||
|
|
||||||
#include "callback.h"
|
#include "callback.h"
|
||||||
|
|
||||||
|
@ -46,6 +47,15 @@ static ctl_table nfs_cb_sysctls[] = {
|
||||||
.strategy = &sysctl_jiffies,
|
.strategy = &sysctl_jiffies,
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
.ctl_name = CTL_UNNUMBERED,
|
||||||
|
.procname = "nfs_mountpoint_timeout",
|
||||||
|
.data = &nfs_mountpoint_expiry_timeout,
|
||||||
|
.maxlen = sizeof(nfs_mountpoint_expiry_timeout),
|
||||||
|
.mode = 0644,
|
||||||
|
.proc_handler = &proc_dointvec_jiffies,
|
||||||
|
.strategy = &sysctl_jiffies,
|
||||||
|
},
|
||||||
{ .ctl_name = 0 }
|
{ .ctl_name = 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -98,11 +98,10 @@ struct nfs_write_data *nfs_commit_alloc(unsigned int pagecount)
|
||||||
if (p) {
|
if (p) {
|
||||||
memset(p, 0, sizeof(*p));
|
memset(p, 0, sizeof(*p));
|
||||||
INIT_LIST_HEAD(&p->pages);
|
INIT_LIST_HEAD(&p->pages);
|
||||||
if (pagecount < NFS_PAGEVEC_SIZE)
|
if (pagecount <= ARRAY_SIZE(p->page_array))
|
||||||
p->pagevec = &p->page_array[0];
|
p->pagevec = p->page_array;
|
||||||
else {
|
else {
|
||||||
size_t size = ++pagecount * sizeof(struct page *);
|
p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
|
||||||
p->pagevec = kzalloc(size, GFP_NOFS);
|
|
||||||
if (!p->pagevec) {
|
if (!p->pagevec) {
|
||||||
mempool_free(p, nfs_commit_mempool);
|
mempool_free(p, nfs_commit_mempool);
|
||||||
p = NULL;
|
p = NULL;
|
||||||
|
@ -126,14 +125,11 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
|
||||||
if (p) {
|
if (p) {
|
||||||
memset(p, 0, sizeof(*p));
|
memset(p, 0, sizeof(*p));
|
||||||
INIT_LIST_HEAD(&p->pages);
|
INIT_LIST_HEAD(&p->pages);
|
||||||
if (pagecount < NFS_PAGEVEC_SIZE)
|
if (pagecount <= ARRAY_SIZE(p->page_array))
|
||||||
p->pagevec = &p->page_array[0];
|
p->pagevec = p->page_array;
|
||||||
else {
|
else {
|
||||||
size_t size = ++pagecount * sizeof(struct page *);
|
p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
|
||||||
p->pagevec = kmalloc(size, GFP_NOFS);
|
if (!p->pagevec) {
|
||||||
if (p->pagevec) {
|
|
||||||
memset(p->pagevec, 0, size);
|
|
||||||
} else {
|
|
||||||
mempool_free(p, nfs_wdata_mempool);
|
mempool_free(p, nfs_wdata_mempool);
|
||||||
p = NULL;
|
p = NULL;
|
||||||
}
|
}
|
||||||
|
@ -583,6 +579,17 @@ static int nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, un
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nfs_cancel_requests(struct list_head *head)
|
||||||
|
{
|
||||||
|
struct nfs_page *req;
|
||||||
|
while(!list_empty(head)) {
|
||||||
|
req = nfs_list_entry(head->next);
|
||||||
|
nfs_list_remove_request(req);
|
||||||
|
nfs_inode_remove_request(req);
|
||||||
|
nfs_clear_page_writeback(req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* nfs_scan_dirty - Scan an inode for dirty requests
|
* nfs_scan_dirty - Scan an inode for dirty requests
|
||||||
* @inode: NFS inode to scan
|
* @inode: NFS inode to scan
|
||||||
|
@ -627,7 +634,7 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_st
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
if (nfsi->ncommit != 0) {
|
if (nfsi->ncommit != 0) {
|
||||||
res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages);
|
res = nfs_scan_list(nfsi, &nfsi->commit, dst, idx_start, npages);
|
||||||
nfsi->ncommit -= res;
|
nfsi->ncommit -= res;
|
||||||
if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))
|
if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))
|
||||||
printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
|
printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
|
||||||
|
@ -1495,15 +1502,25 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
|
||||||
pages = nfs_scan_dirty(inode, &head, idx_start, npages);
|
pages = nfs_scan_dirty(inode, &head, idx_start, npages);
|
||||||
if (pages != 0) {
|
if (pages != 0) {
|
||||||
spin_unlock(&nfsi->req_lock);
|
spin_unlock(&nfsi->req_lock);
|
||||||
ret = nfs_flush_list(inode, &head, pages, how);
|
if (how & FLUSH_INVALIDATE)
|
||||||
|
nfs_cancel_requests(&head);
|
||||||
|
else
|
||||||
|
ret = nfs_flush_list(inode, &head, pages, how);
|
||||||
spin_lock(&nfsi->req_lock);
|
spin_lock(&nfsi->req_lock);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (nocommit)
|
if (nocommit)
|
||||||
break;
|
break;
|
||||||
pages = nfs_scan_commit(inode, &head, 0, 0);
|
pages = nfs_scan_commit(inode, &head, idx_start, npages);
|
||||||
if (pages == 0)
|
if (pages == 0)
|
||||||
break;
|
break;
|
||||||
|
if (how & FLUSH_INVALIDATE) {
|
||||||
|
spin_unlock(&nfsi->req_lock);
|
||||||
|
nfs_cancel_requests(&head);
|
||||||
|
spin_lock(&nfsi->req_lock);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pages += nfs_scan_commit(inode, &head, 0, 0);
|
||||||
spin_unlock(&nfsi->req_lock);
|
spin_unlock(&nfsi->req_lock);
|
||||||
ret = nfs_commit_list(inode, &head, how);
|
ret = nfs_commit_list(inode, &head, how);
|
||||||
spin_lock(&nfsi->req_lock);
|
spin_lock(&nfsi->req_lock);
|
||||||
|
@ -1512,7 +1529,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nfs_init_writepagecache(void)
|
int __init nfs_init_writepagecache(void)
|
||||||
{
|
{
|
||||||
nfs_wdata_cachep = kmem_cache_create("nfs_write_data",
|
nfs_wdata_cachep = kmem_cache_create("nfs_write_data",
|
||||||
sizeof(struct nfs_write_data),
|
sizeof(struct nfs_write_data),
|
||||||
|
@ -1534,7 +1551,7 @@ int nfs_init_writepagecache(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfs_destroy_writepagecache(void)
|
void __exit nfs_destroy_writepagecache(void)
|
||||||
{
|
{
|
||||||
mempool_destroy(nfs_commit_mempool);
|
mempool_destroy(nfs_commit_mempool);
|
||||||
mempool_destroy(nfs_wdata_mempool);
|
mempool_destroy(nfs_wdata_mempool);
|
||||||
|
|
|
@ -871,8 +871,6 @@ do_kern_mount(const char *fstype, int flags, const char *name, void *data)
|
||||||
return mnt;
|
return mnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(do_kern_mount);
|
|
||||||
|
|
||||||
struct vfsmount *kern_mount(struct file_system_type *type)
|
struct vfsmount *kern_mount(struct file_system_type *type)
|
||||||
{
|
{
|
||||||
return vfs_kern_mount(type, 0, type->name, NULL);
|
return vfs_kern_mount(type, 0, type->name, NULL);
|
||||||
|
|
|
@ -1100,7 +1100,7 @@ struct super_operations {
|
||||||
int (*statfs) (struct dentry *, struct kstatfs *);
|
int (*statfs) (struct dentry *, struct kstatfs *);
|
||||||
int (*remount_fs) (struct super_block *, int *, char *);
|
int (*remount_fs) (struct super_block *, int *, char *);
|
||||||
void (*clear_inode) (struct inode *);
|
void (*clear_inode) (struct inode *);
|
||||||
void (*umount_begin) (struct super_block *);
|
void (*umount_begin) (struct vfsmount *, int);
|
||||||
|
|
||||||
int (*show_options)(struct seq_file *, struct vfsmount *);
|
int (*show_options)(struct seq_file *, struct vfsmount *);
|
||||||
int (*show_stats)(struct seq_file *, struct vfsmount *);
|
int (*show_stats)(struct seq_file *, struct vfsmount *);
|
||||||
|
@ -1767,7 +1767,7 @@ extern struct inode_operations simple_dir_inode_operations;
|
||||||
struct tree_descr { char *name; const struct file_operations *ops; int mode; };
|
struct tree_descr { char *name; const struct file_operations *ops; int mode; };
|
||||||
struct dentry *d_alloc_name(struct dentry *, const char *);
|
struct dentry *d_alloc_name(struct dentry *, const char *);
|
||||||
extern int simple_fill_super(struct super_block *, int, struct tree_descr *);
|
extern int simple_fill_super(struct super_block *, int, struct tree_descr *);
|
||||||
extern int simple_pin_fs(char *name, struct vfsmount **mount, int *count);
|
extern int simple_pin_fs(struct file_system_type *, struct vfsmount **mount, int *count);
|
||||||
extern void simple_release_fs(struct vfsmount **mount, int *count);
|
extern void simple_release_fs(struct vfsmount **mount, int *count);
|
||||||
|
|
||||||
extern ssize_t simple_read_from_buffer(void __user *, size_t, loff_t *, const void *, size_t);
|
extern ssize_t simple_read_from_buffer(void __user *, size_t, loff_t *, const void *, size_t);
|
||||||
|
|
|
@ -49,11 +49,12 @@ struct nlm_host {
|
||||||
h_killed : 1,
|
h_killed : 1,
|
||||||
h_monitored : 1;
|
h_monitored : 1;
|
||||||
wait_queue_head_t h_gracewait; /* wait while reclaiming */
|
wait_queue_head_t h_gracewait; /* wait while reclaiming */
|
||||||
|
struct rw_semaphore h_rwsem; /* Reboot recovery lock */
|
||||||
u32 h_state; /* pseudo-state counter */
|
u32 h_state; /* pseudo-state counter */
|
||||||
u32 h_nsmstate; /* true remote NSM state */
|
u32 h_nsmstate; /* true remote NSM state */
|
||||||
u32 h_pidcount; /* Pseudopids */
|
u32 h_pidcount; /* Pseudopids */
|
||||||
atomic_t h_count; /* reference count */
|
atomic_t h_count; /* reference count */
|
||||||
struct semaphore h_sema; /* mutex for pmap binding */
|
struct mutex h_mutex; /* mutex for pmap binding */
|
||||||
unsigned long h_nextrebind; /* next portmap call */
|
unsigned long h_nextrebind; /* next portmap call */
|
||||||
unsigned long h_expires; /* eligible for GC */
|
unsigned long h_expires; /* eligible for GC */
|
||||||
struct list_head h_lockowners; /* Lockowners for the client */
|
struct list_head h_lockowners; /* Lockowners for the client */
|
||||||
|
@ -219,6 +220,7 @@ static __inline__ int
|
||||||
nlm_compare_locks(const struct file_lock *fl1, const struct file_lock *fl2)
|
nlm_compare_locks(const struct file_lock *fl1, const struct file_lock *fl2)
|
||||||
{
|
{
|
||||||
return fl1->fl_pid == fl2->fl_pid
|
return fl1->fl_pid == fl2->fl_pid
|
||||||
|
&& fl1->fl_owner == fl2->fl_owner
|
||||||
&& fl1->fl_start == fl2->fl_start
|
&& fl1->fl_start == fl2->fl_start
|
||||||
&& fl1->fl_end == fl2->fl_end
|
&& fl1->fl_end == fl2->fl_end
|
||||||
&&(fl1->fl_type == fl2->fl_type || fl2->fl_type == F_UNLCK);
|
&&(fl1->fl_type == fl2->fl_type || fl2->fl_type == F_UNLCK);
|
||||||
|
|
|
@ -28,6 +28,8 @@ struct namespace;
|
||||||
#define MNT_NOATIME 0x08
|
#define MNT_NOATIME 0x08
|
||||||
#define MNT_NODIRATIME 0x10
|
#define MNT_NODIRATIME 0x10
|
||||||
|
|
||||||
|
#define MNT_SHRINKABLE 0x100
|
||||||
|
|
||||||
#define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */
|
#define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */
|
||||||
#define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */
|
#define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */
|
||||||
#define MNT_PNODE_MASK 0x3000 /* propogation flag mask */
|
#define MNT_PNODE_MASK 0x3000 /* propogation flag mask */
|
||||||
|
@ -78,12 +80,18 @@ extern struct vfsmount *alloc_vfsmnt(const char *name);
|
||||||
extern struct vfsmount *do_kern_mount(const char *fstype, int flags,
|
extern struct vfsmount *do_kern_mount(const char *fstype, int flags,
|
||||||
const char *name, void *data);
|
const char *name, void *data);
|
||||||
|
|
||||||
|
struct file_system_type;
|
||||||
|
extern struct vfsmount *vfs_kern_mount(struct file_system_type *type,
|
||||||
|
int flags, const char *name,
|
||||||
|
void *data);
|
||||||
|
|
||||||
struct nameidata;
|
struct nameidata;
|
||||||
|
|
||||||
extern int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd,
|
extern int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd,
|
||||||
int mnt_flags, struct list_head *fslist);
|
int mnt_flags, struct list_head *fslist);
|
||||||
|
|
||||||
extern void mark_mounts_for_expiry(struct list_head *mounts);
|
extern void mark_mounts_for_expiry(struct list_head *mounts);
|
||||||
|
extern void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts);
|
||||||
|
|
||||||
extern spinlock_t vfsmount_lock;
|
extern spinlock_t vfsmount_lock;
|
||||||
extern dev_t name_to_dev_t(char *name);
|
extern dev_t name_to_dev_t(char *name);
|
||||||
|
|
|
@ -384,6 +384,7 @@ enum {
|
||||||
NFSPROC4_CLNT_DELEGRETURN,
|
NFSPROC4_CLNT_DELEGRETURN,
|
||||||
NFSPROC4_CLNT_GETACL,
|
NFSPROC4_CLNT_GETACL,
|
||||||
NFSPROC4_CLNT_SETACL,
|
NFSPROC4_CLNT_SETACL,
|
||||||
|
NFSPROC4_CLNT_FS_LOCATIONS,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -9,6 +9,27 @@
|
||||||
#ifndef _LINUX_NFS_FS_H
|
#ifndef _LINUX_NFS_FS_H
|
||||||
#define _LINUX_NFS_FS_H
|
#define _LINUX_NFS_FS_H
|
||||||
|
|
||||||
|
#include <linux/config.h>
|
||||||
|
#include <linux/in.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/pagemap.h>
|
||||||
|
#include <linux/rwsem.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
|
||||||
|
#include <linux/sunrpc/debug.h>
|
||||||
|
#include <linux/sunrpc/auth.h>
|
||||||
|
#include <linux/sunrpc/clnt.h>
|
||||||
|
|
||||||
|
#include <linux/nfs.h>
|
||||||
|
#include <linux/nfs2.h>
|
||||||
|
#include <linux/nfs3.h>
|
||||||
|
#include <linux/nfs4.h>
|
||||||
|
#include <linux/nfs_xdr.h>
|
||||||
|
|
||||||
|
#include <linux/nfs_fs_sb.h>
|
||||||
|
|
||||||
|
#include <linux/rwsem.h>
|
||||||
|
#include <linux/mempool.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable debugging support for nfs client.
|
* Enable debugging support for nfs client.
|
||||||
|
@ -41,27 +62,9 @@
|
||||||
#define FLUSH_LOWPRI 8 /* low priority background flush */
|
#define FLUSH_LOWPRI 8 /* low priority background flush */
|
||||||
#define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */
|
#define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */
|
||||||
#define FLUSH_NOCOMMIT 32 /* Don't send the NFSv3/v4 COMMIT */
|
#define FLUSH_NOCOMMIT 32 /* Don't send the NFSv3/v4 COMMIT */
|
||||||
|
#define FLUSH_INVALIDATE 64 /* Invalidate the page cache */
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
#include <linux/in.h>
|
|
||||||
#include <linux/mm.h>
|
|
||||||
#include <linux/pagemap.h>
|
|
||||||
#include <linux/rwsem.h>
|
|
||||||
#include <linux/wait.h>
|
|
||||||
|
|
||||||
#include <linux/nfs_fs_sb.h>
|
|
||||||
|
|
||||||
#include <linux/sunrpc/debug.h>
|
|
||||||
#include <linux/sunrpc/auth.h>
|
|
||||||
#include <linux/sunrpc/clnt.h>
|
|
||||||
|
|
||||||
#include <linux/nfs.h>
|
|
||||||
#include <linux/nfs2.h>
|
|
||||||
#include <linux/nfs3.h>
|
|
||||||
#include <linux/nfs4.h>
|
|
||||||
#include <linux/nfs_xdr.h>
|
|
||||||
#include <linux/rwsem.h>
|
|
||||||
#include <linux/mempool.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NFSv3/v4 Access mode cache entry
|
* NFSv3/v4 Access mode cache entry
|
||||||
|
@ -233,8 +236,12 @@ static inline int nfs_caches_unstable(struct inode *inode)
|
||||||
|
|
||||||
static inline void nfs_mark_for_revalidate(struct inode *inode)
|
static inline void nfs_mark_for_revalidate(struct inode *inode)
|
||||||
{
|
{
|
||||||
|
struct nfs_inode *nfsi = NFS_I(inode);
|
||||||
|
|
||||||
spin_lock(&inode->i_lock);
|
spin_lock(&inode->i_lock);
|
||||||
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS;
|
nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS;
|
||||||
|
if (S_ISDIR(inode->i_mode))
|
||||||
|
nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA;
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,7 +303,7 @@ extern int nfs_release(struct inode *, struct file *);
|
||||||
extern int nfs_attribute_timeout(struct inode *inode);
|
extern int nfs_attribute_timeout(struct inode *inode);
|
||||||
extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
|
extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
|
||||||
extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
|
extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
|
||||||
extern void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
|
extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
|
||||||
extern int nfs_setattr(struct dentry *, struct iattr *);
|
extern int nfs_setattr(struct dentry *, struct iattr *);
|
||||||
extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
|
extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
|
||||||
extern void nfs_begin_attr_update(struct inode *);
|
extern void nfs_begin_attr_update(struct inode *);
|
||||||
|
@ -306,6 +313,10 @@ extern void nfs_end_data_update(struct inode *);
|
||||||
extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
|
extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
|
||||||
extern void put_nfs_open_context(struct nfs_open_context *ctx);
|
extern void put_nfs_open_context(struct nfs_open_context *ctx);
|
||||||
extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode);
|
extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode);
|
||||||
|
extern struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
|
||||||
|
const struct dentry *dentry,
|
||||||
|
struct nfs_fh *fh,
|
||||||
|
struct nfs_fattr *fattr);
|
||||||
|
|
||||||
/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
|
/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
|
||||||
extern u32 root_nfs_parse_addr(char *name); /*__init*/
|
extern u32 root_nfs_parse_addr(char *name); /*__init*/
|
||||||
|
@ -391,6 +402,15 @@ extern void nfs_unregister_sysctl(void);
|
||||||
#define nfs_unregister_sysctl() do { } while(0)
|
#define nfs_unregister_sysctl() do { } while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* linux/fs/nfs/namespace.c
|
||||||
|
*/
|
||||||
|
extern struct list_head nfs_automount_list;
|
||||||
|
extern struct inode_operations nfs_mountpoint_inode_operations;
|
||||||
|
extern struct inode_operations nfs_referral_inode_operations;
|
||||||
|
extern int nfs_mountpoint_expiry_timeout;
|
||||||
|
extern void nfs_release_automount_timer(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* linux/fs/nfs/unlink.c
|
* linux/fs/nfs/unlink.c
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -35,6 +35,7 @@ struct nfs_server {
|
||||||
char * hostname; /* remote hostname */
|
char * hostname; /* remote hostname */
|
||||||
struct nfs_fh fh;
|
struct nfs_fh fh;
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
|
struct nfs_fsid fsid;
|
||||||
unsigned long mount_time; /* when this fs was mounted */
|
unsigned long mount_time; /* when this fs was mounted */
|
||||||
#ifdef CONFIG_NFS_V4
|
#ifdef CONFIG_NFS_V4
|
||||||
/* Our own IP address, as a null-terminated string.
|
/* Our own IP address, as a null-terminated string.
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
#include <linux/nfs_fs_sb.h>
|
|
||||||
#include <linux/sunrpc/auth.h>
|
#include <linux/sunrpc/auth.h>
|
||||||
#include <linux/nfs_xdr.h>
|
#include <linux/nfs_xdr.h>
|
||||||
|
|
||||||
|
@ -63,8 +62,8 @@ extern void nfs_release_request(struct nfs_page *req);
|
||||||
|
|
||||||
extern int nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst,
|
extern int nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst,
|
||||||
unsigned long idx_start, unsigned int npages);
|
unsigned long idx_start, unsigned int npages);
|
||||||
extern int nfs_scan_list(struct list_head *, struct list_head *,
|
extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, struct list_head *dst,
|
||||||
unsigned long, unsigned int);
|
unsigned long idx_start, unsigned int npages);
|
||||||
extern int nfs_coalesce_requests(struct list_head *, struct list_head *,
|
extern int nfs_coalesce_requests(struct list_head *, struct list_head *,
|
||||||
unsigned int);
|
unsigned int);
|
||||||
extern int nfs_wait_on_request(struct nfs_page *);
|
extern int nfs_wait_on_request(struct nfs_page *);
|
||||||
|
|
|
@ -14,11 +14,19 @@
|
||||||
#define NFS_DEF_FILE_IO_SIZE (4096U)
|
#define NFS_DEF_FILE_IO_SIZE (4096U)
|
||||||
#define NFS_MIN_FILE_IO_SIZE (1024U)
|
#define NFS_MIN_FILE_IO_SIZE (1024U)
|
||||||
|
|
||||||
struct nfs4_fsid {
|
struct nfs_fsid {
|
||||||
__u64 major;
|
uint64_t major;
|
||||||
__u64 minor;
|
uint64_t minor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper for checking equality between 2 fsids.
|
||||||
|
*/
|
||||||
|
static inline int nfs_fsid_equal(const struct nfs_fsid *a, const struct nfs_fsid *b)
|
||||||
|
{
|
||||||
|
return a->major == b->major && a->minor == b->minor;
|
||||||
|
}
|
||||||
|
|
||||||
struct nfs_fattr {
|
struct nfs_fattr {
|
||||||
unsigned short valid; /* which fields are valid */
|
unsigned short valid; /* which fields are valid */
|
||||||
__u64 pre_size; /* pre_op_attr.size */
|
__u64 pre_size; /* pre_op_attr.size */
|
||||||
|
@ -40,10 +48,7 @@ struct nfs_fattr {
|
||||||
} nfs3;
|
} nfs3;
|
||||||
} du;
|
} du;
|
||||||
dev_t rdev;
|
dev_t rdev;
|
||||||
union {
|
struct nfs_fsid fsid;
|
||||||
__u64 nfs3; /* also nfs2 */
|
|
||||||
struct nfs4_fsid nfs4;
|
|
||||||
} fsid_u;
|
|
||||||
__u64 fileid;
|
__u64 fileid;
|
||||||
struct timespec atime;
|
struct timespec atime;
|
||||||
struct timespec mtime;
|
struct timespec mtime;
|
||||||
|
@ -57,8 +62,8 @@ struct nfs_fattr {
|
||||||
#define NFS_ATTR_WCC 0x0001 /* pre-op WCC data */
|
#define NFS_ATTR_WCC 0x0001 /* pre-op WCC data */
|
||||||
#define NFS_ATTR_FATTR 0x0002 /* post-op attributes */
|
#define NFS_ATTR_FATTR 0x0002 /* post-op attributes */
|
||||||
#define NFS_ATTR_FATTR_V3 0x0004 /* NFSv3 attributes */
|
#define NFS_ATTR_FATTR_V3 0x0004 /* NFSv3 attributes */
|
||||||
#define NFS_ATTR_FATTR_V4 0x0008
|
#define NFS_ATTR_FATTR_V4 0x0008 /* NFSv4 change attribute */
|
||||||
#define NFS_ATTR_PRE_CHANGE 0x0010
|
#define NFS_ATTR_FATTR_V4_REFERRAL 0x0010 /* NFSv4 referral */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Info on the file system
|
* Info on the file system
|
||||||
|
@ -675,6 +680,40 @@ struct nfs4_server_caps_res {
|
||||||
u32 has_symlinks;
|
u32 has_symlinks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct nfs4_string {
|
||||||
|
unsigned int len;
|
||||||
|
char *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NFS4_PATHNAME_MAXCOMPONENTS 512
|
||||||
|
struct nfs4_pathname {
|
||||||
|
unsigned int ncomponents;
|
||||||
|
struct nfs4_string components[NFS4_PATHNAME_MAXCOMPONENTS];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NFS4_FS_LOCATION_MAXSERVERS 10
|
||||||
|
struct nfs4_fs_location {
|
||||||
|
unsigned int nservers;
|
||||||
|
struct nfs4_string servers[NFS4_FS_LOCATION_MAXSERVERS];
|
||||||
|
struct nfs4_pathname rootpath;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NFS4_FS_LOCATIONS_MAXENTRIES 10
|
||||||
|
struct nfs4_fs_locations {
|
||||||
|
struct nfs_fattr fattr;
|
||||||
|
const struct nfs_server *server;
|
||||||
|
struct nfs4_pathname fs_path;
|
||||||
|
int nlocations;
|
||||||
|
struct nfs4_fs_location locations[NFS4_FS_LOCATIONS_MAXENTRIES];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nfs4_fs_locations_arg {
|
||||||
|
const struct nfs_fh *dir_fh;
|
||||||
|
const struct qstr *name;
|
||||||
|
struct page *page;
|
||||||
|
const u32 *bitmask;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* CONFIG_NFS_V4 */
|
#endif /* CONFIG_NFS_V4 */
|
||||||
|
|
||||||
struct nfs_page;
|
struct nfs_page;
|
||||||
|
@ -695,7 +734,7 @@ struct nfs_read_data {
|
||||||
#ifdef CONFIG_NFS_V4
|
#ifdef CONFIG_NFS_V4
|
||||||
unsigned long timestamp; /* For lease renewal */
|
unsigned long timestamp; /* For lease renewal */
|
||||||
#endif
|
#endif
|
||||||
struct page *page_array[NFS_PAGEVEC_SIZE + 1];
|
struct page *page_array[NFS_PAGEVEC_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nfs_write_data {
|
struct nfs_write_data {
|
||||||
|
@ -713,7 +752,7 @@ struct nfs_write_data {
|
||||||
#ifdef CONFIG_NFS_V4
|
#ifdef CONFIG_NFS_V4
|
||||||
unsigned long timestamp; /* For lease renewal */
|
unsigned long timestamp; /* For lease renewal */
|
||||||
#endif
|
#endif
|
||||||
struct page *page_array[NFS_PAGEVEC_SIZE + 1];
|
struct page *page_array[NFS_PAGEVEC_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nfs_access_entry;
|
struct nfs_access_entry;
|
||||||
|
|
|
@ -194,6 +194,7 @@ extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
|
||||||
extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p);
|
extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p);
|
||||||
extern uint32_t *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
|
extern uint32_t *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
|
||||||
extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
|
extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
|
||||||
|
extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
|
|
|
@ -2255,7 +2255,7 @@ static int __init init_tmpfs(void)
|
||||||
#ifdef CONFIG_TMPFS
|
#ifdef CONFIG_TMPFS
|
||||||
devfs_mk_dir("shm");
|
devfs_mk_dir("shm");
|
||||||
#endif
|
#endif
|
||||||
shm_mnt = do_kern_mount(tmpfs_fs_type.name, MS_NOUSER,
|
shm_mnt = vfs_kern_mount(&tmpfs_fs_type, MS_NOUSER,
|
||||||
tmpfs_fs_type.name, NULL);
|
tmpfs_fs_type.name, NULL);
|
||||||
if (IS_ERR(shm_mnt)) {
|
if (IS_ERR(shm_mnt)) {
|
||||||
error = PTR_ERR(shm_mnt);
|
error = PTR_ERR(shm_mnt);
|
||||||
|
|
|
@ -118,6 +118,8 @@ struct rpc_auth null_auth = {
|
||||||
.au_cslack = 4,
|
.au_cslack = 4,
|
||||||
.au_rslack = 2,
|
.au_rslack = 2,
|
||||||
.au_ops = &authnull_ops,
|
.au_ops = &authnull_ops,
|
||||||
|
.au_flavor = RPC_AUTH_NULL,
|
||||||
|
.au_count = ATOMIC_INIT(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|
|
@ -225,6 +225,7 @@ struct rpc_auth unix_auth = {
|
||||||
.au_cslack = UNX_WRITESLACK,
|
.au_cslack = UNX_WRITESLACK,
|
||||||
.au_rslack = 2, /* assume AUTH_NULL verf */
|
.au_rslack = 2, /* assume AUTH_NULL verf */
|
||||||
.au_ops = &authunix_ops,
|
.au_ops = &authunix_ops,
|
||||||
|
.au_flavor = RPC_AUTH_UNIX,
|
||||||
.au_count = ATOMIC_INIT(0),
|
.au_count = ATOMIC_INIT(0),
|
||||||
.au_credcache = &unix_cred_cache,
|
.au_credcache = &unix_cred_cache,
|
||||||
};
|
};
|
||||||
|
|
|
@ -439,7 +439,7 @@ struct vfsmount *rpc_get_mount(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = simple_pin_fs("rpc_pipefs", &rpc_mount, &rpc_mount_count);
|
err = simple_pin_fs(&rpc_pipe_fs_type, &rpc_mount, &rpc_mount_count);
|
||||||
if (err != 0)
|
if (err != 0)
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
return rpc_mount;
|
return rpc_mount;
|
||||||
|
|
|
@ -568,8 +568,7 @@ EXPORT_SYMBOL(xdr_inline_decode);
|
||||||
*
|
*
|
||||||
* Moves data beyond the current pointer position from the XDR head[] buffer
|
* Moves data beyond the current pointer position from the XDR head[] buffer
|
||||||
* into the page list. Any data that lies beyond current position + "len"
|
* into the page list. Any data that lies beyond current position + "len"
|
||||||
* bytes is moved into the XDR tail[]. The current pointer is then
|
* bytes is moved into the XDR tail[].
|
||||||
* repositioned at the beginning of the XDR tail.
|
|
||||||
*/
|
*/
|
||||||
void xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
|
void xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
|
||||||
{
|
{
|
||||||
|
@ -606,6 +605,31 @@ void xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(xdr_read_pages);
|
EXPORT_SYMBOL(xdr_read_pages);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xdr_enter_page - decode data from the XDR page
|
||||||
|
* @xdr: pointer to xdr_stream struct
|
||||||
|
* @len: number of bytes of page data
|
||||||
|
*
|
||||||
|
* Moves data beyond the current pointer position from the XDR head[] buffer
|
||||||
|
* into the page list. Any data that lies beyond current position + "len"
|
||||||
|
* bytes is moved into the XDR tail[]. The current pointer is then
|
||||||
|
* repositioned at the beginning of the first XDR page.
|
||||||
|
*/
|
||||||
|
void xdr_enter_page(struct xdr_stream *xdr, unsigned int len)
|
||||||
|
{
|
||||||
|
char * kaddr = page_address(xdr->buf->pages[0]);
|
||||||
|
xdr_read_pages(xdr, len);
|
||||||
|
/*
|
||||||
|
* Position current pointer at beginning of tail, and
|
||||||
|
* set remaining message length.
|
||||||
|
*/
|
||||||
|
if (len > PAGE_CACHE_SIZE - xdr->buf->page_base)
|
||||||
|
len = PAGE_CACHE_SIZE - xdr->buf->page_base;
|
||||||
|
xdr->p = (uint32_t *)(kaddr + xdr->buf->page_base);
|
||||||
|
xdr->end = (uint32_t *)((char *)xdr->p + len);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(xdr_enter_page);
|
||||||
|
|
||||||
static struct kvec empty_iov = {.iov_base = NULL, .iov_len = 0};
|
static struct kvec empty_iov = {.iov_base = NULL, .iov_len = 0};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/random.h>
|
#include <linux/net.h>
|
||||||
|
|
||||||
#include <linux/sunrpc/clnt.h>
|
#include <linux/sunrpc/clnt.h>
|
||||||
#include <linux/sunrpc/metrics.h>
|
#include <linux/sunrpc/metrics.h>
|
||||||
|
@ -830,7 +830,7 @@ static inline u32 xprt_alloc_xid(struct rpc_xprt *xprt)
|
||||||
|
|
||||||
static inline void xprt_init_xid(struct rpc_xprt *xprt)
|
static inline void xprt_init_xid(struct rpc_xprt *xprt)
|
||||||
{
|
{
|
||||||
get_random_bytes(&xprt->xid, sizeof(xprt->xid));
|
xprt->xid = net_random();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
|
static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
|
||||||
|
|
|
@ -930,6 +930,13 @@ static void xs_udp_timer(struct rpc_task *task)
|
||||||
xprt_adjust_cwnd(task, -ETIMEDOUT);
|
xprt_adjust_cwnd(task, -ETIMEDOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned short xs_get_random_port(void)
|
||||||
|
{
|
||||||
|
unsigned short range = xprt_max_resvport - xprt_min_resvport;
|
||||||
|
unsigned short rand = (unsigned short) net_random() % range;
|
||||||
|
return rand + xprt_min_resvport;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xs_set_port - reset the port number in the remote endpoint address
|
* xs_set_port - reset the port number in the remote endpoint address
|
||||||
* @xprt: generic transport
|
* @xprt: generic transport
|
||||||
|
@ -1275,7 +1282,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to)
|
||||||
memset(xprt->slot, 0, slot_table_size);
|
memset(xprt->slot, 0, slot_table_size);
|
||||||
|
|
||||||
xprt->prot = IPPROTO_UDP;
|
xprt->prot = IPPROTO_UDP;
|
||||||
xprt->port = xprt_max_resvport;
|
xprt->port = xs_get_random_port();
|
||||||
xprt->tsh_size = 0;
|
xprt->tsh_size = 0;
|
||||||
xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
|
xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
|
||||||
/* XXX: header size can vary due to auth type, IPv6, etc. */
|
/* XXX: header size can vary due to auth type, IPv6, etc. */
|
||||||
|
@ -1317,7 +1324,7 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to)
|
||||||
memset(xprt->slot, 0, slot_table_size);
|
memset(xprt->slot, 0, slot_table_size);
|
||||||
|
|
||||||
xprt->prot = IPPROTO_TCP;
|
xprt->prot = IPPROTO_TCP;
|
||||||
xprt->port = xprt_max_resvport;
|
xprt->port = xs_get_random_port();
|
||||||
xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32);
|
xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32);
|
||||||
xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
|
xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
|
||||||
xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
|
xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
|
||||||
|
|
|
@ -224,7 +224,7 @@ struct dentry *securityfs_create_file(const char *name, mode_t mode,
|
||||||
|
|
||||||
pr_debug("securityfs: creating file '%s'\n",name);
|
pr_debug("securityfs: creating file '%s'\n",name);
|
||||||
|
|
||||||
error = simple_pin_fs("securityfs", &mount, &mount_count);
|
error = simple_pin_fs(&fs_type, &mount, &mount_count);
|
||||||
if (error) {
|
if (error) {
|
||||||
dentry = ERR_PTR(error);
|
dentry = ERR_PTR(error);
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
Loading…
Reference in New Issue