Commit 53f2c4a8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-3.5-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client updates from Trond Myklebust:
 "New features include:
   - Rewrite the O_DIRECT code so that it can share the same coalescing
     and pNFS functionality as the page cache code.
   - Allow the server to provide hints as to when we should use pNFS,
     and when it is more efficient to read and write through the
     metadata server.
   - NFS cache consistency updates:
     * Use the ctime to emulate a change attribute for NFSv2/v3 so that
       all NFS versions can share the same cache management code.
     * New cache management code will only look at the change attribute
       and size attribute when deciding whether or not our cached data
       is still valid or not.
     * Don't request NFSv4 post-op attributes on writes in cases such as
       O_DIRECT, where we don't care about data cache consistency, or
       when we have a write delegation, and know that our cache is still
       consistent.
     * Don't request NFSv4 post-op attributes on operations such as
       COMMIT, where there are no expected metadata updates.
     * Don't request NFSv4 directory post-op attributes in cases where
       the operations themselves already return change attribute
       updates: i.e. operations such as OPEN, CREATE, REMOVE, LINK and
       RENAME.
   - Speed up 'ls' and friends by using READDIR rather than READDIRPLUS
     if we detect no attempts to lookup filenames.
   - Improve the code sharing between NFSv2/v3 and v4 mounts
   - NFSv4.1 state management efficiency improvements
   - More patches in preparation for NFSv4/v4.1 migration functionality."

Fix trivial conflict in fs/nfs/nfs4proc.c that was due to the dcache
qstr name initialization changes (that made the length/hash a 64-bit
union)

* tag 'nfs-for-3.5-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (146 commits)
  NFSv4: Add debugging printks to state manager
  NFSv4: Map NFS4ERR_SHARE_DENIED into an EACCES error instead of EIO
  NFSv4: update_changeattr does not need to set NFS_INO_REVAL_PAGECACHE
  NFSv4.1: nfs4_reset_session should use nfs4_handle_reclaim_lease_error
  NFSv4.1: Handle other occurrences of NFS4ERR_CONN_NOT_BOUND_TO_SESSION
  NFSv4.1: Handle NFS4ERR_CONN_NOT_BOUND_TO_SESSION in the state manager
  NFSv4.1: Handle errors in nfs4_bind_conn_to_session
  NFSv4.1: nfs4_bind_conn_to_session should drain the session
  NFSv4.1: Don't clobber the seqid if exchange_id returns a confirmed clientid
  NFSv4.1: Add DESTROY_CLIENTID
  NFSv4.1: Ensure we use the correct credentials for bind_conn_to_session
  NFSv4.1: Ensure we use the correct credentials for session create/destroy
  NFSv4.1: Move NFSPROC4_CLNT_BIND_CONN_TO_SESSION to the end of the operations
  NFSv4.1: Handle NFS4ERR_SEQ_MISORDERED when confirming the lease
  NFSv4: When purging the lease, we must clear NFS4CLNT_LEASE_CONFIRM
  NFSv4: Clean up the error handling for nfs4_reclaim_lease
  NFSv4.1: Exchange ID must use GFP_NOFS allocation mode
  nfs41: Use BIND_CONN_TO_SESSION for CB_PATH_DOWN*
  nfs4.1: add BIND_CONN_TO_SESSION operation
  NFSv4.1 test the mdsthreshold hint parameters
  ...
