mirror of https://gitee.com/openkylin/linux.git
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
|
@ -19,7 +19,7 @@ following procedure:
|
|||
|
||||
(2) Have the follow_link() op do the following steps:
|
||||
|
||||
(a) Call do_kern_mount() to call the appropriate filesystem to set up a
|
||||
(a) Call vfs_kern_mount() to call the appropriate filesystem to set up a
|
||||
superblock and gain a vfsmount structure representing it.
|
||||
|
||||
(b) Copy the nameidata provided as an argument and substitute the dentry
|
||||
|
|
|
@ -569,7 +569,7 @@ static int create_special_files (void)
|
|||
ignore_mount = 1;
|
||||
|
||||
/* create the devices special file */
|
||||
retval = simple_pin_fs("usbfs", &usbfs_mount, &usbfs_mount_count);
|
||||
retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count);
|
||||
if (retval) {
|
||||
err ("Unable to get usbfs mount");
|
||||
goto exit;
|
||||
|
|
|
@ -256,11 +256,12 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt)
|
|||
}
|
||||
|
||||
static void
|
||||
v9fs_umount_begin(struct super_block *sb)
|
||||
v9fs_umount_begin(struct vfsmount *vfsmnt, int flags)
|
||||
{
|
||||
struct v9fs_session_info *v9ses = sb->s_fs_info;
|
||||
struct v9fs_session_info *v9ses = vfsmnt->mnt_sb->s_fs_info;
|
||||
|
||||
v9fs_session_cancel(v9ses);
|
||||
if (flags & MNT_FORCE)
|
||||
v9fs_session_cancel(v9ses);
|
||||
}
|
||||
|
||||
static struct super_operations v9fs_super_ops = {
|
||||
|
|
|
@ -203,7 +203,7 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
|
|||
|
||||
/* try and do the mount */
|
||||
kdebug("--- attempting mount %s -o %s ---", devname, options);
|
||||
mnt = do_kern_mount("afs", 0, devname, options);
|
||||
mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options);
|
||||
kdebug("--- mount result %p ---", mnt);
|
||||
|
||||
free_page((unsigned long) devname);
|
||||
|
|
|
@ -48,7 +48,7 @@ static void afs_put_super(struct super_block *sb);
|
|||
|
||||
static void afs_destroy_inode(struct inode *inode);
|
||||
|
||||
static struct file_system_type afs_fs_type = {
|
||||
struct file_system_type afs_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "afs",
|
||||
.get_sb = afs_get_sb,
|
||||
|
|
|
@ -38,6 +38,8 @@ static inline struct afs_super_info *AFS_FS_S(struct super_block *sb)
|
|||
return sb->s_fs_info;
|
||||
}
|
||||
|
||||
extern struct file_system_type afs_fs_type;
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _LINUX_AFS_SUPER_H */
|
||||
|
|
|
@ -55,6 +55,7 @@ typedef struct {
|
|||
} Node;
|
||||
|
||||
static DEFINE_RWLOCK(entries_lock);
|
||||
static struct file_system_type bm_fs_type;
|
||||
static struct vfsmount *bm_mnt;
|
||||
static int entry_count;
|
||||
|
||||
|
@ -637,7 +638,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
|
|||
if (!inode)
|
||||
goto out2;
|
||||
|
||||
err = simple_pin_fs("binfmt_misc", &bm_mnt, &entry_count);
|
||||
err = simple_pin_fs(&bm_fs_type, &bm_mnt, &entry_count);
|
||||
if (err) {
|
||||
iput(inode);
|
||||
inode = NULL;
|
||||
|
|
|
@ -403,12 +403,14 @@ static struct quotactl_ops cifs_quotactl_ops = {
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
static void cifs_umount_begin(struct super_block * sblock)
|
||||
static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo * tcon;
|
||||
|
||||
cifs_sb = CIFS_SB(sblock);
|
||||
if (!(flags & MNT_FORCE))
|
||||
return;
|
||||
cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
|
||||
if(cifs_sb == NULL)
|
||||
return;
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ static struct file_system_type configfs_fs_type = {
|
|||
|
||||
int configfs_pin_fs(void)
|
||||
{
|
||||
return simple_pin_fs("configfs", &configfs_mount,
|
||||
return simple_pin_fs(&configfs_fs_type, &configfs_mount,
|
||||
&configfs_mnt_count);
|
||||
}
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ struct dentry *debugfs_create_file(const char *name, mode_t mode,
|
|||
|
||||
pr_debug("debugfs: creating file '%s'\n",name);
|
||||
|
||||
error = simple_pin_fs("debugfs", &debugfs_mount, &debugfs_mount_count);
|
||||
error = simple_pin_fs(&debug_fs_type, &debugfs_mount, &debugfs_mount_count);
|
||||
if (error)
|
||||
goto exit;
|
||||
|
||||
|
|
|
@ -198,9 +198,10 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
|
|||
return inode;
|
||||
}
|
||||
|
||||
static void fuse_umount_begin(struct super_block *sb)
|
||||
static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags)
|
||||
{
|
||||
fuse_abort_conn(get_fuse_conn_super(sb));
|
||||
if (flags & MNT_FORCE)
|
||||
fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb));
|
||||
}
|
||||
|
||||
static void fuse_put_super(struct super_block *sb)
|
||||
|
|
|
@ -424,13 +424,13 @@ int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files
|
|||
|
||||
static DEFINE_SPINLOCK(pin_fs_lock);
|
||||
|
||||
int simple_pin_fs(char *name, struct vfsmount **mount, int *count)
|
||||
int simple_pin_fs(struct file_system_type *type, struct vfsmount **mount, int *count)
|
||||
{
|
||||
struct vfsmount *mnt = NULL;
|
||||
spin_lock(&pin_fs_lock);
|
||||
if (unlikely(!*mount)) {
|
||||
spin_unlock(&pin_fs_lock);
|
||||
mnt = do_kern_mount(name, 0, name, NULL);
|
||||
mnt = vfs_kern_mount(type, 0, type->name, NULL);
|
||||
if (IS_ERR(mnt))
|
||||
return PTR_ERR(mnt);
|
||||
spin_lock(&pin_fs_lock);
|
||||
|
|
|
@ -147,11 +147,10 @@ u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
|
|||
* Someone has sent us an SM_NOTIFY. Ensure we bind to the new port number,
|
||||
* that we mark locks for reclaiming, and that we bump the pseudo NSM state.
|
||||
*/
|
||||
static inline
|
||||
void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
|
||||
static void nlmclnt_prepare_reclaim(struct nlm_host *host)
|
||||
{
|
||||
down_write(&host->h_rwsem);
|
||||
host->h_monitored = 0;
|
||||
host->h_nsmstate = newstate;
|
||||
host->h_state++;
|
||||
host->h_nextrebind = 0;
|
||||
nlm_rebind_host(host);
|
||||
|
@ -164,6 +163,13 @@ void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
|
|||
dprintk("NLM: reclaiming locks for host %s", host->h_name);
|
||||
}
|
||||
|
||||
static void nlmclnt_finish_reclaim(struct nlm_host *host)
|
||||
{
|
||||
host->h_reclaiming = 0;
|
||||
up_write(&host->h_rwsem);
|
||||
dprintk("NLM: done reclaiming locks for host %s", host->h_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reclaim all locks on server host. We do this by spawning a separate
|
||||
* reclaimer thread.
|
||||
|
@ -171,12 +177,10 @@ void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
|
|||
void
|
||||
nlmclnt_recovery(struct nlm_host *host, u32 newstate)
|
||||
{
|
||||
if (host->h_reclaiming++) {
|
||||
if (host->h_nsmstate == newstate)
|
||||
return;
|
||||
nlmclnt_prepare_reclaim(host, newstate);
|
||||
} else {
|
||||
nlmclnt_prepare_reclaim(host, newstate);
|
||||
if (host->h_nsmstate == newstate)
|
||||
return;
|
||||
host->h_nsmstate = newstate;
|
||||
if (!host->h_reclaiming++) {
|
||||
nlm_get_host(host);
|
||||
__module_get(THIS_MODULE);
|
||||
if (kernel_thread(reclaimer, host, CLONE_KERNEL) < 0)
|
||||
|
@ -190,6 +194,7 @@ reclaimer(void *ptr)
|
|||
struct nlm_host *host = (struct nlm_host *) ptr;
|
||||
struct nlm_wait *block;
|
||||
struct file_lock *fl, *next;
|
||||
u32 nsmstate;
|
||||
|
||||
daemonize("%s-reclaim", host->h_name);
|
||||
allow_signal(SIGKILL);
|
||||
|
@ -199,19 +204,25 @@ reclaimer(void *ptr)
|
|||
lock_kernel();
|
||||
lockd_up();
|
||||
|
||||
nlmclnt_prepare_reclaim(host);
|
||||
/* First, reclaim all locks that have been marked. */
|
||||
restart:
|
||||
nsmstate = host->h_nsmstate;
|
||||
list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
|
||||
list_del_init(&fl->fl_u.nfs_fl.list);
|
||||
|
||||
if (signalled())
|
||||
continue;
|
||||
if (nlmclnt_reclaim(host, fl) == 0)
|
||||
list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
|
||||
goto restart;
|
||||
if (nlmclnt_reclaim(host, fl) != 0)
|
||||
continue;
|
||||
list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
|
||||
if (host->h_nsmstate != nsmstate) {
|
||||
/* Argh! The server rebooted again! */
|
||||
list_splice_init(&host->h_granted, &host->h_reclaim);
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
||||
host->h_reclaiming = 0;
|
||||
nlmclnt_finish_reclaim(host);
|
||||
|
||||
/* Now, wake up all processes that sleep on a blocked lock */
|
||||
list_for_each_entry(block, &nlm_blocked, b_list) {
|
||||
|
|
|
@ -508,7 +508,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
|
|||
}
|
||||
|
||||
block = nlmclnt_prepare_block(host, fl);
|
||||
again:
|
||||
for(;;) {
|
||||
/* Reboot protection */
|
||||
fl->fl_u.nfs_fl.state = host->h_state;
|
||||
status = nlmclnt_call(req, NLMPROC_LOCK);
|
||||
if (status < 0)
|
||||
goto out_unblock;
|
||||
|
@ -531,10 +534,16 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
|
|||
}
|
||||
|
||||
if (resp->status == NLM_LCK_GRANTED) {
|
||||
fl->fl_u.nfs_fl.state = host->h_state;
|
||||
down_read(&host->h_rwsem);
|
||||
/* Check whether or not the server has rebooted */
|
||||
if (fl->fl_u.nfs_fl.state != host->h_state) {
|
||||
up_read(&host->h_rwsem);
|
||||
goto again;
|
||||
}
|
||||
fl->fl_flags |= FL_SLEEP;
|
||||
/* Ensure the resulting lock will get added to granted list */
|
||||
do_vfs_lock(fl);
|
||||
up_read(&host->h_rwsem);
|
||||
}
|
||||
status = nlm_stat_to_errno(resp->status);
|
||||
out_unblock:
|
||||
|
@ -596,6 +605,7 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl)
|
|||
static int
|
||||
nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
|
||||
{
|
||||
struct nlm_host *host = req->a_host;
|
||||
struct nlm_res *resp = &req->a_res;
|
||||
int status;
|
||||
|
||||
|
@ -604,7 +614,9 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
|
|||
* request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
|
||||
* case, we want to unlock.
|
||||
*/
|
||||
down_read(&host->h_rwsem);
|
||||
do_vfs_lock(fl);
|
||||
up_read(&host->h_rwsem);
|
||||
|
||||
if (req->a_flags & RPC_TASK_ASYNC)
|
||||
return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
|
||||
|
|
|
@ -112,11 +112,12 @@ nlm_lookup_host(int server, struct sockaddr_in *sin,
|
|||
host->h_version = version;
|
||||
host->h_proto = proto;
|
||||
host->h_rpcclnt = NULL;
|
||||
init_MUTEX(&host->h_sema);
|
||||
mutex_init(&host->h_mutex);
|
||||
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
|
||||
host->h_expires = jiffies + NLM_HOST_EXPIRE;
|
||||
atomic_set(&host->h_count, 1);
|
||||
init_waitqueue_head(&host->h_gracewait);
|
||||
init_rwsem(&host->h_rwsem);
|
||||
host->h_state = 0; /* pseudo NSM state */
|
||||
host->h_nsmstate = 0; /* real NSM state */
|
||||
host->h_server = server;
|
||||
|
@ -172,7 +173,7 @@ nlm_bind_host(struct nlm_host *host)
|
|||
(unsigned)ntohl(host->h_addr.sin_addr.s_addr));
|
||||
|
||||
/* Lock host handle */
|
||||
down(&host->h_sema);
|
||||
mutex_lock(&host->h_mutex);
|
||||
|
||||
/* If we've already created an RPC client, check whether
|
||||
* RPC rebind is required
|
||||
|
@ -204,12 +205,12 @@ nlm_bind_host(struct nlm_host *host)
|
|||
host->h_rpcclnt = clnt;
|
||||
}
|
||||
|
||||
up(&host->h_sema);
|
||||
mutex_unlock(&host->h_mutex);
|
||||
return clnt;
|
||||
|
||||
forgetit:
|
||||
printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
|
||||
up(&host->h_sema);
|
||||
mutex_unlock(&host->h_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
134
fs/namespace.c
134
fs/namespace.c
|
@ -585,8 +585,8 @@ static int do_umount(struct vfsmount *mnt, int flags)
|
|||
*/
|
||||
|
||||
lock_kernel();
|
||||
if ((flags & MNT_FORCE) && sb->s_op->umount_begin)
|
||||
sb->s_op->umount_begin(sb);
|
||||
if (sb->s_op->umount_begin)
|
||||
sb->s_op->umount_begin(mnt, flags);
|
||||
unlock_kernel();
|
||||
|
||||
/*
|
||||
|
@ -1171,6 +1171,40 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* go through the vfsmounts we've just consigned to the graveyard to
|
||||
* - check that they're still dead
|
||||
* - delete the vfsmount from the appropriate namespace under lock
|
||||
* - dispose of the corpse
|
||||
*/
|
||||
static void expire_mount_list(struct list_head *graveyard, struct list_head *mounts)
|
||||
{
|
||||
struct namespace *namespace;
|
||||
struct vfsmount *mnt;
|
||||
|
||||
while (!list_empty(graveyard)) {
|
||||
LIST_HEAD(umounts);
|
||||
mnt = list_entry(graveyard->next, struct vfsmount, mnt_expire);
|
||||
list_del_init(&mnt->mnt_expire);
|
||||
|
||||
/* don't do anything if the namespace is dead - all the
|
||||
* vfsmounts from it are going away anyway */
|
||||
namespace = mnt->mnt_namespace;
|
||||
if (!namespace || !namespace->root)
|
||||
continue;
|
||||
get_namespace(namespace);
|
||||
|
||||
spin_unlock(&vfsmount_lock);
|
||||
down_write(&namespace_sem);
|
||||
expire_mount(mnt, mounts, &umounts);
|
||||
up_write(&namespace_sem);
|
||||
release_mounts(&umounts);
|
||||
mntput(mnt);
|
||||
put_namespace(namespace);
|
||||
spin_lock(&vfsmount_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* process a list of expirable mountpoints with the intent of discarding any
|
||||
* mountpoints that aren't in use and haven't been touched since last we came
|
||||
|
@ -1178,7 +1212,6 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts,
|
|||
*/
|
||||
void mark_mounts_for_expiry(struct list_head *mounts)
|
||||
{
|
||||
struct namespace *namespace;
|
||||
struct vfsmount *mnt, *next;
|
||||
LIST_HEAD(graveyard);
|
||||
|
||||
|
@ -1202,39 +1235,80 @@ void mark_mounts_for_expiry(struct list_head *mounts)
|
|||
list_move(&mnt->mnt_expire, &graveyard);
|
||||
}
|
||||
|
||||
/*
|
||||
* go through the vfsmounts we've just consigned to the graveyard to
|
||||
* - check that they're still dead
|
||||
* - delete the vfsmount from the appropriate namespace under lock
|
||||
* - dispose of the corpse
|
||||
*/
|
||||
while (!list_empty(&graveyard)) {
|
||||
LIST_HEAD(umounts);
|
||||
mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire);
|
||||
list_del_init(&mnt->mnt_expire);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
expire_mount_list(&graveyard, mounts);
|
||||
|
||||
spin_unlock(&vfsmount_lock);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(mark_mounts_for_expiry);
|
||||
|
||||
/*
|
||||
* Ripoff of 'select_parent()'
|
||||
*
|
||||
* search the list of submounts for a given mountpoint, and move any
|
||||
* shrinkable submounts to the 'graveyard' list.
|
||||
*/
|
||||
static int select_submounts(struct vfsmount *parent, struct list_head *graveyard)
|
||||
{
|
||||
struct vfsmount *this_parent = parent;
|
||||
struct list_head *next;
|
||||
int found = 0;
|
||||
|
||||
repeat:
|
||||
next = this_parent->mnt_mounts.next;
|
||||
resume:
|
||||
while (next != &this_parent->mnt_mounts) {
|
||||
struct list_head *tmp = next;
|
||||
struct vfsmount *mnt = list_entry(tmp, struct vfsmount, mnt_child);
|
||||
|
||||
next = tmp->next;
|
||||
if (!(mnt->mnt_flags & MNT_SHRINKABLE))
|
||||
continue;
|
||||
/*
|
||||
* 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
|
||||
* bytes remaining to copy on a fault. But copy_mount_options() requires that.
|
||||
|
|
|
@ -4,14 +4,16 @@
|
|||
|
||||
obj-$(CONFIG_NFS_FS) += nfs.o
|
||||
|
||||
nfs-y := dir.o file.o inode.o nfs2xdr.o pagelist.o \
|
||||
proc.o read.o symlink.o unlink.o write.o
|
||||
nfs-y := dir.o file.o inode.o super.o nfs2xdr.o pagelist.o \
|
||||
proc.o read.o symlink.o unlink.o write.o \
|
||||
namespace.o
|
||||
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
|
||||
nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
|
||||
nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
|
||||
nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
|
||||
delegation.o idmap.o \
|
||||
callback.o callback_xdr.o callback_proc.o
|
||||
callback.o callback_xdr.o callback_proc.o \
|
||||
nfs4namespace.o
|
||||
nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
|
||||
nfs-$(CONFIG_SYSCTL) += sysctl.o
|
||||
nfs-objs := $(nfs-y)
|
||||
|
|
|
@ -182,8 +182,6 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp)
|
|||
/*
|
||||
* Define NFS4 callback program
|
||||
*/
|
||||
extern struct svc_version nfs4_callback_version1;
|
||||
|
||||
static struct svc_version *nfs4_callback_version[] = {
|
||||
[1] = &nfs4_callback_version1,
|
||||
};
|
||||
|
|
|
@ -202,7 +202,7 @@ static unsigned decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xd
|
|||
status = decode_fh(xdr, &args->fh);
|
||||
out:
|
||||
dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
|
||||
return 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
|
||||
|
|
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();
|
||||
|
||||
res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
|
||||
res = nfs_revalidate_mapping(inode, filp->f_mapping);
|
||||
if (res < 0) {
|
||||
unlock_kernel();
|
||||
return res;
|
||||
|
@ -868,6 +868,17 @@ int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
|
|||
return (nd->intent.open.flags & O_EXCL) != 0;
|
||||
}
|
||||
|
||||
static inline int nfs_reval_fsid(struct inode *dir,
|
||||
struct nfs_fh *fh, struct nfs_fattr *fattr)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(dir);
|
||||
|
||||
if (!nfs_fsid_equal(&server->fsid, &fattr->fsid))
|
||||
/* Revalidate fsid on root dir */
|
||||
return __nfs_revalidate_inode(server, dir->i_sb->s_root->d_inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
|
||||
{
|
||||
struct dentry *res;
|
||||
|
@ -900,6 +911,11 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
|
|||
res = ERR_PTR(error);
|
||||
goto out_unlock;
|
||||
}
|
||||
error = nfs_reval_fsid(dir, &fhandle, &fattr);
|
||||
if (error < 0) {
|
||||
res = ERR_PTR(error);
|
||||
goto out_unlock;
|
||||
}
|
||||
inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);
|
||||
res = (struct dentry *)inode;
|
||||
if (IS_ERR(res))
|
||||
|
|
|
@ -892,7 +892,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t
|
|||
* 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",
|
||||
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))
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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,
|
||||
(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);
|
||||
if (!result)
|
||||
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,
|
||||
(unsigned long) count, (unsigned long long) *ppos);
|
||||
|
||||
res = nfs_revalidate_file(inode, filp);
|
||||
res = nfs_revalidate_mapping(inode, filp->f_mapping);
|
||||
if (!res)
|
||||
res = generic_file_sendfile(filp, ppos, count, actor, target);
|
||||
return res;
|
||||
|
@ -263,7 +246,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
|
|||
dfprintk(VFS, "nfs: mmap(%s/%s)\n",
|
||||
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)
|
||||
status = generic_file_mmap(file, vma);
|
||||
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)
|
||||
{
|
||||
/* 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)
|
||||
|
@ -373,7 +360,6 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t
|
|||
if (result)
|
||||
goto out;
|
||||
}
|
||||
nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
|
||||
|
||||
result = count;
|
||||
if (!count)
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#include <linux/workqueue.h>
|
||||
#include <linux/sunrpc/rpc_pipe_fs.h>
|
||||
|
||||
#include <linux/nfs_fs_sb.h>
|
||||
#include <linux/nfs_fs.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/nfs2.h>
|
||||
#include <linux/nfs_fs.h>
|
||||
#include "internal.h"
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_XDR
|
||||
/* #define NFS_PARANOIA 1 */
|
||||
|
||||
extern int nfs_stat_to_errno(int stat);
|
||||
|
||||
/* Mapping from NFS error code to "errno" error code. */
|
||||
#define errno_NFSERR_IO EIO
|
||||
|
||||
|
@ -131,7 +132,8 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
|
|||
fattr->du.nfs2.blocksize = ntohl(*p++);
|
||||
rdev = 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++);
|
||||
p = xdr_decode_time(p, &fattr->atime);
|
||||
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);
|
||||
spin_lock(&inode->i_lock);
|
||||
__nfs3_forget_cached_acls(NFS_I(inode));
|
||||
nfsi->acl_access = posix_acl_dup(acl);
|
||||
nfsi->acl_default = posix_acl_dup(dfacl);
|
||||
if (!IS_ERR(acl))
|
||||
nfsi->acl_access = posix_acl_dup(acl);
|
||||
if (!IS_ERR(dfacl))
|
||||
nfsi->acl_default = posix_acl_dup(dfacl);
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
|
||||
|
@ -254,7 +256,9 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
|
|||
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) {
|
||||
case ACL_TYPE_ACCESS:
|
||||
|
@ -329,6 +333,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
|
|||
switch (status) {
|
||||
case 0:
|
||||
status = nfs_refresh_inode(inode, &fattr);
|
||||
nfs3_cache_acls(inode, acl, dfacl);
|
||||
break;
|
||||
case -EPFNOSUPPORT:
|
||||
case -EPROTONOSUPPORT:
|
||||
|
|
|
@ -20,11 +20,10 @@
|
|||
#include <linux/nfs_mount.h>
|
||||
|
||||
#include "iostat.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_PROC
|
||||
|
||||
extern struct rpc_procinfo nfs3_procedures[];
|
||||
|
||||
/* A wrapper to handle the EJUKEBOX error message */
|
||||
static int
|
||||
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;
|
||||
}
|
||||
|
||||
extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
|
||||
|
||||
static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data)
|
||||
{
|
||||
if (nfs3_async_handle_jukebox(task, data->inode))
|
||||
|
|
|
@ -22,14 +22,13 @@
|
|||
#include <linux/nfs3.h>
|
||||
#include <linux/nfs_fs.h>
|
||||
#include <linux/nfsacl.h>
|
||||
#include "internal.h"
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_XDR
|
||||
|
||||
/* Mapping from NFS error code to "errno" error code. */
|
||||
#define errno_NFSERR_IO EIO
|
||||
|
||||
extern int nfs_stat_to_errno(int);
|
||||
|
||||
/*
|
||||
* Declare the space requirements for NFS arguments and replies as
|
||||
* 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)
|
||||
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_time3(p, &fattr->atime);
|
||||
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 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_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_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_pathconf_bitmap[2];
|
||||
extern const u32 nfs4_fsinfo_bitmap[2];
|
||||
extern const u32 nfs4_fs_locations_bitmap[2];
|
||||
|
||||
/* nfs4renewd.c */
|
||||
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_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);
|
||||
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 */
|
||||
int nfs4_map_errors(int err)
|
||||
|
@ -121,6 +119,25 @@ const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE
|
|||
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,
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
|
||||
spin_lock(&dir->i_lock);
|
||||
nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA;
|
||||
if (cinfo->before == nfsi->change_attr && cinfo->atomic)
|
||||
nfsi->change_attr = cinfo->after;
|
||||
spin_unlock(&inode->i_lock);
|
||||
spin_unlock(&dir->i_lock);
|
||||
}
|
||||
|
||||
struct nfs4_opendata {
|
||||
|
@ -1331,7 +1348,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
|
|||
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 = { };
|
||||
int err;
|
||||
|
@ -1443,6 +1460,50 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
|||
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)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
return status;
|
||||
}
|
||||
|
@ -2008,7 +2071,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
|
|||
if (!status) {
|
||||
update_changeattr(dir, &res.cinfo);
|
||||
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;
|
||||
|
@ -3570,6 +3633,36 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
|
|||
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 = {
|
||||
.recover_open = nfs4_open_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 + \
|
||||
decode_putfh_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 {
|
||||
unsigned int mode;
|
||||
|
@ -722,6 +731,13 @@ static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask)
|
|||
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)
|
||||
{
|
||||
uint32_t *p;
|
||||
|
@ -2002,6 +2018,38 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, uint32_t *p, const str
|
|||
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.
|
||||
* These may look a little ugly since they are imported from a "generic"
|
||||
|
@ -2036,7 +2084,7 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, uint32_t *p, const str
|
|||
} \
|
||||
} 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;
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
uint32_t *p;
|
||||
uint32_t strlen;
|
||||
unsigned int strlen;
|
||||
char *str;
|
||||
|
||||
READ_BUF(12);
|
||||
|
@ -2217,7 +2265,7 @@ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap,
|
|||
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;
|
||||
|
||||
|
@ -2285,6 +2333,22 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t
|
|||
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)
|
||||
{
|
||||
uint32_t *p;
|
||||
|
@ -2336,6 +2400,116 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin
|
|||
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)
|
||||
{
|
||||
uint32_t *p;
|
||||
|
@ -2841,6 +3015,7 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
|
|||
bitmap[2] = {0},
|
||||
type;
|
||||
int status, fmode = 0;
|
||||
uint64_t fileid;
|
||||
|
||||
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
|
||||
goto xdr_error;
|
||||
|
@ -2863,10 +3038,14 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
|
|||
goto xdr_error;
|
||||
if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0)
|
||||
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;
|
||||
if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
|
||||
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)
|
||||
goto xdr_error;
|
||||
fattr->mode |= fmode;
|
||||
|
@ -2886,6 +3065,10 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
|
|||
goto xdr_error;
|
||||
if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0)
|
||||
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)
|
||||
fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
|
||||
xdr_error:
|
||||
|
@ -3350,8 +3533,7 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
|
|||
attrlen, recvd);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (attrlen <= *acl_len)
|
||||
xdr_read_pages(xdr, attrlen);
|
||||
xdr_read_pages(xdr, attrlen);
|
||||
*acl_len = attrlen;
|
||||
} else
|
||||
status = -EOPNOTSUPP;
|
||||
|
@ -4211,6 +4393,29 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, struct
|
|||
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 bitmap[2] = {0};
|
||||
|
@ -4382,6 +4587,7 @@ struct rpc_procinfo nfs4_procedures[] = {
|
|||
PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn),
|
||||
PROC(GETACL, enc_getacl, dec_getacl),
|
||||
PROC(SETACL, enc_setacl, dec_setacl),
|
||||
PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations),
|
||||
};
|
||||
|
||||
struct rpc_version nfs_version4 = {
|
||||
|
|
|
@ -325,6 +325,7 @@ nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst,
|
|||
|
||||
/**
|
||||
* nfs_scan_list - Scan a list for matching requests
|
||||
* @nfsi: NFS inode
|
||||
* @head: One of the NFS inode request lists
|
||||
* @dst: Destination list
|
||||
* @idx_start: lower bound of page->index to scan
|
||||
|
@ -336,14 +337,15 @@ nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst,
|
|||
* 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
|
||||
*/
|
||||
int
|
||||
nfs_scan_list(struct list_head *head, struct list_head *dst,
|
||||
unsigned long idx_start, unsigned int npages)
|
||||
int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head,
|
||||
struct list_head *dst, unsigned long idx_start,
|
||||
unsigned int npages)
|
||||
{
|
||||
struct list_head *pos, *tmp;
|
||||
struct nfs_page *req;
|
||||
unsigned long idx_end;
|
||||
int res;
|
||||
struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
|
||||
struct nfs_page *req;
|
||||
unsigned long idx_end;
|
||||
int found, i;
|
||||
int res;
|
||||
|
||||
res = 0;
|
||||
if (npages == 0)
|
||||
|
@ -351,25 +353,32 @@ nfs_scan_list(struct list_head *head, struct list_head *dst,
|
|||
else
|
||||
idx_end = idx_start + npages - 1;
|
||||
|
||||
list_for_each_safe(pos, tmp, head) {
|
||||
|
||||
req = nfs_list_entry(pos);
|
||||
|
||||
if (req->wb_index < idx_start)
|
||||
continue;
|
||||
if (req->wb_index > idx_end)
|
||||
for (;;) {
|
||||
found = radix_tree_gang_lookup(&nfsi->nfs_page_tree,
|
||||
(void **)&pgvec[0], idx_start,
|
||||
NFS_SCAN_MAXENTRIES);
|
||||
if (found <= 0)
|
||||
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;
|
||||
}
|
||||
|
||||
int nfs_init_nfspagecache(void)
|
||||
int __init nfs_init_nfspagecache(void)
|
||||
{
|
||||
nfs_page_cachep = kmem_cache_create("nfs_page",
|
||||
sizeof(struct nfs_page),
|
||||
|
@ -381,7 +390,7 @@ int nfs_init_nfspagecache(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void nfs_destroy_nfspagecache(void)
|
||||
void __exit nfs_destroy_nfspagecache(void)
|
||||
{
|
||||
if (kmem_cache_destroy(nfs_page_cachep))
|
||||
printk(KERN_INFO "nfs_page: not all structures were freed\n");
|
||||
|
|
|
@ -44,11 +44,10 @@
|
|||
#include <linux/nfs_page.h>
|
||||
#include <linux/lockd/bind.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include "internal.h"
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_PROC
|
||||
|
||||
extern struct rpc_procinfo nfs_procedures[];
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
|
||||
|
||||
static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
|
||||
{
|
||||
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) {
|
||||
memset(p, 0, sizeof(*p));
|
||||
INIT_LIST_HEAD(&p->pages);
|
||||
if (pagecount < NFS_PAGEVEC_SIZE)
|
||||
p->pagevec = &p->page_array[0];
|
||||
if (pagecount <= ARRAY_SIZE(p->page_array))
|
||||
p->pagevec = p->page_array;
|
||||
else {
|
||||
size_t size = ++pagecount * sizeof(struct page *);
|
||||
p->pagevec = kmalloc(size, GFP_NOFS);
|
||||
if (p->pagevec) {
|
||||
memset(p->pagevec, 0, size);
|
||||
} else {
|
||||
p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
|
||||
if (!p->pagevec) {
|
||||
mempool_free(p, nfs_rdata_mempool);
|
||||
p = NULL;
|
||||
}
|
||||
|
@ -104,6 +101,28 @@ int nfs_return_empty_page(struct page *page)
|
|||
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.
|
||||
*/
|
||||
|
@ -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;
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
if (count)
|
||||
memclear_highpage_flush(page, rdata->args.pgbase, count);
|
||||
SetPageUptodate(page);
|
||||
if (PageError(page))
|
||||
ClearPageError(page);
|
||||
nfs_readpage_truncate_uninitialised_page(rdata);
|
||||
if (rdata->res.eof || rdata->res.count == rdata->args.count)
|
||||
SetPageUptodate(page);
|
||||
result = 0;
|
||||
|
||||
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 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)
|
||||
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 (!PageError(page))
|
||||
SetPageUptodate(page);
|
||||
|
@ -462,6 +471,40 @@ static const struct rpc_call_ops nfs_read_partial_ops = {
|
|||
.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
|
||||
* 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)
|
||||
{
|
||||
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)
|
||||
return;
|
||||
while (!list_empty(&data->pages)) {
|
||||
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) {
|
||||
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_list_remove_request(req);
|
||||
nfs_readpage_release(req);
|
||||
}
|
||||
}
|
||||
|
@ -654,7 +694,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int nfs_init_readpagecache(void)
|
||||
int __init nfs_init_readpagecache(void)
|
||||
{
|
||||
nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
|
||||
sizeof(struct nfs_read_data),
|
||||
|
@ -671,7 +711,7 @@ int nfs_init_readpagecache(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void nfs_destroy_readpagecache(void)
|
||||
void __exit nfs_destroy_readpagecache(void)
|
||||
{
|
||||
mempool_destroy(nfs_rdata_mempool);
|
||||
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 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)
|
||||
goto read_failed;
|
||||
page = read_cache_page(&inode->i_data, 0,
|
||||
|
@ -75,22 +75,13 @@ static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
|||
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...
|
||||
*/
|
||||
struct inode_operations nfs_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = nfs_follow_link,
|
||||
.put_link = nfs_put_link,
|
||||
.put_link = page_put_link,
|
||||
.getattr = nfs_getattr,
|
||||
.setattr = nfs_setattr,
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/nfs4.h>
|
||||
#include <linux/nfs_idmap.h>
|
||||
#include <linux/nfs_fs.h>
|
||||
|
||||
#include "callback.h"
|
||||
|
||||
|
@ -46,6 +47,15 @@ static ctl_table nfs_cb_sysctls[] = {
|
|||
.strategy = &sysctl_jiffies,
|
||||
},
|
||||
#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 }
|
||||
};
|
||||
|
||||
|
|
|
@ -98,11 +98,10 @@ struct nfs_write_data *nfs_commit_alloc(unsigned int pagecount)
|
|||
if (p) {
|
||||
memset(p, 0, sizeof(*p));
|
||||
INIT_LIST_HEAD(&p->pages);
|
||||
if (pagecount < NFS_PAGEVEC_SIZE)
|
||||
p->pagevec = &p->page_array[0];
|
||||
if (pagecount <= ARRAY_SIZE(p->page_array))
|
||||
p->pagevec = p->page_array;
|
||||
else {
|
||||
size_t size = ++pagecount * sizeof(struct page *);
|
||||
p->pagevec = kzalloc(size, GFP_NOFS);
|
||||
p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
|
||||
if (!p->pagevec) {
|
||||
mempool_free(p, nfs_commit_mempool);
|
||||
p = NULL;
|
||||
|
@ -126,14 +125,11 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
|
|||
if (p) {
|
||||
memset(p, 0, sizeof(*p));
|
||||
INIT_LIST_HEAD(&p->pages);
|
||||
if (pagecount < NFS_PAGEVEC_SIZE)
|
||||
p->pagevec = &p->page_array[0];
|
||||
if (pagecount <= ARRAY_SIZE(p->page_array))
|
||||
p->pagevec = p->page_array;
|
||||
else {
|
||||
size_t size = ++pagecount * sizeof(struct page *);
|
||||
p->pagevec = kmalloc(size, GFP_NOFS);
|
||||
if (p->pagevec) {
|
||||
memset(p->pagevec, 0, size);
|
||||
} else {
|
||||
p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
|
||||
if (!p->pagevec) {
|
||||
mempool_free(p, nfs_wdata_mempool);
|
||||
p = NULL;
|
||||
}
|
||||
|
@ -583,6 +579,17 @@ static int nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, un
|
|||
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
|
||||
* @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;
|
||||
|
||||
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;
|
||||
if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))
|
||||
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);
|
||||
if (pages != 0) {
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
if (nocommit)
|
||||
break;
|
||||
pages = nfs_scan_commit(inode, &head, 0, 0);
|
||||
pages = nfs_scan_commit(inode, &head, idx_start, npages);
|
||||
if (pages == 0)
|
||||
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);
|
||||
ret = nfs_commit_list(inode, &head, how);
|
||||
spin_lock(&nfsi->req_lock);
|
||||
|
@ -1512,7 +1529,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int nfs_init_writepagecache(void)
|
||||
int __init nfs_init_writepagecache(void)
|
||||
{
|
||||
nfs_wdata_cachep = kmem_cache_create("nfs_write_data",
|
||||
sizeof(struct nfs_write_data),
|
||||
|
@ -1534,7 +1551,7 @@ int nfs_init_writepagecache(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void nfs_destroy_writepagecache(void)
|
||||
void __exit nfs_destroy_writepagecache(void)
|
||||
{
|
||||
mempool_destroy(nfs_commit_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;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(do_kern_mount);
|
||||
|
||||
struct vfsmount *kern_mount(struct file_system_type *type)
|
||||
{
|
||||
return vfs_kern_mount(type, 0, type->name, NULL);
|
||||
|
|
|
@ -1100,7 +1100,7 @@ struct super_operations {
|
|||
int (*statfs) (struct dentry *, struct kstatfs *);
|
||||
int (*remount_fs) (struct super_block *, int *, char *);
|
||||
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_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 dentry *d_alloc_name(struct dentry *, const char *);
|
||||
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 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_monitored : 1;
|
||||
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_nsmstate; /* true remote NSM state */
|
||||
u32 h_pidcount; /* Pseudopids */
|
||||
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_expires; /* eligible for GC */
|
||||
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)
|
||||
{
|
||||
return fl1->fl_pid == fl2->fl_pid
|
||||
&& fl1->fl_owner == fl2->fl_owner
|
||||
&& fl1->fl_start == fl2->fl_start
|
||||
&& fl1->fl_end == fl2->fl_end
|
||||
&&(fl1->fl_type == fl2->fl_type || fl2->fl_type == F_UNLCK);
|
||||
|
|
|
@ -28,6 +28,8 @@ struct namespace;
|
|||
#define MNT_NOATIME 0x08
|
||||
#define MNT_NODIRATIME 0x10
|
||||
|
||||
#define MNT_SHRINKABLE 0x100
|
||||
|
||||
#define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */
|
||||
#define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */
|
||||
#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,
|
||||
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;
|
||||
|
||||
extern int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd,
|
||||
int mnt_flags, struct list_head *fslist);
|
||||
|
||||
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 dev_t name_to_dev_t(char *name);
|
||||
|
|
|
@ -384,6 +384,7 @@ enum {
|
|||
NFSPROC4_CLNT_DELEGRETURN,
|
||||
NFSPROC4_CLNT_GETACL,
|
||||
NFSPROC4_CLNT_SETACL,
|
||||
NFSPROC4_CLNT_FS_LOCATIONS,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,6 +9,27 @@
|
|||
#ifndef _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.
|
||||
|
@ -41,27 +62,9 @@
|
|||
#define FLUSH_LOWPRI 8 /* low priority background flush */
|
||||
#define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */
|
||||
#define FLUSH_NOCOMMIT 32 /* Don't send the NFSv3/v4 COMMIT */
|
||||
#define FLUSH_INVALIDATE 64 /* Invalidate the page cache */
|
||||
|
||||
#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
|
||||
|
@ -233,8 +236,12 @@ static inline int nfs_caches_unstable(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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -296,7 +303,7 @@ extern int nfs_release(struct inode *, struct file *);
|
|||
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 *, 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 void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
|
||||
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 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 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. */
|
||||
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)
|
||||
#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
|
||||
*/
|
||||
|
|
|
@ -35,6 +35,7 @@ struct nfs_server {
|
|||
char * hostname; /* remote hostname */
|
||||
struct nfs_fh fh;
|
||||
struct sockaddr_in addr;
|
||||
struct nfs_fsid fsid;
|
||||
unsigned long mount_time; /* when this fs was mounted */
|
||||
#ifdef CONFIG_NFS_V4
|
||||
/* Our own IP address, as a null-terminated string.
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/nfs_fs_sb.h>
|
||||
#include <linux/sunrpc/auth.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,
|
||||
unsigned long idx_start, unsigned int npages);
|
||||
extern int nfs_scan_list(struct list_head *, struct list_head *,
|
||||
unsigned long, unsigned int);
|
||||
extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, struct list_head *dst,
|
||||
unsigned long idx_start, unsigned int npages);
|
||||
extern int nfs_coalesce_requests(struct list_head *, struct list_head *,
|
||||
unsigned int);
|
||||
extern int nfs_wait_on_request(struct nfs_page *);
|
||||
|
|
|
@ -14,11 +14,19 @@
|
|||
#define NFS_DEF_FILE_IO_SIZE (4096U)
|
||||
#define NFS_MIN_FILE_IO_SIZE (1024U)
|
||||
|
||||
struct nfs4_fsid {
|
||||
__u64 major;
|
||||
__u64 minor;
|
||||
struct nfs_fsid {
|
||||
uint64_t major;
|
||||
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 {
|
||||
unsigned short valid; /* which fields are valid */
|
||||
__u64 pre_size; /* pre_op_attr.size */
|
||||
|
@ -40,10 +48,7 @@ struct nfs_fattr {
|
|||
} nfs3;
|
||||
} du;
|
||||
dev_t rdev;
|
||||
union {
|
||||
__u64 nfs3; /* also nfs2 */
|
||||
struct nfs4_fsid nfs4;
|
||||
} fsid_u;
|
||||
struct nfs_fsid fsid;
|
||||
__u64 fileid;
|
||||
struct timespec atime;
|
||||
struct timespec mtime;
|
||||
|
@ -57,8 +62,8 @@ struct nfs_fattr {
|
|||
#define NFS_ATTR_WCC 0x0001 /* pre-op WCC data */
|
||||
#define NFS_ATTR_FATTR 0x0002 /* post-op attributes */
|
||||
#define NFS_ATTR_FATTR_V3 0x0004 /* NFSv3 attributes */
|
||||
#define NFS_ATTR_FATTR_V4 0x0008
|
||||
#define NFS_ATTR_PRE_CHANGE 0x0010
|
||||
#define NFS_ATTR_FATTR_V4 0x0008 /* NFSv4 change attribute */
|
||||
#define NFS_ATTR_FATTR_V4_REFERRAL 0x0010 /* NFSv4 referral */
|
||||
|
||||
/*
|
||||
* Info on the file system
|
||||
|
@ -675,6 +680,40 @@ struct nfs4_server_caps_res {
|
|||
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 */
|
||||
|
||||
struct nfs_page;
|
||||
|
@ -695,7 +734,7 @@ struct nfs_read_data {
|
|||
#ifdef CONFIG_NFS_V4
|
||||
unsigned long timestamp; /* For lease renewal */
|
||||
#endif
|
||||
struct page *page_array[NFS_PAGEVEC_SIZE + 1];
|
||||
struct page *page_array[NFS_PAGEVEC_SIZE];
|
||||
};
|
||||
|
||||
struct nfs_write_data {
|
||||
|
@ -713,7 +752,7 @@ struct nfs_write_data {
|
|||
#ifdef CONFIG_NFS_V4
|
||||
unsigned long timestamp; /* For lease renewal */
|
||||
#endif
|
||||
struct page *page_array[NFS_PAGEVEC_SIZE + 1];
|
||||
struct page *page_array[NFS_PAGEVEC_SIZE];
|
||||
};
|
||||
|
||||
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 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_enter_page(struct xdr_stream *xdr, unsigned int len);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
|
|
|
@ -2255,7 +2255,7 @@ static int __init init_tmpfs(void)
|
|||
#ifdef CONFIG_TMPFS
|
||||
devfs_mk_dir("shm");
|
||||
#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);
|
||||
if (IS_ERR(shm_mnt)) {
|
||||
error = PTR_ERR(shm_mnt);
|
||||
|
|
|
@ -118,6 +118,8 @@ struct rpc_auth null_auth = {
|
|||
.au_cslack = 4,
|
||||
.au_rslack = 2,
|
||||
.au_ops = &authnull_ops,
|
||||
.au_flavor = RPC_AUTH_NULL,
|
||||
.au_count = ATOMIC_INIT(0),
|
||||
};
|
||||
|
||||
static
|
||||
|
|
|
@ -225,6 +225,7 @@ struct rpc_auth unix_auth = {
|
|||
.au_cslack = UNX_WRITESLACK,
|
||||
.au_rslack = 2, /* assume AUTH_NULL verf */
|
||||
.au_ops = &authunix_ops,
|
||||
.au_flavor = RPC_AUTH_UNIX,
|
||||
.au_count = ATOMIC_INIT(0),
|
||||
.au_credcache = &unix_cred_cache,
|
||||
};
|
||||
|
|
|
@ -439,7 +439,7 @@ struct vfsmount *rpc_get_mount(void)
|
|||
{
|
||||
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)
|
||||
return ERR_PTR(err);
|
||||
return rpc_mount;
|
||||
|
|
|
@ -568,8 +568,7 @@ EXPORT_SYMBOL(xdr_inline_decode);
|
|||
*
|
||||
* 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 XDR tail.
|
||||
* bytes is moved into the XDR tail[].
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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};
|
||||
|
||||
void
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/net.h>
|
||||
|
||||
#include <linux/sunrpc/clnt.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)
|
||||
{
|
||||
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)
|
||||
|
|
|
@ -930,6 +930,13 @@ static void xs_udp_timer(struct rpc_task *task)
|
|||
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
|
||||
* @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);
|
||||
|
||||
xprt->prot = IPPROTO_UDP;
|
||||
xprt->port = xprt_max_resvport;
|
||||
xprt->port = xs_get_random_port();
|
||||
xprt->tsh_size = 0;
|
||||
xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
|
||||
/* 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);
|
||||
|
||||
xprt->prot = IPPROTO_TCP;
|
||||
xprt->port = xprt_max_resvport;
|
||||
xprt->port = xs_get_random_port();
|
||||
xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32);
|
||||
xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
|
||||
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);
|
||||
|
||||
error = simple_pin_fs("securityfs", &mount, &mount_count);
|
||||
error = simple_pin_fs(&fs_type, &mount, &mount_count);
|
||||
if (error) {
|
||||
dentry = ERR_PTR(error);
|
||||
goto exit;
|
||||
|
|
Loading…
Reference in New Issue