parents 8f6576ad cc0a9843
...@@ -29,9 +29,20 @@ config NFS_FS ...@@ -29,9 +29,20 @@ config NFS_FS
If unsure, say N. If unsure, say N.
config NFS_V2
bool "NFS client support for NFS version 2"
depends on NFS_FS
default y
help
This option enables support for version 2 of the NFS protocol
(RFC 1094) in the kernel's NFS client.
If unsure, say Y.
config NFS_V3 config NFS_V3
bool "NFS client support for NFS version 3" bool "NFS client support for NFS version 3"
depends on NFS_FS depends on NFS_FS
default y
help help
This option enables support for version 3 of the NFS protocol This option enables support for version 3 of the NFS protocol
(RFC 1813) in the kernel's NFS client. (RFC 1813) in the kernel's NFS client.
......
...@@ -4,11 +4,12 @@ ...@@ -4,11 +4,12 @@
obj-$(CONFIG_NFS_FS) += nfs.o obj-$(CONFIG_NFS_FS) += nfs.o
nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ nfs-y := client.o dir.o file.o getroot.o inode.o super.o \
direct.o pagelist.o proc.o read.o symlink.o unlink.o \ direct.o pagelist.o read.o symlink.o unlink.o \
write.o namespace.o mount_clnt.o \ write.o namespace.o mount_clnt.o \
dns_resolve.o cache_lib.o dns_resolve.o cache_lib.o
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
nfs-$(CONFIG_NFS_V2) += proc.o nfs2xdr.o
nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
......
This diff is collapsed.
...@@ -123,7 +123,7 @@ nfs4_blk_decode_device(struct nfs_server *server, ...@@ -123,7 +123,7 @@ nfs4_blk_decode_device(struct nfs_server *server,
uint8_t *dataptr; uint8_t *dataptr;
DECLARE_WAITQUEUE(wq, current); DECLARE_WAITQUEUE(wq, current);
int offset, len, i, rc; int offset, len, i, rc;
struct net *net = server->nfs_client->net; struct net *net = server->nfs_client->cl_net;
struct nfs_net *nn = net_generic(net, nfs_net_id); struct nfs_net *nn = net_generic(net, nfs_net_id);
struct bl_dev_msg *reply = &nn->bl_mount_reply; struct bl_dev_msg *reply = &nn->bl_mount_reply;
......
This diff is collapsed.
...@@ -316,6 +316,10 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat ...@@ -316,6 +316,10 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat
* nfs_client_return_marked_delegations - return previously marked delegations * nfs_client_return_marked_delegations - return previously marked delegations
* @clp: nfs_client to process * @clp: nfs_client to process
* *
* Note that this function is designed to be called by the state
* manager thread. For this reason, it cannot flush the dirty data,
* since that could deadlock in case of a state recovery error.
*
* Returns zero on success, or a negative errno value. * Returns zero on success, or a negative errno value.
*/ */
int nfs_client_return_marked_delegations(struct nfs_client *clp) int nfs_client_return_marked_delegations(struct nfs_client *clp)
...@@ -340,11 +344,9 @@ int nfs_client_return_marked_delegations(struct nfs_client *clp) ...@@ -340,11 +344,9 @@ int nfs_client_return_marked_delegations(struct nfs_client *clp)
server); server);
rcu_read_unlock(); rcu_read_unlock();
if (delegation != NULL) { if (delegation != NULL)
filemap_flush(inode->i_mapping);
err = __nfs_inode_return_delegation(inode, err = __nfs_inode_return_delegation(inode,
delegation, 0); delegation, 0);
}
iput(inode); iput(inode);
if (!err) if (!err)
goto restart; goto restart;
...@@ -380,6 +382,10 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode) ...@@ -380,6 +382,10 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode)
* nfs_inode_return_delegation - synchronously return a delegation * nfs_inode_return_delegation - synchronously return a delegation
* @inode: inode to process * @inode: inode to process
* *
* This routine will always flush any dirty data to disk on the
* assumption that if we need to return the delegation, then
* we should stop caching.
*
* Returns zero on success, or a negative errno value. * Returns zero on success, or a negative errno value.
*/ */
int nfs_inode_return_delegation(struct inode *inode) int nfs_inode_return_delegation(struct inode *inode)
...@@ -389,10 +395,10 @@ int nfs_inode_return_delegation(struct inode *inode) ...@@ -389,10 +395,10 @@ int nfs_inode_return_delegation(struct inode *inode)
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
int err = 0; int err = 0;
nfs_wb_all(inode);
if (rcu_access_pointer(nfsi->delegation) != NULL) { if (rcu_access_pointer(nfsi->delegation) != NULL) {
delegation = nfs_detach_delegation(nfsi, server); delegation = nfs_detach_delegation(nfsi, server);
if (delegation != NULL) { if (delegation != NULL) {
nfs_wb_all(inode);
err = __nfs_inode_return_delegation(inode, delegation, 1); err = __nfs_inode_return_delegation(inode, delegation, 1);
} }
} }
...@@ -538,6 +544,8 @@ int nfs_async_inode_return_delegation(struct inode *inode, ...@@ -538,6 +544,8 @@ int nfs_async_inode_return_delegation(struct inode *inode,
struct nfs_client *clp = server->nfs_client; struct nfs_client *clp = server->nfs_client;
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
filemap_flush(inode->i_mapping);
rcu_read_lock(); rcu_read_lock();
delegation = rcu_dereference(NFS_I(inode)->delegation); delegation = rcu_dereference(NFS_I(inode)->delegation);
......
...@@ -66,6 +66,7 @@ static inline int nfs_have_delegation(struct inode *inode, fmode_t flags) ...@@ -66,6 +66,7 @@ static inline int nfs_have_delegation(struct inode *inode, fmode_t flags)
static inline int nfs_inode_return_delegation(struct inode *inode) static inline int nfs_inode_return_delegation(struct inode *inode)
{ {
nfs_wb_all(inode);
return 0; return 0;
} }
#endif #endif
......
...@@ -474,6 +474,29 @@ int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) ...@@ -474,6 +474,29 @@ int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
return 0; return 0;
} }
static
bool nfs_use_readdirplus(struct inode *dir, struct file *filp)
{
if (!nfs_server_capable(dir, NFS_CAP_READDIRPLUS))
return false;
if (test_and_clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags))
return true;
if (filp->f_pos == 0)
return true;
return false;
}
/*
* This function is called by the lookup code to request the use of
* readdirplus to accelerate any future lookups in the same
* directory.
*/
static
void nfs_advise_use_readdirplus(struct inode *dir)
{
set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags);
}
static static
void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
{ {
...@@ -871,7 +894,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -871,7 +894,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
desc->file = filp; desc->file = filp;
desc->dir_cookie = &dir_ctx->dir_cookie; desc->dir_cookie = &dir_ctx->dir_cookie;
desc->decode = NFS_PROTO(inode)->decode_dirent; desc->decode = NFS_PROTO(inode)->decode_dirent;
desc->plus = NFS_USE_READDIRPLUS(inode); desc->plus = nfs_use_readdirplus(inode, filp) ? 1 : 0;
nfs_block_sillyrename(dentry); nfs_block_sillyrename(dentry);
res = nfs_revalidate_mapping(inode, filp->f_mapping); res = nfs_revalidate_mapping(inode, filp->f_mapping);
...@@ -1111,7 +1134,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -1111,7 +1134,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
if (!inode) { if (!inode) {
if (nfs_neg_need_reval(dir, dentry, nd)) if (nfs_neg_need_reval(dir, dentry, nd))
goto out_bad; goto out_bad;
goto out_valid; goto out_valid_noent;
} }
if (is_bad_inode(inode)) { if (is_bad_inode(inode)) {
...@@ -1140,7 +1163,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -1140,7 +1163,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
if (fhandle == NULL || fattr == NULL) if (fhandle == NULL || fattr == NULL)
goto out_error; goto out_error;
error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr); error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
if (error) if (error)
goto out_bad; goto out_bad;
if (nfs_compare_fh(NFS_FH(inode), fhandle)) if (nfs_compare_fh(NFS_FH(inode), fhandle))
...@@ -1153,6 +1176,9 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -1153,6 +1176,9 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
out_set_verifier: out_set_verifier:
nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out_valid: out_valid:
/* Success: notify readdir to use READDIRPLUS */
nfs_advise_use_readdirplus(dir);
out_valid_noent:
dput(parent); dput(parent);
dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is valid\n", dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is valid\n",
__func__, dentry->d_parent->d_name.name, __func__, dentry->d_parent->d_name.name,
...@@ -1296,7 +1322,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru ...@@ -1296,7 +1322,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
parent = dentry->d_parent; parent = dentry->d_parent;
/* Protect against concurrent sillydeletes */ /* Protect against concurrent sillydeletes */
nfs_block_sillyrename(parent); nfs_block_sillyrename(parent);
error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr); error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
if (error == -ENOENT) if (error == -ENOENT)
goto no_entry; goto no_entry;
if (error < 0) { if (error < 0) {
...@@ -1308,6 +1334,9 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru ...@@ -1308,6 +1334,9 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
if (IS_ERR(res)) if (IS_ERR(res))
goto out_unblock_sillyrename; goto out_unblock_sillyrename;
/* Success: notify readdir to use READDIRPLUS */
nfs_advise_use_readdirplus(dir);
no_entry: no_entry:
res = d_materialise_unique(dentry, inode); res = d_materialise_unique(dentry, inode);
if (res != NULL) { if (res != NULL) {
...@@ -1643,7 +1672,7 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, ...@@ -1643,7 +1672,7 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
if (dentry->d_inode) if (dentry->d_inode)
goto out; goto out;
if (fhandle->size == 0) { if (fhandle->size == 0) {
error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr); error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
if (error) if (error)
goto out_error; goto out_error;
} }
......
This diff is collapsed.
...@@ -174,6 +174,13 @@ nfs_file_flush(struct file *file, fl_owner_t id) ...@@ -174,6 +174,13 @@ nfs_file_flush(struct file *file, fl_owner_t id)
if ((file->f_mode & FMODE_WRITE) == 0) if ((file->f_mode & FMODE_WRITE) == 0)
return 0; return 0;
/*
* If we're holding a write delegation, then just start the i/o
* but don't wait for completion (or send a commit).
*/
if (nfs_have_delegation(inode, FMODE_WRITE))
return filemap_fdatawrite(file->f_mapping);
/* Flush writes to the server and return any errors */ /* Flush writes to the server and return any errors */
return vfs_fsync(file, 0); return vfs_fsync(file, 0);
} }
...@@ -417,6 +424,7 @@ static int nfs_write_end(struct file *file, struct address_space *mapping, ...@@ -417,6 +424,7 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
if (status < 0) if (status < 0)
return status; return status;
NFS_I(mapping->host)->write_io += copied;
return copied; return copied;
} }
......
...@@ -64,23 +64,12 @@ void nfs_fscache_release_client_cookie(struct nfs_client *clp) ...@@ -64,23 +64,12 @@ void nfs_fscache_release_client_cookie(struct nfs_client *clp)
* either by the 'fsc=xxx' option to mount, or by inheriting it from the parent * either by the 'fsc=xxx' option to mount, or by inheriting it from the parent
* superblock across an automount point of some nature. * superblock across an automount point of some nature.
*/ */
void nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, void nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int ulen)
struct nfs_clone_mount *mntdata)
{ {
struct nfs_fscache_key *key, *xkey; struct nfs_fscache_key *key, *xkey;
struct nfs_server *nfss = NFS_SB(sb); struct nfs_server *nfss = NFS_SB(sb);
struct rb_node **p, *parent; struct rb_node **p, *parent;
int diff, ulen; int diff;
if (uniq) {
ulen = strlen(uniq);
} else if (mntdata) {
struct nfs_server *mnt_s = NFS_SB(mntdata->sb);
if (mnt_s->fscache_key) {
uniq = mnt_s->fscache_key->key.uniquifier;
ulen = mnt_s->fscache_key->key.uniq_len;
}
}
if (!uniq) { if (!uniq) {
uniq = ""; uniq = "";
......
...@@ -73,9 +73,7 @@ extern void nfs_fscache_unregister(void); ...@@ -73,9 +73,7 @@ extern void nfs_fscache_unregister(void);
extern void nfs_fscache_get_client_cookie(struct nfs_client *); extern void nfs_fscache_get_client_cookie(struct nfs_client *);
extern void nfs_fscache_release_client_cookie(struct nfs_client *); extern void nfs_fscache_release_client_cookie(struct nfs_client *);
extern void nfs_fscache_get_super_cookie(struct super_block *, extern void nfs_fscache_get_super_cookie(struct super_block *, const char *, int);
const char *,
struct nfs_clone_mount *);
extern void nfs_fscache_release_super_cookie(struct super_block *); extern void nfs_fscache_release_super_cookie(struct super_block *);
extern void nfs_fscache_init_inode_cookie(struct inode *); extern void nfs_fscache_init_inode_cookie(struct inode *);
...@@ -172,12 +170,6 @@ static inline void nfs_fscache_unregister(void) {} ...@@ -172,12 +170,6 @@ static inline void nfs_fscache_unregister(void) {}
static inline void nfs_fscache_get_client_cookie(struct nfs_client *clp) {} static inline void nfs_fscache_get_client_cookie(struct nfs_client *clp) {}
static inline void nfs_fscache_release_client_cookie(struct nfs_client *clp) {} static inline void nfs_fscache_release_client_cookie(struct nfs_client *clp) {}
static inline void nfs_fscache_get_super_cookie(
struct super_block *sb,
const char *uniq,
struct nfs_clone_mount *mntdata)
{
}
static inline void nfs_fscache_release_super_cookie(struct super_block *sb) {} static inline void nfs_fscache_release_super_cookie(struct super_block *sb) {}
static inline void nfs_fscache_init_inode_cookie(struct inode *inode) {} static inline void nfs_fscache_init_inode_cookie(struct inode *inode) {}
......
...@@ -150,7 +150,7 @@ int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh) ...@@ -150,7 +150,7 @@ int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh)
goto out; goto out;
/* Start by getting the root filehandle from the server */ /* Start by getting the root filehandle from the server */
ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); ret = nfs4_proc_get_rootfh(server, mntfh, &fsinfo);
if (ret < 0) { if (ret < 0) {
dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret); dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret);
goto out; goto out;
...@@ -178,87 +178,4 @@ int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh) ...@@ -178,87 +178,4 @@ int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh)
return ret; return ret;
} }
/*
* get an NFS4 root dentry from the root filehandle
*/
struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh,
const char *devname)
{
struct nfs_server *server = NFS_SB(sb);
struct nfs_fattr *fattr = NULL;
struct dentry *ret;
struct inode *inode;
void *name = kstrdup(devname, GFP_KERNEL);
int error;
dprintk("--> nfs4_get_root()\n");
if (!name)
return ERR_PTR(-ENOMEM);
/* get the info about the server and filesystem */
error = nfs4_server_capabilities(server, mntfh);
if (error < 0) {
dprintk("nfs_get_root: getcaps error = %d\n",
-error);
kfree(name);
return ERR_PTR(error);
}
fattr = nfs_alloc_fattr();
if (fattr == NULL) {
kfree(name);
return ERR_PTR(-ENOMEM);
}
/* get the actual root for this mount */
error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr);
if (error < 0) {
dprintk("nfs_get_root: getattr error = %d\n", -error);
ret = ERR_PTR(error);
goto out;
}
if (fattr->valid & NFS_ATTR_FATTR_FSID &&
!nfs_fsid_equal(&server->fsid, &fattr->fsid))
memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
inode = nfs_fhget(sb, mntfh, fattr);
if (IS_ERR(inode)) {
dprintk("nfs_get_root: get root inode failed\n");
ret = ERR_CAST(inode);
goto out;
}
error = nfs_superblock_set_dummy_root(sb, inode);
if (error != 0) {
ret = ERR_PTR(error);
goto out;
}
/* root dentries normally start off anonymous and get spliced in later
* if the dentry tree reaches them; however if the dentry already
* exists, we'll pick it up at this point and use it as the root
*/
ret = d_obtain_alias(inode);
if (IS_ERR(ret)) {
dprintk("nfs_get_root: get root dentry failed\n");
goto out;
}
security_d_instantiate(ret, inode);
spin_lock(&ret->d_lock);
if (IS_ROOT(ret) && !(ret->d_flags & DCACHE_NFSFS_RENAMED)) {
ret->d_fsdata = name;
name = NULL;
}
spin_unlock(&ret->d_lock);
out:
if (name)
kfree(name);
nfs_free_fattr(fattr);
dprintk("<-- nfs4_get_root()\n");
return ret;
}
#endif /* CONFIG_NFS_V4 */ #endif /* CONFIG_NFS_V4 */
...@@ -415,7 +415,7 @@ static int __nfs_idmap_register(struct dentry *dir, ...@@ -415,7 +415,7 @@ static int __nfs_idmap_register(struct dentry *dir,
static void nfs_idmap_unregister(struct nfs_client *clp, static void nfs_idmap_unregister(struct nfs_client *clp,
struct rpc_pipe *pipe) struct rpc_pipe *pipe)
{ {
struct net *net = clp->net; struct net *net = clp->cl_net;
struct super_block *pipefs_sb; struct super_block *pipefs_sb;
pipefs_sb = rpc_get_sb_net(net); pipefs_sb = rpc_get_sb_net(net);
...@@ -429,7 +429,7 @@ static int nfs_idmap_register(struct nfs_client *clp, ...@@ -429,7 +429,7 @@ static int nfs_idmap_register(struct nfs_client *clp,
struct idmap *idmap, struct idmap *idmap,
struct rpc_pipe *pipe) struct rpc_pipe *pipe)
{ {
struct net *net = clp->net; struct net *net = clp->cl_net;
struct super_block *pipefs_sb; struct super_block *pipefs_sb;
int err = 0; int err = 0;
...@@ -530,9 +530,25 @@ static struct nfs_client *nfs_get_client_for_event(struct net *net, int event) ...@@ -530,9 +530,25 @@ static struct nfs_client *nfs_get_client_for_event(struct net *net, int event)
struct nfs_net *nn = net_generic(net, nfs_net_id); struct nfs_net *nn = net_generic(net, nfs_net_id);
struct dentry *cl_dentry; struct dentry *cl_dentry;
struct nfs_client *clp; struct nfs_client *clp;
int err;
restart:
spin_lock(&nn->nfs_client_lock); spin_lock(&nn->nfs_client_lock);
list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
/* Wait for initialisation to finish */
if (clp->cl_cons_state == NFS_CS_INITING) {
atomic_inc(&clp->cl_count);
spin_unlock(&nn->nfs_client_lock);
err = nfs_wait_client_init_complete(clp);
nfs_put_client(clp);
if (err)
return NULL;
goto restart;
}
/* Skip nfs_clients that failed to initialise */
if (clp->cl_cons_state < 0)
continue;
smp_rmb();
if (clp->rpc_ops != &nfs_v4_clientops) if (clp->rpc_ops != &nfs_v4_clientops)
continue; continue;
cl_dentry = clp->cl_idmap->idmap_pipe->dentry; cl_dentry = clp->cl_idmap->idmap_pipe->dentry;
...@@ -640,20 +656,16 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons, ...@@ -640,20 +656,16 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
struct idmap_msg *im; struct idmap_msg *im;
struct idmap *idmap = (struct idmap *)aux; struct idmap *idmap = (struct idmap *)aux;
struct key *key = cons->key; struct key *key = cons->key;
int ret; int ret = -ENOMEM;
/* msg and im are freed in idmap_pipe_destroy_msg */ /* msg and im are freed in idmap_pipe_destroy_msg */
msg = kmalloc(sizeof(*msg), GFP_KERNEL); msg = kmalloc(sizeof(*msg), GFP_KERNEL);
if (IS_ERR(msg)) { if (!msg)
ret = PTR_ERR(msg);
goto out0; goto out0;
}
im = kmalloc(sizeof(*im), GFP_KERNEL); im = kmalloc(sizeof(*im), GFP_KERNEL);
if (IS_ERR(im)) { if (!im)
ret = PTR_ERR(im);
goto out1; goto out1;
}
ret = nfs_idmap_prepare_message(key->description, im, msg); ret = nfs_idmap_prepare_message(key->description, im, msg);
if (ret < 0) if (ret < 0)
......
This diff is collapsed.
...@@ -103,6 +103,7 @@ struct nfs_parsed_mount_data { ...@@ -103,6 +103,7 @@ struct nfs_parsed_mount_data {
unsigned int version; unsigned int version;
unsigned int minorversion; unsigned int minorversion;
char *fscache_uniq; char *fscache_uniq;
bool need_mount;
struct { struct {
struct sockaddr_storage address; struct sockaddr_storage address;
...@@ -167,11 +168,13 @@ extern struct nfs_server *nfs_clone_server(struct nfs_server *, ...@@ -167,11 +168,13 @@ extern struct nfs_server *nfs_clone_server(struct nfs_server *,
struct nfs_fh *, struct nfs_fh *,
struct nfs_fattr *, struct nfs_fattr *,
rpc_authflavor_t); rpc_authflavor_t);
extern int nfs_wait_client_init_complete(const struct nfs_client *clp);
extern void nfs_mark_client_ready(struct nfs_client *clp, int state); extern void nfs_mark_client_ready(struct nfs_client *clp, int state);
extern int nfs4_check_client_ready(struct nfs_client *clp);
extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
const struct sockaddr *ds_addr, const struct sockaddr *ds_addr,
int ds_addrlen, int ds_proto); int ds_addrlen, int ds_proto,
unsigned int ds_timeo,
unsigned int ds_retrans);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
extern int __init nfs_fs_proc_init(void); extern int __init nfs_fs_proc_init(void);
extern void nfs_fs_proc_exit(void); extern void nfs_fs_proc_exit(void);
...@@ -185,21 +188,11 @@ static inline void nfs_fs_proc_exit(void) ...@@ -185,21 +188,11 @@ static inline void nfs_fs_proc_exit(void)
} }
#endif #endif
/* nfs4namespace.c */
#ifdef CONFIG_NFS_V4
extern struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry);
#else
static inline
struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry)
{
return ERR_PTR(-ENOENT);
}
#endif
/* callback_xdr.c */ /* callback_xdr.c */
extern struct svc_version nfs4_callback_version1; extern struct svc_version nfs4_callback_version1;
extern struct svc_version nfs4_callback_version4; extern struct svc_version nfs4_callback_version4;
struct nfs_pageio_descriptor;
/* pagelist.c */ /* pagelist.c */
extern int __init nfs_init_nfspagecache(void); extern int __init nfs_init_nfspagecache(void);
extern void nfs_destroy_nfspagecache(void); extern void nfs_destroy_nfspagecache(void);
...@@ -210,9 +203,13 @@ extern void nfs_destroy_writepagecache(void); ...@@ -210,9 +203,13 @@ extern void nfs_destroy_writepagecache(void);
extern int __init nfs_init_directcache(void); extern int __init nfs_init_directcache(void);
extern void nfs_destroy_directcache(void); extern void nfs_destroy_directcache(void);
extern bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount);
extern void nfs_pgheader_init(struct nfs_pageio_descriptor *desc,
struct nfs_pgio_header *hdr,
void (*release)(struct nfs_pgio_header *hdr));
void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos);
/* nfs2xdr.c */ /* nfs2xdr.c */
extern int nfs_stat_to_errno(enum nfs_stat);
extern struct rpc_procinfo nfs_procedures[]; extern struct rpc_procinfo nfs_procedures[];
extern int nfs2_decode_dirent(struct xdr_stream *, extern int nfs2_decode_dirent(struct xdr_stream *,
struct nfs_entry *, int); struct nfs_entry *, int);
...@@ -237,14 +234,13 @@ extern const u32 nfs41_maxwrite_overhead; ...@@ -237,14 +234,13 @@ extern const u32 nfs41_maxwrite_overhead;
extern struct rpc_procinfo nfs4_procedures[]; extern struct rpc_procinfo nfs4_procedures[];
#endif #endif
extern int nfs4_init_ds_session(struct nfs_client *clp); extern int nfs4_init_ds_session(struct nfs_client *, unsigned long);
/* proc.c */ /* proc.c */
void nfs_close_context(struct nfs_open_context *ctx, int is_sync); void nfs_close_context(struct nfs_open_context *ctx, int is_sync);
extern int nfs_init_client(struct nfs_client *clp, extern struct nfs_client *nfs_init_client(struct nfs_client *clp,
const struct rpc_timeout *timeparms, const struct rpc_timeout *timeparms,
const char *ip_addr, rpc_authflavor_t authflavour, const char *ip_addr, rpc_authflavor_t authflavour);
int noresvport);
/* dir.c */ /* dir.c */
extern int nfs_access_cache_shrinker(struct shrinker *shrink, extern int nfs_access_cache_shrinker(struct shrinker *shrink,
...@@ -280,9 +276,10 @@ extern void nfs_sb_deactive(struct super_block *sb); ...@@ -280,9 +276,10 @@ extern void nfs_sb_deactive(struct super_block *sb);
extern char *nfs_path(char **p, struct dentry *dentry, extern char *nfs_path(char **p, struct dentry *dentry,
char *buffer, ssize_t buflen); char *buffer, ssize_t buflen);
extern struct vfsmount *nfs_d_automount(struct path *path); extern struct vfsmount *nfs_d_automount(struct path *path);
#ifdef CONFIG_NFS_V4 struct vfsmount *nfs_submount(struct nfs_server *, struct dentry *,
rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *); struct nfs_fh *, struct nfs_fattr *);
#endif struct vfsmount *nfs_do_submount(struct dentry *, struct nfs_fh *,
struct nfs_fattr *, rpc_authflavor_t);
/* getroot.c */ /* getroot.c */
extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *, extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *,
...@@ -294,46 +291,73 @@ extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *, ...@@ -294,46 +291,73 @@ extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *,
extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh); extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh);
#endif #endif
struct nfs_pageio_descriptor; struct nfs_pgio_completion_ops;
/* read.c */ /* read.c */
extern int nfs_initiate_read(struct nfs_read_data *data, struct rpc_clnt *clnt, extern struct nfs_read_header *nfs_readhdr_alloc(void);
const struct rpc_call_ops *call_ops); extern void nfs_readhdr_free(struct nfs_pgio_header *hdr);
extern void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
struct inode *inode,
const struct nfs_pgio_completion_ops *compl_ops);
extern int nfs_initiate_read(struct rpc_clnt *clnt,
struct nfs_read_data *data,
const struct rpc_call_ops *call_ops, int flags);
extern void nfs_read_prepare(struct rpc_task *task, void *calldata); extern void nfs_read_prepare(struct rpc_task *task, void *calldata);
extern int nfs_generic_pagein(struct nfs_pageio_descriptor *desc, extern int nfs_generic_pagein(struct nfs_pageio_descriptor *desc,
struct list_head *head); struct nfs_pgio_header *hdr);
extern void nfs_pageio_init_read_mds(struct nfs_pageio_descriptor *pgio, extern void nfs_pageio_init_read_mds(struct nfs_pageio_descriptor *pgio,
struct inode *inode); struct inode *inode,
const struct nfs_pgio_completion_ops *compl_ops);
extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio); extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio);
extern void nfs_readdata_release(struct nfs_read_data *rdata); extern void nfs_readdata_release(struct nfs_read_data *rdata);
/* write.c */ /* write.c */
extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
struct inode *inode, int ioflags,
const struct nfs_pgio_completion_ops *compl_ops);
extern struct nfs_write_header *nfs_writehdr_alloc(void);
extern void nfs_writehdr_free(struct nfs_pgio_header *hdr);
extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc, extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc,
struct list_head *head); struct nfs_pgio_header *hdr);
extern void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio, extern void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio,
struct inode *inode, int ioflags); struct inode *inode, int ioflags,
const struct nfs_pgio_completion_ops *compl_ops);
extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio); extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio);
extern void nfs_writedata_release(struct nfs_write_data *wdata); extern void nfs_writedata_release(struct nfs_write_data *wdata);
extern void nfs_commit_free(struct nfs_write_data *p); extern void nfs_commit_free(struct nfs_commit_data *p);
extern int nfs_initiate_write(struct nfs_write_data *data, extern int nfs_initiate_write(struct rpc_clnt *clnt,
struct rpc_clnt *clnt, struct nfs_write_data *data,
const struct rpc_call_ops *call_ops, const struct rpc_call_ops *call_ops,
int how); int how, int flags);
extern void nfs_write_prepare(struct rpc_task *task, void *calldata); extern void nfs_write_prepare(struct rpc_task *task, void *calldata);
extern int nfs_initiate_commit(struct nfs_write_data *data, extern void nfs_commit_prepare(struct rpc_task *task, void *calldata);
struct rpc_clnt *clnt, extern int nfs_initiate_commit(struct rpc_clnt *clnt,
struct nfs_commit_data *data,
const struct rpc_call_ops *call_ops, const struct rpc_call_ops *call_ops,
int how); int how, int flags);
extern void nfs_init_commit(struct nfs_write_data *data, extern void nfs_init_commit(struct nfs_commit_data *data,
struct list_head *head, struct list_head *head,
struct pnfs_layout_segment *lseg); struct pnfs_layout_segment *lseg,
struct nfs_commit_info *cinfo);
int nfs_scan_commit_list(struct list_head *src, struct list_head *dst,
struct nfs_commit_info *cinfo, int max);
int nfs_scan_commit(struct inode *inode, struct list_head *dst,
struct nfs_commit_info *cinfo);
void nfs_mark_request_commit(struct nfs_page *req,
struct pnfs_layout_segment *lseg,
struct nfs_commit_info *cinfo);
int nfs_generic_commit_list(struct inode *inode, struct list_head *head,
int how, struct nfs_commit_info *cinfo);
void nfs_retry_commit(struct list_head *page_list, void nfs_retry_commit(struct list_head *page_list,
struct pnfs_layout_segment *lseg); struct pnfs_layout_segment *lseg,
void nfs_commit_clear_lock(struct nfs_inode *nfsi); struct nfs_commit_info *cinfo);
void nfs_commitdata_release(void *data); void nfs_commitdata_release(struct nfs_commit_data *data);
void nfs_commit_release_pages(struct nfs_write_data *data); void nfs_request_add_commit_list(struct nfs_page *req, struct list_head *dst,
void nfs_request_add_commit_list(struct nfs_page *req, struct list_head *head); struct nfs_commit_info *cinfo);
void nfs_request_remove_commit_list(struct nfs_page *req); void nfs_request_remove_commit_list(struct nfs_page *req,
struct nfs_commit_info *cinfo);
void nfs_init_cinfo(struct nfs_commit_info *cinfo,
struct inode *inode,
struct nfs_direct_req *dreq);
#ifdef CONFIG_MIGRATION #ifdef CONFIG_MIGRATION
extern int nfs_migrate_page(struct address_space *, extern int nfs_migrate_page(struct address_space *,
...@@ -342,15 +366,16 @@ extern int nfs_migrate_page(struct address_space *, ...@@ -342,15 +366,16 @@ extern int nfs_migrate_page(struct address_space *,
#define nfs_migrate_page NULL #define nfs_migrate_page NULL
#endif #endif
/* direct.c */
void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo,
struct nfs_direct_req *dreq);
/* nfs4proc.c */ /* nfs4proc.c */
extern void __nfs4_read_done_cb(struct nfs_read_data *); extern void __nfs4_read_done_cb(struct nfs_read_data *);
extern void nfs4_reset_read(struct rpc_task *task, struct nfs_read_data *data); extern struct nfs_client *nfs4_init_client(struct nfs_client *clp,
extern int nfs4_init_client(struct nfs_client *clp,
const struct rpc_timeout *timeparms, const struct rpc_timeout *timeparms,
const char *ip_addr, const char *ip_addr,
rpc_authflavor_t authflavour, rpc_authflavor_t authflavour);
int noresvport);
extern void nfs4_reset_write(struct rpc_task *task, struct nfs_write_data *data);
extern int _nfs4_call_sync(struct rpc_clnt *clnt, extern int _nfs4_call_sync(struct rpc_clnt *clnt,
struct nfs_server *server, struct nfs_server *server,
struct rpc_message *msg, struct rpc_message *msg,
...@@ -466,3 +491,15 @@ unsigned int nfs_page_array_len(unsigned int base, size_t len) ...@@ -466,3 +491,15 @@ unsigned int nfs_page_array_len(unsigned int base, size_t len)
PAGE_SIZE - 1) >> PAGE_SHIFT; PAGE_SIZE - 1) >> PAGE_SHIFT;
} }
/*
* Convert a struct timespec into a 64-bit change attribute
*
* This does approximately the same thing as timespec_to_ns(),
* but for calculation efficiency, we multiply the seconds by
* 1024*1024*1024.
*/
static inline
u64 nfs_timespec_to_change_attr(const struct timespec *ts)
{
return ((u64)ts->tv_sec << 30) + ts->tv_nsec;
}
...@@ -26,11 +26,6 @@ static LIST_HEAD(nfs_automount_list); ...@@ -26,11 +26,6 @@ static LIST_HEAD(nfs_automount_list);
static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts); static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts);
int nfs_mountpoint_expiry_timeout = 500 * HZ; int nfs_mountpoint_expiry_timeout = 500 * HZ;
static struct vfsmount *nfs_do_submount(struct dentry *dentry,
struct nfs_fh *fh,
struct nfs_fattr *fattr,
rpc_authflavor_t authflavor);
/* /*
* nfs_path - reconstruct the path given an arbitrary dentry * nfs_path - reconstruct the path given an arbitrary dentry
* @base - used to return pointer to the end of devname part of path * @base - used to return pointer to the end of devname part of path
...@@ -118,64 +113,6 @@ char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen) ...@@ -118,64 +113,6 @@ char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen)
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
} }
#ifdef CONFIG_NFS_V4
rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
{
struct gss_api_mech *mech;
struct xdr_netobj oid;
int i;
rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX;
for (i = 0; i < flavors->num_flavors; i++) {
struct nfs4_secinfo_flavor *flavor;
flavor = &flavors->flavors[i];
if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) {
pseudoflavor = flavor->flavor;
break;
} else if (flavor->flavor == RPC_AUTH_GSS) {
oid.len = flavor->gss.sec_oid4.len;
oid.data = flavor->gss.sec_oid4.data;
mech = gss_mech_get_by_OID(&oid);
if (!mech)
continue;
pseudoflavor = gss_svc_to_pseudoflavor(mech, flavor->gss.service);
gss_mech_put(mech);
break;
}
}
return pseudoflavor;
}
static struct rpc_clnt *nfs_lookup_mountpoint(struct inode *dir,
struct qstr *name,
struct nfs_fh *fh,
struct nfs_fattr *fattr)
{
int err;
if (NFS_PROTO(dir)->version == 4)
return nfs4_proc_lookup_mountpoint(dir, name, fh, fattr);
err = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, name, fh, fattr);
if (err)
return ERR_PTR(err);
return rpc_clone_client(NFS_SERVER(dir)->client);
}
#else /* CONFIG_NFS_V4 */
static inline struct rpc_clnt *nfs_lookup_mountpoint(struct inode *dir,
struct qstr *name,
struct nfs_fh *fh,
struct nfs_fattr *fattr)
{
int err = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, name, fh, fattr);
if (err)
return ERR_PTR(err);
return rpc_clone_client(NFS_SERVER(dir)->client);
}
#endif /* CONFIG_NFS_V4 */
/* /*
* nfs_d_automount - Handle crossing a mountpoint on the server * nfs_d_automount - Handle crossing a mountpoint on the server
* @path - The mountpoint * @path - The mountpoint
...@@ -191,10 +128,9 @@ static inline struct rpc_clnt *nfs_lookup_mountpoint(struct inode *dir, ...@@ -191,10 +128,9 @@ static inline struct rpc_clnt *nfs_lookup_mountpoint(struct inode *dir,
struct vfsmount *nfs_d_automount(struct path *path) struct vfsmount *nfs_d_automount(struct path *path)
{ {
struct vfsmount *mnt; struct vfsmount *mnt;
struct dentry *parent; struct nfs_server *server = NFS_SERVER(path->dentry->d_inode);
struct nfs_fh *fh = NULL; struct nfs_fh *fh = NULL;
struct nfs_fattr *fattr = NULL; struct nfs_fattr *fattr = NULL;
struct rpc_clnt *client;
dprintk("--> nfs_d_automount()\n"); dprintk("--> nfs_d_automount()\n");
...@@ -210,21 +146,7 @@ struct vfsmount *nfs_d_automount(struct path *path) ...@@ -210,21 +146,7 @@ struct vfsmount *nfs_d_automount(struct path *path)
dprintk("%s: enter\n", __func__); dprintk("%s: enter\n", __func__);
/* Look it up again to get its attributes */ mnt = server->nfs_client->rpc_ops->submount(server, path->dentry, fh, fattr);
parent = dget_parent(path->dentry);
client = nfs_lookup_mountpoint(parent->d_inode, &path->dentry->d_name, fh, fattr);
dput(parent);
if (IS_ERR(client)) {
mnt = ERR_CAST(client);
goto out;
}
if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
mnt = nfs_do_refmount(client, path->dentry);
else
mnt = nfs_do_submount(path->dentry, fh, fattr, client->cl_auth->au_flavor);
rpc_shutdown_client(client);
if (IS_ERR(mnt)) if (IS_ERR(mnt))
goto out; goto out;
...@@ -297,10 +219,8 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, ...@@ -297,10 +219,8 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
* @authflavor - security flavor to use when performing the mount * @authflavor - security flavor to use when performing the mount
* *
*/ */
static struct vfsmount *nfs_do_submount(struct dentry *dentry, struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh,
struct nfs_fh *fh, struct nfs_fattr *fattr, rpc_authflavor_t authflavor)
struct nfs_fattr *fattr,
rpc_authflavor_t authflavor)
{ {
struct nfs_clone_mount mountdata = { struct nfs_clone_mount mountdata = {
.sb = dentry->d_sb, .sb = dentry->d_sb,
...@@ -333,3 +253,18 @@ static struct vfsmount *nfs_do_submount(struct dentry *dentry, ...@@ -333,3 +253,18 @@ static struct vfsmount *nfs_do_submount(struct dentry *dentry,
dprintk("<-- nfs_do_submount() = %p\n", mnt); dprintk("<-- nfs_do_submount() = %p\n", mnt);
return mnt; return mnt;
} }
struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry,
struct nfs_fh *fh, struct nfs_fattr *fattr)
{
int err;
struct dentry *parent = dget_parent(dentry);
/* Look it up again to get its attributes */
err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr);
dput(parent);
if (err != 0)
return ERR_PTR(err);
return nfs_do_submount(dentry, fh, fattr, server->client->cl_auth->au_flavor);
}
/*
* NFS-private data for each "struct net". Accessed with net_generic().
*/
#ifndef __NFS_NETNS_H__ #ifndef __NFS_NETNS_H__
#define __NFS_NETNS_H__ #define __NFS_NETNS_H__
...@@ -20,6 +24,7 @@ struct nfs_net { ...@@ -20,6 +24,7 @@ struct nfs_net {
struct idr cb_ident_idr; /* Protected by nfs_client_lock */ struct idr cb_ident_idr; /* Protected by nfs_client_lock */
#endif #endif
spinlock_t nfs_client_lock; spinlock_t nfs_client_lock;
struct timespec boot_time;
}; };
extern int nfs_net_id; extern int nfs_net_id;
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
#define NFS_readdirres_sz (1) #define NFS_readdirres_sz (1)
#define NFS_statfsres_sz (1+NFS_info_sz) #define NFS_statfsres_sz (1+NFS_info_sz)
static int nfs_stat_to_errno(enum nfs_stat);
/* /*
* While encoding arguments, set up the reply buffer in advance to * While encoding arguments, set up the reply buffer in advance to
...@@ -313,6 +314,8 @@ static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr) ...@@ -313,6 +314,8 @@ static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
p = xdr_decode_time(p, &fattr->atime); p = xdr_decode_time(p, &fattr->atime);
p = xdr_decode_time(p, &fattr->mtime); p = xdr_decode_time(p, &fattr->mtime);
xdr_decode_time(p, &fattr->ctime); xdr_decode_time(p, &fattr->ctime);
fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime);
return 0; return 0;
out_overflow: out_overflow:
print_overflow_msg(__func__, xdr); print_overflow_msg(__func__, xdr);
...@@ -1109,7 +1112,7 @@ static const struct { ...@@ -1109,7 +1112,7 @@ static const struct {
* Returns a local errno value, or -EIO if the NFS status code is * Returns a local errno value, or -EIO if the NFS status code is
* not recognized. This function is used jointly by NFSv2 and NFSv3. * not recognized. This function is used jointly by NFSv2 and NFSv3.
*/ */
int nfs_stat_to_errno(enum nfs_stat status) static int nfs_stat_to_errno(enum nfs_stat status)
{ {
int i; int i;
......
...@@ -142,7 +142,7 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, ...@@ -142,7 +142,7 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
} }
static int static int
nfs3_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name, nfs3_proc_lookup(struct inode *dir, struct qstr *name,
struct nfs_fh *fhandle, struct nfs_fattr *fattr) struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{ {
struct nfs3_diropargs arg = { struct nfs3_diropargs arg = {
...@@ -810,11 +810,13 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -810,11 +810,13 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data) static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data)
{ {
if (nfs3_async_handle_jukebox(task, data->inode)) struct inode *inode = data->header->inode;
if (nfs3_async_handle_jukebox(task, inode))
return -EAGAIN; return -EAGAIN;
nfs_invalidate_atime(data->inode); nfs_invalidate_atime(inode);
nfs_refresh_inode(data->inode, &data->fattr); nfs_refresh_inode(inode, &data->fattr);
return 0; return 0;
} }
...@@ -830,10 +832,12 @@ static void nfs3_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_da ...@@ -830,10 +832,12 @@ static void nfs3_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_da
static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data)
{ {
if (nfs3_async_handle_jukebox(task, data->inode)) struct inode *inode = data->header->inode;
if (nfs3_async_handle_jukebox(task, inode))
return -EAGAIN; return -EAGAIN;
if (task->tk_status >= 0) if (task->tk_status >= 0)
nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr); nfs_post_op_update_inode_force_wcc(inode, data->res.fattr);
return 0; return 0;
} }
...@@ -847,7 +851,12 @@ static void nfs3_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_ ...@@ -847,7 +851,12 @@ static void nfs3_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_
rpc_call_start(task); rpc_call_start(task);
} }
static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data) static void nfs3_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
{
rpc_call_start(task);
}
static int nfs3_commit_done(struct rpc_task *task, struct nfs_commit_data *data)
{ {
if (nfs3_async_handle_jukebox(task, data->inode)) if (nfs3_async_handle_jukebox(task, data->inode))
return -EAGAIN; return -EAGAIN;
...@@ -855,7 +864,7 @@ static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data) ...@@ -855,7 +864,7 @@ static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data)
return 0; return 0;
} }
static void nfs3_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg) static void nfs3_proc_commit_setup(struct nfs_commit_data *data, struct rpc_message *msg)
{ {
msg->rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT]; msg->rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT];
} }
...@@ -875,6 +884,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = { ...@@ -875,6 +884,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
.file_inode_ops = &nfs3_file_inode_operations, .file_inode_ops = &nfs3_file_inode_operations,
.file_ops = &nfs_file_operations, .file_ops = &nfs_file_operations,
.getroot = nfs3_proc_get_root, .getroot = nfs3_proc_get_root,
.submount = nfs_submount,
.getattr = nfs3_proc_getattr, .getattr = nfs3_proc_getattr,
.setattr = nfs3_proc_setattr, .setattr = nfs3_proc_setattr,
.lookup = nfs3_proc_lookup, .lookup = nfs3_proc_lookup,
...@@ -906,6 +916,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = { ...@@ -906,6 +916,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
.write_rpc_prepare = nfs3_proc_write_rpc_prepare, .write_rpc_prepare = nfs3_proc_write_rpc_prepare,
.write_done = nfs3_write_done, .write_done = nfs3_write_done,
.commit_setup = nfs3_proc_commit_setup, .commit_setup = nfs3_proc_commit_setup,
.commit_rpc_prepare = nfs3_proc_commit_rpc_prepare,
.commit_done = nfs3_commit_done, .commit_done = nfs3_commit_done,
.lock = nfs3_proc_lock, .lock = nfs3_proc_lock,
.clear_acl_cache = nfs3_forget_cached_acls, .clear_acl_cache = nfs3_forget_cached_acls,
......
...@@ -86,6 +86,8 @@ ...@@ -86,6 +86,8 @@
XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
#define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz) #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
static int nfs3_stat_to_errno(enum nfs_stat);
/* /*
* Map file type to S_IFMT bits * Map file type to S_IFMT bits
*/ */
...@@ -675,6 +677,7 @@ static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr) ...@@ -675,6 +677,7 @@ static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr)
p = xdr_decode_nfstime3(p, &fattr->atime); p = xdr_decode_nfstime3(p, &fattr->atime);
p = xdr_decode_nfstime3(p, &fattr->mtime); p = xdr_decode_nfstime3(p, &fattr->mtime);
xdr_decode_nfstime3(p, &fattr->ctime); xdr_decode_nfstime3(p, &fattr->ctime);
fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime);
fattr->valid |= NFS_ATTR_FATTR_V3; fattr->valid |= NFS_ATTR_FATTR_V3;
return 0; return 0;
...@@ -725,12 +728,14 @@ static int decode_wcc_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr) ...@@ -725,12 +728,14 @@ static int decode_wcc_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
goto out_overflow; goto out_overflow;
fattr->valid |= NFS_ATTR_FATTR_PRESIZE fattr->valid |= NFS_ATTR_FATTR_PRESIZE
| NFS_ATTR_FATTR_PRECHANGE
| NFS_ATTR_FATTR_PREMTIME | NFS_ATTR_FATTR_PREMTIME
| NFS_ATTR_FATTR_PRECTIME; | NFS_ATTR_FATTR_PRECTIME;
p = xdr_decode_size3(p, &fattr->pre_size); p = xdr_decode_size3(p, &fattr->pre_size);
p = xdr_decode_nfstime3(p, &fattr->pre_mtime); p = xdr_decode_nfstime3(p, &fattr->pre_mtime);
xdr_decode_nfstime3(p, &fattr->pre_ctime); xdr_decode_nfstime3(p, &fattr->pre_ctime);
fattr->pre_change_attr = nfs_timespec_to_change_attr(&fattr->pre_ctime);
return 0; return 0;
out_overflow: out_overflow:
...@@ -1287,7 +1292,7 @@ static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, ...@@ -1287,7 +1292,7 @@ static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req,
* }; * };
*/ */
static void encode_commit3args(struct xdr_stream *xdr, static void encode_commit3args(struct xdr_stream *xdr,
const struct nfs_writeargs *args) const struct nfs_commitargs *args)
{ {
__be32 *p; __be32 *p;
...@@ -1300,7 +1305,7 @@ static void encode_commit3args(struct xdr_stream *xdr, ...@@ -1300,7 +1305,7 @@ static void encode_commit3args(struct xdr_stream *xdr,
static void nfs3_xdr_enc_commit3args(struct rpc_rqst *req, static void nfs3_xdr_enc_commit3args(struct rpc_rqst *req,
struct xdr_stream *xdr, struct xdr_stream *xdr,
const struct nfs_writeargs *args) const struct nfs_commitargs *args)
{ {
encode_commit3args(xdr, args); encode_commit3args(xdr, args);
} }
...@@ -1385,7 +1390,7 @@ static int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req, ...@@ -1385,7 +1390,7 @@ static int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req,
out: out:
return error; return error;
out_default: out_default:
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
/* /*
...@@ -1424,7 +1429,7 @@ static int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req, ...@@ -1424,7 +1429,7 @@ static int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req,
out: out:
return error; return error;
out_status: out_status:
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
/* /*
...@@ -1472,7 +1477,7 @@ static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req, ...@@ -1472,7 +1477,7 @@ static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req,
error = decode_post_op_attr(xdr, result->dir_attr); error = decode_post_op_attr(xdr, result->dir_attr);
if (unlikely(error)) if (unlikely(error))
goto out; goto out;
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
/* /*
...@@ -1513,7 +1518,7 @@ static int nfs3_xdr_dec_access3res(struct rpc_rqst *req, ...@@ -1513,7 +1518,7 @@ static int nfs3_xdr_dec_access3res(struct rpc_rqst *req,
out: out:
return error; return error;
out_default: out_default:
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
/* /*
...@@ -1554,7 +1559,7 @@ static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req, ...@@ -1554,7 +1559,7 @@ static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req,
out: out:
return error; return error;
out_default: out_default:
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
/* /*
...@@ -1636,7 +1641,7 @@ static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -1636,7 +1641,7 @@ static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr,
out: out:
return error; return error;
out_status: out_status:
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
/* /*
...@@ -1706,7 +1711,7 @@ static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -1706,7 +1711,7 @@ static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr,
out: out:
return error; return error;
out_status: out_status:
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
/* /*
...@@ -1770,7 +1775,7 @@ static int nfs3_xdr_dec_create3res(struct rpc_rqst *req, ...@@ -1770,7 +1775,7 @@ static int nfs3_xdr_dec_create3res(struct rpc_rqst *req,
error = decode_wcc_data(xdr, result->dir_attr); error = decode_wcc_data(xdr, result->dir_attr);
if (unlikely(error)) if (unlikely(error))
goto out; goto out;
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
/* /*
...@@ -1809,7 +1814,7 @@ static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req, ...@@ -1809,7 +1814,7 @@ static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req,
out: out:
return error; return error;
out_status: out_status:
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
/* /*
...@@ -1853,7 +1858,7 @@ static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req, ...@@ -1853,7 +1858,7 @@ static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req,
out: out:
return error; return error;
out_status: out_status:
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
/* /*
...@@ -1896,7 +1901,7 @@ static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -1896,7 +1901,7 @@ static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr,
out: out:
return error; return error;
out_status: out_status:
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
/** /**
...@@ -2088,7 +2093,7 @@ static int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req, ...@@ -2088,7 +2093,7 @@ static int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req,
error = decode_post_op_attr(xdr, result->dir_attr); error = decode_post_op_attr(xdr, result->dir_attr);
if (unlikely(error)) if (unlikely(error))
goto out; goto out;
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
/* /*
...@@ -2156,7 +2161,7 @@ static int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req, ...@@ -2156,7 +2161,7 @@ static int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req,
out: out:
return error; return error;
out_status: out_status:
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
/* /*
...@@ -2232,7 +2237,7 @@ static int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req, ...@@ -2232,7 +2237,7 @@ static int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req,
out: out:
return error; return error;
out_status: out_status:
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
/* /*
...@@ -2295,7 +2300,7 @@ static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req, ...@@ -2295,7 +2300,7 @@ static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req,
out: out:
return error; return error;
out_status: out_status:
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
/* /*
...@@ -2319,7 +2324,7 @@ static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req, ...@@ -2319,7 +2324,7 @@ static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req,
*/ */
static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req, static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req,
struct xdr_stream *xdr, struct xdr_stream *xdr,
struct nfs_writeres *result) struct nfs_commitres *result)
{ {
enum nfs_stat status; enum nfs_stat status;
int error; int error;
...@@ -2336,7 +2341,7 @@ static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req, ...@@ -2336,7 +2341,7 @@ static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req,
out: out:
return error; return error;
out_status: out_status:
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
#ifdef CONFIG_NFS_V3_ACL #ifdef CONFIG_NFS_V3_ACL
...@@ -2401,7 +2406,7 @@ static int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req, ...@@ -2401,7 +2406,7 @@ static int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req,
out: out:
return error; return error;
out_default: out_default:
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req, static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req,
...@@ -2420,11 +2425,76 @@ static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req, ...@@ -2420,11 +2425,76 @@ static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req,
out: out:
return error; return error;
out_default: out_default:
return nfs_stat_to_errno(status); return nfs3_stat_to_errno(status);
} }
#endif /* CONFIG_NFS_V3_ACL */ #endif /* CONFIG_NFS_V3_ACL */
/*
* We need to translate between nfs status return values and
* the local errno values which may not be the same.
*/
static const struct {
int stat;
int errno;
} nfs_errtbl[] = {
{ NFS_OK, 0 },
{ NFSERR_PERM, -EPERM },
{ NFSERR_NOENT, -ENOENT },
{ NFSERR_IO, -errno_NFSERR_IO},
{ NFSERR_NXIO, -ENXIO },
/* { NFSERR_EAGAIN, -EAGAIN }, */
{ NFSERR_ACCES, -EACCES },
{ NFSERR_EXIST, -EEXIST },
{ NFSERR_XDEV, -EXDEV },
{ NFSERR_NODEV, -ENODEV },
{ NFSERR_NOTDIR, -ENOTDIR },
{ NFSERR_ISDIR, -EISDIR },
{ NFSERR_INVAL, -EINVAL },
{ NFSERR_FBIG, -EFBIG },
{ NFSERR_NOSPC, -ENOSPC },
{ NFSERR_ROFS, -EROFS },
{ NFSERR_MLINK, -EMLINK },
{ NFSERR_NAMETOOLONG, -ENAMETOOLONG },
{ NFSERR_NOTEMPTY, -ENOTEMPTY },
{ NFSERR_DQUOT, -EDQUOT },
{ NFSERR_STALE, -ESTALE },
{ NFSERR_REMOTE, -EREMOTE },
#ifdef EWFLUSH
{ NFSERR_WFLUSH, -EWFLUSH },
#endif
{ NFSERR_BADHANDLE, -EBADHANDLE },
{ NFSERR_NOT_SYNC, -ENOTSYNC },
{ NFSERR_BAD_COOKIE, -EBADCOOKIE },
{ NFSERR_NOTSUPP, -ENOTSUPP },
{ NFSERR_TOOSMALL, -ETOOSMALL },
{ NFSERR_SERVERFAULT, -EREMOTEIO },
{ NFSERR_BADTYPE, -EBADTYPE },
{ NFSERR_JUKEBOX, -EJUKEBOX },
{ -1, -EIO }
};
/**
* nfs3_stat_to_errno - convert an NFS status code to a local errno
* @status: NFS status code to convert
*
* Returns a local errno value, or -EIO if the NFS status code is
* not recognized. This function is used jointly by NFSv2 and NFSv3.
*/
static int nfs3_stat_to_errno(enum nfs_stat status)
{
int i;
for (i = 0; nfs_errtbl[i].stat != -1; i++) {
if (nfs_errtbl[i].stat == (int)status)
return nfs_errtbl[i].errno;
}
dprintk("NFS: Unrecognized nfs status value: %u\n", status);
return nfs_errtbl[i].errno;
}
#define PROC(proc, argtype, restype, timer) \ #define PROC(proc, argtype, restype, timer) \
[NFS3PROC_##proc] = { \ [NFS3PROC_##proc] = { \
.p_proc = NFS3PROC_##proc, \ .p_proc = NFS3PROC_##proc, \
......
...@@ -24,6 +24,8 @@ enum nfs4_client_state { ...@@ -24,6 +24,8 @@ enum nfs4_client_state {
NFS4CLNT_RECALL_SLOT, NFS4CLNT_RECALL_SLOT,
NFS4CLNT_LEASE_CONFIRM, NFS4CLNT_LEASE_CONFIRM,
NFS4CLNT_SERVER_SCOPE_MISMATCH, NFS4CLNT_SERVER_SCOPE_MISMATCH,
NFS4CLNT_PURGE_STATE,
NFS4CLNT_BIND_CONN_TO_SESSION,
}; };
enum nfs4_session_state { enum nfs4_session_state {
...@@ -52,11 +54,6 @@ struct nfs4_minor_version_ops { ...@@ -52,11 +54,6 @@ struct nfs4_minor_version_ops {
const struct nfs4_state_maintenance_ops *state_renewal_ops; const struct nfs4_state_maintenance_ops *state_renewal_ops;
}; };
struct nfs_unique_id {
struct rb_node rb_node;
__u64 id;
};
#define NFS_SEQID_CONFIRMED 1 #define NFS_SEQID_CONFIRMED 1
struct nfs_seqid_counter { struct nfs_seqid_counter {
ktime_t create_time; ktime_t create_time;
...@@ -206,12 +203,18 @@ extern const struct dentry_operations nfs4_dentry_operations; ...@@ -206,12 +203,18 @@ extern const struct dentry_operations nfs4_dentry_operations;
extern const struct inode_operations nfs4_dir_inode_operations; extern const struct inode_operations nfs4_dir_inode_operations;
/* nfs4namespace.c */ /* nfs4namespace.c */
rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *);
struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *); struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *);
struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *,
struct nfs_fh *, struct nfs_fattr *);
/* nfs4proc.c */ /* nfs4proc.c */
extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *); extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *);
extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, struct rpc_cred *); extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, struct rpc_cred *);
extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
extern int nfs4_proc_bind_conn_to_session(struct nfs_client *, struct rpc_cred *cred);
extern int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred); extern int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred);
extern int nfs4_destroy_clientid(struct nfs_client *clp);
extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *);
extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *);
extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc); extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc);
...@@ -239,8 +242,8 @@ extern int nfs41_setup_sequence(struct nfs4_session *session, ...@@ -239,8 +242,8 @@ extern int nfs41_setup_sequence(struct nfs4_session *session,
struct rpc_task *task); struct rpc_task *task);
extern void nfs4_destroy_session(struct nfs4_session *session); extern void nfs4_destroy_session(struct nfs4_session *session);
extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp);
extern int nfs4_proc_create_session(struct nfs_client *); extern int nfs4_proc_create_session(struct nfs_client *, struct rpc_cred *);
extern int nfs4_proc_destroy_session(struct nfs4_session *); extern int nfs4_proc_destroy_session(struct nfs4_session *, struct rpc_cred *);
extern int nfs4_init_session(struct nfs_server *server); extern int nfs4_init_session(struct nfs_server *server);
extern int nfs4_proc_get_lease_time(struct nfs_client *clp, extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
struct nfs_fsinfo *fsinfo); struct nfs_fsinfo *fsinfo);
...@@ -310,9 +313,9 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp); ...@@ -310,9 +313,9 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp);
#if defined(CONFIG_NFS_V4_1) #if defined(CONFIG_NFS_V4_1)
struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp); struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp);
struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp); struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp);
extern void nfs4_schedule_session_recovery(struct nfs4_session *); extern void nfs4_schedule_session_recovery(struct nfs4_session *, int);
#else #else
static inline void nfs4_schedule_session_recovery(struct nfs4_session *session) static inline void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
{ {
} }
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
...@@ -334,7 +337,7 @@ extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs ...@@ -334,7 +337,7 @@ extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs
extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags);
extern void nfs41_handle_recall_slot(struct nfs_client *clp); extern void nfs41_handle_recall_slot(struct nfs_client *clp);
extern void nfs41_handle_server_scope(struct nfs_client *, extern void nfs41_handle_server_scope(struct nfs_client *,
struct server_scope **); struct nfs41_server_scope **);
extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
extern void nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *, extern void nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *,
......
This diff is collapsed.
...@@ -32,6 +32,13 @@ ...@@ -32,6 +32,13 @@
#include "pnfs.h" #include "pnfs.h"
/*
* Default data server connection timeout and retrans vaules.
* Set by module paramters dataserver_timeo and dataserver_retrans.
*/
#define NFS4_DEF_DS_TIMEO 60
#define NFS4_DEF_DS_RETRANS 5
/* /*
* Field testing shows we need to support up to 4096 stripe indices. * Field testing shows we need to support up to 4096 stripe indices.
* We store each index as a u8 (u32 on the wire) to keep the memory footprint * We store each index as a u8 (u32 on the wire) to keep the memory footprint
...@@ -41,6 +48,9 @@ ...@@ -41,6 +48,9 @@
#define NFS4_PNFS_MAX_STRIPE_CNT 4096 #define NFS4_PNFS_MAX_STRIPE_CNT 4096
#define NFS4_PNFS_MAX_MULTI_CNT 256 /* 256 fit into a u8 stripe_index */ #define NFS4_PNFS_MAX_MULTI_CNT 256 /* 256 fit into a u8 stripe_index */
/* error codes for internal use */
#define NFS4ERR_RESET_TO_MDS 12001
enum stripetype4 { enum stripetype4 {
STRIPE_SPARSE = 1, STRIPE_SPARSE = 1,
STRIPE_DENSE = 2 STRIPE_DENSE = 2
...@@ -62,23 +72,14 @@ struct nfs4_pnfs_ds { ...@@ -62,23 +72,14 @@ struct nfs4_pnfs_ds {
atomic_t ds_count; atomic_t ds_count;
}; };
/* nfs4_file_layout_dsaddr flags */
#define NFS4_DEVICE_ID_NEG_ENTRY 0x00000001
struct nfs4_file_layout_dsaddr { struct nfs4_file_layout_dsaddr {
struct nfs4_deviceid_node id_node; struct nfs4_deviceid_node id_node;
unsigned long flags;
u32 stripe_count; u32 stripe_count;
u8 *stripe_indices; u8 *stripe_indices;
u32 ds_num; u32 ds_num;
struct nfs4_pnfs_ds *ds_list[1]; struct nfs4_pnfs_ds *ds_list[1];
}; };
struct nfs4_fl_commit_bucket {
struct list_head written;
struct list_head committing;
};
struct nfs4_filelayout_segment { struct nfs4_filelayout_segment {
struct pnfs_layout_segment generic_hdr; struct pnfs_layout_segment generic_hdr;
u32 stripe_type; u32 stripe_type;
...@@ -89,10 +90,19 @@ struct nfs4_filelayout_segment { ...@@ -89,10 +90,19 @@ struct nfs4_filelayout_segment {
struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */ struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */
unsigned int num_fh; unsigned int num_fh;
struct nfs_fh **fh_array; struct nfs_fh **fh_array;
struct nfs4_fl_commit_bucket *commit_buckets; /* Sort commits to ds */
int number_of_buckets;
}; };
struct nfs4_filelayout {
struct pnfs_layout_hdr generic_hdr;
struct pnfs_ds_commit_info commit_info;
};
static inline struct nfs4_filelayout *
FILELAYOUT_FROM_HDR(struct pnfs_layout_hdr *lo)
{
return container_of(lo, struct nfs4_filelayout, generic_hdr);
}
static inline struct nfs4_filelayout_segment * static inline struct nfs4_filelayout_segment *
FILELAYOUT_LSEG(struct pnfs_layout_segment *lseg) FILELAYOUT_LSEG(struct pnfs_layout_segment *lseg)
{ {
...@@ -107,6 +117,36 @@ FILELAYOUT_DEVID_NODE(struct pnfs_layout_segment *lseg) ...@@ -107,6 +117,36 @@ FILELAYOUT_DEVID_NODE(struct pnfs_layout_segment *lseg)
return &FILELAYOUT_LSEG(lseg)->dsaddr->id_node; return &FILELAYOUT_LSEG(lseg)->dsaddr->id_node;
} }
static inline void
filelayout_mark_devid_invalid(struct nfs4_deviceid_node *node)
{
u32 *p = (u32 *)&node->deviceid;
printk(KERN_WARNING "NFS: Deviceid [%x%x%x%x] marked out of use.\n",
p[0], p[1], p[2], p[3]);
set_bit(NFS_DEVICEID_INVALID, &node->flags);
}
static inline bool
filelayout_test_layout_invalid(struct pnfs_layout_hdr *lo)
{
return test_bit(NFS_LAYOUT_INVALID, &lo->plh_flags);
}
static inline bool
filelayout_test_devid_invalid(struct nfs4_deviceid_node *node)
{
return test_bit(NFS_DEVICEID_INVALID, &node->flags);
}
static inline bool
filelayout_reset_to_mds(struct pnfs_layout_segment *lseg)
{
return filelayout_test_devid_invalid(FILELAYOUT_DEVID_NODE(lseg)) ||
filelayout_test_layout_invalid(lseg->pls_layout);
}
extern struct nfs_fh * extern struct nfs_fh *
nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j); nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j);
...@@ -119,5 +159,6 @@ extern void nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr); ...@@ -119,5 +159,6 @@ extern void nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr);
extern void nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr); extern void nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr);
struct nfs4_file_layout_dsaddr * struct nfs4_file_layout_dsaddr *
get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags); get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags);
void nfs4_ds_disconnect(struct nfs_client *clp);
#endif /* FS_NFS_NFS4FILELAYOUT_H */ #endif /* FS_NFS_NFS4FILELAYOUT_H */
...@@ -30,12 +30,16 @@ ...@@ -30,12 +30,16 @@
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/module.h>
#include "internal.h" #include "internal.h"
#include "nfs4filelayout.h" #include "nfs4filelayout.h"
#define NFSDBG_FACILITY NFSDBG_PNFS_LD #define NFSDBG_FACILITY NFSDBG_PNFS_LD
static unsigned int dataserver_timeo = NFS4_DEF_DS_TIMEO;
static unsigned int dataserver_retrans = NFS4_DEF_DS_RETRANS;
/* /*
* Data server cache * Data server cache
* *
...@@ -144,6 +148,28 @@ _data_server_lookup_locked(const struct list_head *dsaddrs) ...@@ -144,6 +148,28 @@ _data_server_lookup_locked(const struct list_head *dsaddrs)
return NULL; return NULL;
} }
/*
* Lookup DS by nfs_client pointer. Zero data server client pointer
*/
void nfs4_ds_disconnect(struct nfs_client *clp)
{
struct nfs4_pnfs_ds *ds;
struct nfs_client *found = NULL;
dprintk("%s clp %p\n", __func__, clp);
spin_lock(&nfs4_ds_cache_lock);
list_for_each_entry(ds, &nfs4_data_server_cache, ds_node)
if (ds->ds_clp && ds->ds_clp == clp) {
found = ds->ds_clp;
ds->ds_clp = NULL;
}
spin_unlock(&nfs4_ds_cache_lock);
if (found) {
set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
nfs_put_client(clp);
}
}
/* /*
* Create an rpc connection to the nfs4_pnfs_ds data server * Create an rpc connection to the nfs4_pnfs_ds data server
* Currently only supports IPv4 and IPv6 addresses * Currently only supports IPv4 and IPv6 addresses
...@@ -165,8 +191,9 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds) ...@@ -165,8 +191,9 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
__func__, ds->ds_remotestr, da->da_remotestr); __func__, ds->ds_remotestr, da->da_remotestr);
clp = nfs4_set_ds_client(mds_srv->nfs_client, clp = nfs4_set_ds_client(mds_srv->nfs_client,
(struct sockaddr *)&da->da_addr, (struct sockaddr *)&da->da_addr,
da->da_addrlen, IPPROTO_TCP); da->da_addrlen, IPPROTO_TCP,
dataserver_timeo, dataserver_retrans);
if (!IS_ERR(clp)) if (!IS_ERR(clp))
break; break;
} }
...@@ -176,28 +203,7 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds) ...@@ -176,28 +203,7 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
goto out; goto out;
} }
if ((clp->cl_exchange_flags & EXCHGID4_FLAG_MASK_PNFS) != 0) { status = nfs4_init_ds_session(clp, mds_srv->nfs_client->cl_lease_time);
if (!is_ds_client(clp)) {
status = -ENODEV;
goto out_put;
}
ds->ds_clp = clp;
dprintk("%s [existing] server=%s\n", __func__,
ds->ds_remotestr);
goto out;
}
/*
* Do not set NFS_CS_CHECK_LEASE_TIME instead set the DS lease to
* be equal to the MDS lease. Renewal is scheduled in create_session.
*/
spin_lock(&mds_srv->nfs_client->cl_lock);
clp->cl_lease_time = mds_srv->nfs_client->cl_lease_time;
spin_unlock(&mds_srv->nfs_client->cl_lock);
clp->cl_last_renewal = jiffies;
/* New nfs_client */
status = nfs4_init_ds_session(clp);
if (status) if (status)
goto out_put; goto out_put;
...@@ -602,7 +608,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags) ...@@ -602,7 +608,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
mp_count = be32_to_cpup(p); /* multipath count */ mp_count = be32_to_cpup(p); /* multipath count */
for (j = 0; j < mp_count; j++) { for (j = 0; j < mp_count; j++) {
da = decode_ds_addr(NFS_SERVER(ino)->nfs_client->net, da = decode_ds_addr(NFS_SERVER(ino)->nfs_client->cl_net,
&stream, gfp_flags); &stream, gfp_flags);
if (da) if (da)
list_add_tail(&da->da_node, &dsaddrs); list_add_tail(&da->da_node, &dsaddrs);
...@@ -791,48 +797,42 @@ nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j) ...@@ -791,48 +797,42 @@ nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j)
return flseg->fh_array[i]; return flseg->fh_array[i];
} }
static void
filelayout_mark_devid_negative(struct nfs4_file_layout_dsaddr *dsaddr,
int err, const char *ds_remotestr)
{
u32 *p = (u32 *)&dsaddr->id_node.deviceid;
printk(KERN_ERR "NFS: data server %s connection error %d."
" Deviceid [%x%x%x%x] marked out of use.\n",
ds_remotestr, err, p[0], p[1], p[2], p[3]);
spin_lock(&nfs4_ds_cache_lock);
dsaddr->flags |= NFS4_DEVICE_ID_NEG_ENTRY;
spin_unlock(&nfs4_ds_cache_lock);
}
struct nfs4_pnfs_ds * struct nfs4_pnfs_ds *
nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx) nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
{ {
struct nfs4_file_layout_dsaddr *dsaddr = FILELAYOUT_LSEG(lseg)->dsaddr; struct nfs4_file_layout_dsaddr *dsaddr = FILELAYOUT_LSEG(lseg)->dsaddr;
struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx]; struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
if (filelayout_test_devid_invalid(devid))
return NULL;
if (ds == NULL) { if (ds == NULL) {
printk(KERN_ERR "NFS: %s: No data server for offset index %d\n", printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
__func__, ds_idx); __func__, ds_idx);
return NULL; goto mark_dev_invalid;
} }
if (!ds->ds_clp) { if (!ds->ds_clp) {
struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode); struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode);
int err; int err;
if (dsaddr->flags & NFS4_DEVICE_ID_NEG_ENTRY) {
/* Already tried to connect, don't try again */
dprintk("%s Deviceid marked out of use\n", __func__);
return NULL;
}
err = nfs4_ds_connect(s, ds); err = nfs4_ds_connect(s, ds);
if (err) { if (err)
filelayout_mark_devid_negative(dsaddr, err, goto mark_dev_invalid;
ds->ds_remotestr);
return NULL;
}
} }
return ds; return ds;
mark_dev_invalid:
filelayout_mark_devid_invalid(devid);
return NULL;
} }
module_param(dataserver_retrans, uint, 0644);
MODULE_PARM_DESC(dataserver_retrans, "The number of times the NFSv4.1 client "
"retries a request before it attempts further "
" recovery action.");
module_param(dataserver_timeo, uint, 0644);
MODULE_PARM_DESC(dataserver_timeo, "The time (in tenths of a second) the "
"NFSv4.1 client waits for a response from a "
" data server before it retries an NFS request.");
...@@ -132,6 +132,35 @@ static size_t nfs_parse_server_name(char *string, size_t len, ...@@ -132,6 +132,35 @@ static size_t nfs_parse_server_name(char *string, size_t len,
return ret; return ret;
} }
rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
{
struct gss_api_mech *mech;
struct xdr_netobj oid;
int i;
rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX;
for (i = 0; i < flavors->num_flavors; i++) {
struct nfs4_secinfo_flavor *flavor;
flavor = &flavors->flavors[i];
if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) {
pseudoflavor = flavor->flavor;
break;
} else if (flavor->flavor == RPC_AUTH_GSS) {
oid.len = flavor->gss.sec_oid4.len;
oid.data = flavor->gss.sec_oid4.data;
mech = gss_mech_get_by_OID(&oid);
if (!mech)
continue;
pseudoflavor = gss_svc_to_pseudoflavor(mech, flavor->gss.service);
gss_mech_put(mech);
break;
}
}
return pseudoflavor;
}
static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name) static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name)
{ {
struct page *page; struct page *page;
...@@ -168,7 +197,7 @@ struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *clnt, struct inode *ino ...@@ -168,7 +197,7 @@ struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *clnt, struct inode *ino
rpc_authflavor_t flavor; rpc_authflavor_t flavor;
flavor = nfs4_negotiate_security(inode, name); flavor = nfs4_negotiate_security(inode, name);
if (flavor < 0) if ((int)flavor < 0)
return ERR_PTR(flavor); return ERR_PTR(flavor);
clone = rpc_clone_client(clnt); clone = rpc_clone_client(clnt);
...@@ -300,7 +329,7 @@ static struct vfsmount *nfs_follow_referral(struct dentry *dentry, ...@@ -300,7 +329,7 @@ static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
* @dentry - dentry of referral * @dentry - dentry of referral
* *
*/ */
struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry) static struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry)
{ {
struct vfsmount *mnt = ERR_PTR(-ENOMEM); struct vfsmount *mnt = ERR_PTR(-ENOMEM);
struct dentry *parent; struct dentry *parent;
...@@ -341,3 +370,25 @@ struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry) ...@@ -341,3 +370,25 @@ struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry)
dprintk("%s: done\n", __func__); dprintk("%s: done\n", __func__);
return mnt; return mnt;
} }
struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry,
struct nfs_fh *fh, struct nfs_fattr *fattr)
{
struct dentry *parent = dget_parent(dentry);
struct rpc_clnt *client;
struct vfsmount *mnt;
/* Look it up again to get its attributes and sec flavor */
client = nfs4_proc_lookup_mountpoint(parent->d_inode, &dentry->d_name, fh, fattr);
dput(parent);
if (IS_ERR(client))
return ERR_CAST(client);
if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
mnt = nfs_do_refmount(client, dentry);
else
mnt = nfs_do_submount(dentry, fh, fattr, client->cl_auth->au_flavor);
rpc_shutdown_client(client);
return mnt;
}
This diff is collapsed.
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
#include "nfs4_fs.h" #include "nfs4_fs.h"
#include "delegation.h" #include "delegation.h"
#define NFSDBG_FACILITY NFSDBG_PROC #define NFSDBG_FACILITY NFSDBG_STATE
void void
nfs4_renew_state(struct work_struct *work) nfs4_renew_state(struct work_struct *work)
......
This diff is collapsed.
This diff is collapsed.
...@@ -211,7 +211,7 @@ static void copy_single_comp(struct ore_components *oc, unsigned c, ...@@ -211,7 +211,7 @@ static void copy_single_comp(struct ore_components *oc, unsigned c,
memcpy(ocomp->cred, src_comp->oc_cap.cred, sizeof(ocomp->cred)); memcpy(ocomp->cred, src_comp->oc_cap.cred, sizeof(ocomp->cred));
} }
int __alloc_objio_seg(unsigned numdevs, gfp_t gfp_flags, static int __alloc_objio_seg(unsigned numdevs, gfp_t gfp_flags,
struct objio_segment **pseg) struct objio_segment **pseg)
{ {
/* This is the in memory structure of the objio_segment /* This is the in memory structure of the objio_segment
...@@ -440,11 +440,12 @@ static void _read_done(struct ore_io_state *ios, void *private) ...@@ -440,11 +440,12 @@ static void _read_done(struct ore_io_state *ios, void *private)
int objio_read_pagelist(struct nfs_read_data *rdata) int objio_read_pagelist(struct nfs_read_data *rdata)
{ {
struct nfs_pgio_header *hdr = rdata->header;
struct objio_state *objios; struct objio_state *objios;
int ret; int ret;
ret = objio_alloc_io_state(NFS_I(rdata->inode)->layout, true, ret = objio_alloc_io_state(NFS_I(hdr->inode)->layout, true,
rdata->lseg, rdata->args.pages, rdata->args.pgbase, hdr->lseg, rdata->args.pages, rdata->args.pgbase,
rdata->args.offset, rdata->args.count, rdata, rdata->args.offset, rdata->args.count, rdata,
GFP_KERNEL, &objios); GFP_KERNEL, &objios);
if (unlikely(ret)) if (unlikely(ret))
...@@ -483,12 +484,12 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate) ...@@ -483,12 +484,12 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate)
{ {
struct objio_state *objios = priv; struct objio_state *objios = priv;
struct nfs_write_data *wdata = objios->oir.rpcdata; struct nfs_write_data *wdata = objios->oir.rpcdata;
struct address_space *mapping = wdata->header->inode->i_mapping;
pgoff_t index = offset / PAGE_SIZE; pgoff_t index = offset / PAGE_SIZE;
struct page *page = find_get_page(wdata->inode->i_mapping, index); struct page *page = find_get_page(mapping, index);
if (!page) { if (!page) {
page = find_or_create_page(wdata->inode->i_mapping, page = find_or_create_page(mapping, index, GFP_NOFS);
index, GFP_NOFS);
if (unlikely(!page)) { if (unlikely(!page)) {
dprintk("%s: grab_cache_page Failed index=0x%lx\n", dprintk("%s: grab_cache_page Failed index=0x%lx\n",
__func__, index); __func__, index);
...@@ -518,11 +519,12 @@ static const struct _ore_r4w_op _r4w_op = { ...@@ -518,11 +519,12 @@ static const struct _ore_r4w_op _r4w_op = {
int objio_write_pagelist(struct nfs_write_data *wdata, int how) int objio_write_pagelist(struct nfs_write_data *wdata, int how)
{ {
struct nfs_pgio_header *hdr = wdata->header;
struct objio_state *objios; struct objio_state *objios;
int ret; int ret;
ret = objio_alloc_io_state(NFS_I(wdata->inode)->layout, false, ret = objio_alloc_io_state(NFS_I(hdr->inode)->layout, false,
wdata->lseg, wdata->args.pages, wdata->args.pgbase, hdr->lseg, wdata->args.pages, wdata->args.pgbase,
wdata->args.offset, wdata->args.count, wdata, GFP_NOFS, wdata->args.offset, wdata->args.count, wdata, GFP_NOFS,
&objios); &objios);
if (unlikely(ret)) if (unlikely(ret))
......
...@@ -258,7 +258,7 @@ objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync) ...@@ -258,7 +258,7 @@ objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync)
if (status >= 0) if (status >= 0)
rdata->res.count = status; rdata->res.count = status;
else else
rdata->pnfs_error = status; rdata->header->pnfs_error = status;
objlayout_iodone(oir); objlayout_iodone(oir);
/* must not use oir after this point */ /* must not use oir after this point */
...@@ -279,12 +279,14 @@ objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync) ...@@ -279,12 +279,14 @@ objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync)
enum pnfs_try_status enum pnfs_try_status
objlayout_read_pagelist(struct nfs_read_data *rdata) objlayout_read_pagelist(struct nfs_read_data *rdata)
{ {
struct nfs_pgio_header *hdr = rdata->header;
struct inode *inode = hdr->inode;
loff_t offset = rdata->args.offset; loff_t offset = rdata->args.offset;
size_t count = rdata->args.count; size_t count = rdata->args.count;
int err; int err;
loff_t eof; loff_t eof;
eof = i_size_read(rdata->inode); eof = i_size_read(inode);
if (unlikely(offset + count > eof)) { if (unlikely(offset + count > eof)) {
if (offset >= eof) { if (offset >= eof) {
err = 0; err = 0;
...@@ -297,17 +299,17 @@ objlayout_read_pagelist(struct nfs_read_data *rdata) ...@@ -297,17 +299,17 @@ objlayout_read_pagelist(struct nfs_read_data *rdata)
} }
rdata->res.eof = (offset + count) >= eof; rdata->res.eof = (offset + count) >= eof;
_fix_verify_io_params(rdata->lseg, &rdata->args.pages, _fix_verify_io_params(hdr->lseg, &rdata->args.pages,
&rdata->args.pgbase, &rdata->args.pgbase,
rdata->args.offset, rdata->args.count); rdata->args.offset, rdata->args.count);
dprintk("%s: inode(%lx) offset 0x%llx count 0x%Zx eof=%d\n", dprintk("%s: inode(%lx) offset 0x%llx count 0x%Zx eof=%d\n",
__func__, rdata->inode->i_ino, offset, count, rdata->res.eof); __func__, inode->i_ino, offset, count, rdata->res.eof);
err = objio_read_pagelist(rdata); err = objio_read_pagelist(rdata);
out: out:
if (unlikely(err)) { if (unlikely(err)) {
rdata->pnfs_error = err; hdr->pnfs_error = err;
dprintk("%s: Returned Error %d\n", __func__, err); dprintk("%s: Returned Error %d\n", __func__, err);
return PNFS_NOT_ATTEMPTED; return PNFS_NOT_ATTEMPTED;
} }
...@@ -340,7 +342,7 @@ objlayout_write_done(struct objlayout_io_res *oir, ssize_t status, bool sync) ...@@ -340,7 +342,7 @@ objlayout_write_done(struct objlayout_io_res *oir, ssize_t status, bool sync)
wdata->res.count = status; wdata->res.count = status;
wdata->verf.committed = oir->committed; wdata->verf.committed = oir->committed;
} else { } else {
wdata->pnfs_error = status; wdata->header->pnfs_error = status;
} }
objlayout_iodone(oir); objlayout_iodone(oir);
/* must not use oir after this point */ /* must not use oir after this point */
...@@ -363,15 +365,16 @@ enum pnfs_try_status ...@@ -363,15 +365,16 @@ enum pnfs_try_status
objlayout_write_pagelist(struct nfs_write_data *wdata, objlayout_write_pagelist(struct nfs_write_data *wdata,
int how) int how)
{ {
struct nfs_pgio_header *hdr = wdata->header;
int err; int err;
_fix_verify_io_params(wdata->lseg, &wdata->args.pages, _fix_verify_io_params(hdr->lseg, &wdata->args.pages,
&wdata->args.pgbase, &wdata->args.pgbase,
wdata->args.offset, wdata->args.count); wdata->args.offset, wdata->args.count);
err = objio_write_pagelist(wdata, how); err = objio_write_pagelist(wdata, how);
if (unlikely(err)) { if (unlikely(err)) {
wdata->pnfs_error = err; hdr->pnfs_error = err;
dprintk("%s: Returned Error %d\n", __func__, err); dprintk("%s: Returned Error %d\n", __func__, err);
return PNFS_NOT_ATTEMPTED; return PNFS_NOT_ATTEMPTED;
} }
......
...@@ -26,6 +26,47 @@ ...@@ -26,6 +26,47 @@
static struct kmem_cache *nfs_page_cachep; static struct kmem_cache *nfs_page_cachep;
bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount)
{
p->npages = pagecount;
if (pagecount <= ARRAY_SIZE(p->page_array))
p->pagevec = p->page_array;
else {
p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_KERNEL);
if (!p->pagevec)
p->npages = 0;
}
return p->pagevec != NULL;
}
void nfs_pgheader_init(struct nfs_pageio_descriptor *desc,
struct nfs_pgio_header *hdr,
void (*release)(struct nfs_pgio_header *hdr))
{
hdr->req = nfs_list_entry(desc->pg_list.next);
hdr->inode = desc->pg_inode;
hdr->cred = hdr->req->wb_context->cred;
hdr->io_start = req_offset(hdr->req);
hdr->good_bytes = desc->pg_count;
hdr->dreq = desc->pg_dreq;
hdr->release = release;
hdr->completion_ops = desc->pg_completion_ops;
if (hdr->completion_ops->init_hdr)
hdr->completion_ops->init_hdr(hdr);
}
void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos)
{
spin_lock(&hdr->lock);
if (pos < hdr->io_start + hdr->good_bytes) {
set_bit(NFS_IOHDR_ERROR, &hdr->flags);
clear_bit(NFS_IOHDR_EOF, &hdr->flags);
hdr->good_bytes = pos - hdr->io_start;
hdr->error = error;
}
spin_unlock(&hdr->lock);
}
static inline struct nfs_page * static inline struct nfs_page *
nfs_page_alloc(void) nfs_page_alloc(void)
{ {
...@@ -76,12 +117,8 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, ...@@ -76,12 +117,8 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
* long write-back delay. This will be adjusted in * long write-back delay. This will be adjusted in
* update_nfs_request below if the region is not locked. */ * update_nfs_request below if the region is not locked. */
req->wb_page = page; req->wb_page = page;
atomic_set(&req->wb_complete, 0);
req->wb_index = page->index; req->wb_index = page->index;
page_cache_get(page); page_cache_get(page);
BUG_ON(PagePrivate(page));
BUG_ON(!PageLocked(page));
BUG_ON(page->mapping->host != inode);
req->wb_offset = offset; req->wb_offset = offset;
req->wb_pgbase = offset; req->wb_pgbase = offset;
req->wb_bytes = count; req->wb_bytes = count;
...@@ -104,6 +141,15 @@ void nfs_unlock_request(struct nfs_page *req) ...@@ -104,6 +141,15 @@ void nfs_unlock_request(struct nfs_page *req)
clear_bit(PG_BUSY, &req->wb_flags); clear_bit(PG_BUSY, &req->wb_flags);
smp_mb__after_clear_bit(); smp_mb__after_clear_bit();
wake_up_bit(&req->wb_flags, PG_BUSY); wake_up_bit(&req->wb_flags, PG_BUSY);
}
/**
* nfs_unlock_and_release_request - Unlock request and release the nfs_page
* @req:
*/
void nfs_unlock_and_release_request(struct nfs_page *req)
{
nfs_unlock_request(req);
nfs_release_request(req); nfs_release_request(req);
} }
...@@ -203,6 +249,7 @@ EXPORT_SYMBOL_GPL(nfs_generic_pg_test); ...@@ -203,6 +249,7 @@ EXPORT_SYMBOL_GPL(nfs_generic_pg_test);
void nfs_pageio_init(struct nfs_pageio_descriptor *desc, void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
struct inode *inode, struct inode *inode,
const struct nfs_pageio_ops *pg_ops, const struct nfs_pageio_ops *pg_ops,
const struct nfs_pgio_completion_ops *compl_ops,
size_t bsize, size_t bsize,
int io_flags) int io_flags)
{ {
...@@ -215,9 +262,11 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc, ...@@ -215,9 +262,11 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
desc->pg_recoalesce = 0; desc->pg_recoalesce = 0;
desc->pg_inode = inode; desc->pg_inode = inode;
desc->pg_ops = pg_ops; desc->pg_ops = pg_ops;
desc->pg_completion_ops = compl_ops;
desc->pg_ioflags = io_flags; desc->pg_ioflags = io_flags;
desc->pg_error = 0; desc->pg_error = 0;
desc->pg_lseg = NULL; desc->pg_lseg = NULL;
desc->pg_dreq = NULL;
} }
/** /**
...@@ -241,12 +290,12 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev, ...@@ -241,12 +290,12 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev,
return false; return false;
if (req->wb_context->state != prev->wb_context->state) if (req->wb_context->state != prev->wb_context->state)
return false; return false;
if (req->wb_index != (prev->wb_index + 1))
return false;
if (req->wb_pgbase != 0) if (req->wb_pgbase != 0)
return false; return false;
if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE) if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE)
return false; return false;
if (req_offset(req) != req_offset(prev) + prev->wb_bytes)
return false;
return pgio->pg_ops->pg_test(pgio, prev, req); return pgio->pg_ops->pg_test(pgio, prev, req);
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -69,6 +69,10 @@ ...@@ -69,6 +69,10 @@
#define NFS4_CDFC4_FORE_OR_BOTH 0x3 #define NFS4_CDFC4_FORE_OR_BOTH 0x3
#define NFS4_CDFC4_BACK_OR_BOTH 0x7 #define NFS4_CDFC4_BACK_OR_BOTH 0x7
#define NFS4_CDFS4_FORE 0x1
#define NFS4_CDFS4_BACK 0x2
#define NFS4_CDFS4_BOTH 0x3
#define NFS4_SET_TO_SERVER_TIME 0 #define NFS4_SET_TO_SERVER_TIME 0
#define NFS4_SET_TO_CLIENT_TIME 1 #define NFS4_SET_TO_CLIENT_TIME 1
...@@ -526,6 +530,13 @@ enum lock_type4 { ...@@ -526,6 +530,13 @@ enum lock_type4 {
#define FATTR4_WORD1_MOUNTED_ON_FILEID (1UL << 23) #define FATTR4_WORD1_MOUNTED_ON_FILEID (1UL << 23)
#define FATTR4_WORD1_FS_LAYOUT_TYPES (1UL << 30) #define FATTR4_WORD1_FS_LAYOUT_TYPES (1UL << 30)
#define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1) #define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1)
#define FATTR4_WORD2_MDSTHRESHOLD (1UL << 4)
/* MDS threshold bitmap bits */
#define THRESHOLD_RD (1UL << 0)
#define THRESHOLD_WR (1UL << 1)
#define THRESHOLD_RD_IO (1UL << 2)
#define THRESHOLD_WR_IO (1UL << 3)
#define NFSPROC4_NULL 0 #define NFSPROC4_NULL 0
#define NFSPROC4_COMPOUND 1 #define NFSPROC4_COMPOUND 1
...@@ -596,6 +607,8 @@ enum { ...@@ -596,6 +607,8 @@ enum {
NFSPROC4_CLNT_TEST_STATEID, NFSPROC4_CLNT_TEST_STATEID,
NFSPROC4_CLNT_FREE_STATEID, NFSPROC4_CLNT_FREE_STATEID,
NFSPROC4_CLNT_GETDEVICELIST, NFSPROC4_CLNT_GETDEVICELIST,
NFSPROC4_CLNT_BIND_CONN_TO_SESSION,
NFSPROC4_CLNT_DESTROY_CLIENTID,
}; };
/* nfs41 types */ /* nfs41 types */
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -1286,6 +1286,8 @@ call_reserveresult(struct rpc_task *task) ...@@ -1286,6 +1286,8 @@ call_reserveresult(struct rpc_task *task)
} }
switch (status) { switch (status) {
case -ENOMEM:
rpc_delay(task, HZ >> 2);
case -EAGAIN: /* woken up; retry */ case -EAGAIN: /* woken up; retry */
task->tk_action = call_reserve; task->tk_action = call_reserve;
return; return;
......
This diff is collapsed.
...@@ -394,6 +394,7 @@ static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg) ...@@ -394,6 +394,7 @@ static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg)
/** /**
* rpcb_register - set or unset a port registration with the local rpcbind svc * rpcb_register - set or unset a port registration with the local rpcbind svc
* @net: target network namespace
* @prog: RPC program number to bind * @prog: RPC program number to bind
* @vers: RPC version number to bind * @vers: RPC version number to bind
* @prot: transport protocol to register * @prot: transport protocol to register
...@@ -521,6 +522,7 @@ static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn, ...@@ -521,6 +522,7 @@ static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn,
/** /**
* rpcb_v4_register - set or unset a port registration with the local rpcbind * rpcb_v4_register - set or unset a port registration with the local rpcbind
* @net: target network namespace
* @program: RPC program number of service to (un)register * @program: RPC program number of service to (un)register
* @version: RPC version number of service to (un)register * @version: RPC version number of service to (un)register
* @address: address family, IP address, and port to (un)register * @address: address family, IP address, and port to (un)register
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment