Commit 16cefa8c authored by Linus Torvalds's avatar Linus Torvalds

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

* git://git.linux-nfs.org/pub/linux/nfs-2.6: (122 commits)
  sunrpc: drop BKL around wrap and unwrap
  NFSv4: Make sure unlock is really an unlock when cancelling a lock
  NLM: fix source address of callback to client
  SUNRPC client: add interface for binding to a local address
  SUNRPC server: record the destination address of a request
  SUNRPC: cleanup transport creation argument passing
  NFSv4: Make the NFS state model work with the nosharedcache mount option
  NFS: Error when mounting the same filesystem with different options
  NFS: Add the mount option "nosharecache"
  NFS: Add support for mounting NFSv4 file systems with string options
  NFS: Add final pieces to support in-kernel mount option parsing
  NFS: Introduce generic mount client API
  NFS: Add enums and match tables for mount option parsing
  NFS: Improve debugging output in NFS in-kernel mount client
  NFS: Clean up in-kernel NFS mount
  NFS: Remake nfsroot_mount as a permanent part of NFS client
  SUNRPC: Add a convenient default for the hostname when calling rpc_create()
  SUNRPC: Rename rpcb_getport to be consistent with new rpcb_getport_sync name
  SUNRPC: Rename rpcb_getport_external routine
  SUNRPC: Allow rpcbind requests to be interrupted by a signal.
  ...
parents 4fbef206 d8558f99
...@@ -44,9 +44,8 @@ static struct nsm_handle * nsm_find(const struct sockaddr_in *sin, ...@@ -44,9 +44,8 @@ static struct nsm_handle * nsm_find(const struct sockaddr_in *sin,
*/ */
static struct nlm_host * static struct nlm_host *
nlm_lookup_host(int server, const struct sockaddr_in *sin, nlm_lookup_host(int server, const struct sockaddr_in *sin,
int proto, int version, int proto, int version, const char *hostname,
const char *hostname, int hostname_len, const struct sockaddr_in *ssin)
int hostname_len)
{ {
struct hlist_head *chain; struct hlist_head *chain;
struct hlist_node *pos; struct hlist_node *pos;
...@@ -54,7 +53,9 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, ...@@ -54,7 +53,9 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin,
struct nsm_handle *nsm = NULL; struct nsm_handle *nsm = NULL;
int hash; int hash;
dprintk("lockd: nlm_lookup_host(%u.%u.%u.%u, p=%d, v=%d, my role=%s, name=%.*s)\n", dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT
", p=%d, v=%d, my role=%s, name=%.*s)\n",
NIPQUAD(ssin->sin_addr.s_addr),
NIPQUAD(sin->sin_addr.s_addr), proto, version, NIPQUAD(sin->sin_addr.s_addr), proto, version,
server? "server" : "client", server? "server" : "client",
hostname_len, hostname_len,
...@@ -91,6 +92,8 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, ...@@ -91,6 +92,8 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin,
continue; continue;
if (host->h_server != server) if (host->h_server != server)
continue; continue;
if (!nlm_cmp_addr(&host->h_saddr, ssin))
continue;
/* Move to head of hash chain. */ /* Move to head of hash chain. */
hlist_del(&host->h_hash); hlist_del(&host->h_hash);
...@@ -118,6 +121,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, ...@@ -118,6 +121,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin,
host->h_name = nsm->sm_name; host->h_name = nsm->sm_name;
host->h_addr = *sin; host->h_addr = *sin;
host->h_addr.sin_port = 0; /* ouch! */ host->h_addr.sin_port = 0; /* ouch! */
host->h_saddr = *ssin;
host->h_version = version; host->h_version = version;
host->h_proto = proto; host->h_proto = proto;
host->h_rpcclnt = NULL; host->h_rpcclnt = NULL;
...@@ -161,15 +165,9 @@ nlm_destroy_host(struct nlm_host *host) ...@@ -161,15 +165,9 @@ nlm_destroy_host(struct nlm_host *host)
*/ */
nsm_unmonitor(host); nsm_unmonitor(host);
if ((clnt = host->h_rpcclnt) != NULL) { clnt = host->h_rpcclnt;
if (atomic_read(&clnt->cl_users)) { if (clnt != NULL)
printk(KERN_WARNING rpc_shutdown_client(clnt);
"lockd: active RPC handle\n");
clnt->cl_dead = 1;
} else {
rpc_destroy_client(host->h_rpcclnt);
}
}
kfree(host); kfree(host);
} }
...@@ -180,8 +178,10 @@ struct nlm_host * ...@@ -180,8 +178,10 @@ struct nlm_host *
nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version, nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version,
const char *hostname, int hostname_len) const char *hostname, int hostname_len)
{ {
struct sockaddr_in ssin = {0};
return nlm_lookup_host(0, sin, proto, version, return nlm_lookup_host(0, sin, proto, version,
hostname, hostname_len); hostname, hostname_len, &ssin);
} }
/* /*
...@@ -191,9 +191,12 @@ struct nlm_host * ...@@ -191,9 +191,12 @@ struct nlm_host *
nlmsvc_lookup_host(struct svc_rqst *rqstp, nlmsvc_lookup_host(struct svc_rqst *rqstp,
const char *hostname, int hostname_len) const char *hostname, int hostname_len)
{ {
struct sockaddr_in ssin = {0};
ssin.sin_addr = rqstp->rq_daddr.addr;
return nlm_lookup_host(1, svc_addr_in(rqstp), return nlm_lookup_host(1, svc_addr_in(rqstp),
rqstp->rq_prot, rqstp->rq_vers, rqstp->rq_prot, rqstp->rq_vers,
hostname, hostname_len); hostname, hostname_len, &ssin);
} }
/* /*
...@@ -204,8 +207,9 @@ nlm_bind_host(struct nlm_host *host) ...@@ -204,8 +207,9 @@ nlm_bind_host(struct nlm_host *host)
{ {
struct rpc_clnt *clnt; struct rpc_clnt *clnt;
dprintk("lockd: nlm_bind_host(%08x)\n", dprintk("lockd: nlm_bind_host("NIPQUAD_FMT"->"NIPQUAD_FMT")\n",
(unsigned)ntohl(host->h_addr.sin_addr.s_addr)); NIPQUAD(host->h_saddr.sin_addr),
NIPQUAD(host->h_addr.sin_addr));
/* Lock host handle */ /* Lock host handle */
mutex_lock(&host->h_mutex); mutex_lock(&host->h_mutex);
...@@ -232,6 +236,7 @@ nlm_bind_host(struct nlm_host *host) ...@@ -232,6 +236,7 @@ nlm_bind_host(struct nlm_host *host)
.protocol = host->h_proto, .protocol = host->h_proto,
.address = (struct sockaddr *)&host->h_addr, .address = (struct sockaddr *)&host->h_addr,
.addrsize = sizeof(host->h_addr), .addrsize = sizeof(host->h_addr),
.saddress = (struct sockaddr *)&host->h_saddr,
.timeout = &timeparms, .timeout = &timeparms,
.servername = host->h_name, .servername = host->h_name,
.program = &nlm_program, .program = &nlm_program,
......
...@@ -61,6 +61,7 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) ...@@ -61,6 +61,7 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
status); status);
else else
status = 0; status = 0;
rpc_shutdown_client(clnt);
out: out:
return status; return status;
} }
...@@ -138,7 +139,6 @@ nsm_create(void) ...@@ -138,7 +139,6 @@ nsm_create(void)
.program = &nsm_program, .program = &nsm_program,
.version = SM_VERSION, .version = SM_VERSION,
.authflavor = RPC_AUTH_NULL, .authflavor = RPC_AUTH_NULL,
.flags = (RPC_CLNT_CREATE_ONESHOT),
}; };
return rpc_create(&args); return rpc_create(&args);
......
...@@ -123,9 +123,6 @@ lockd(struct svc_rqst *rqstp) ...@@ -123,9 +123,6 @@ lockd(struct svc_rqst *rqstp)
/* Process request with signals blocked, but allow SIGKILL. */ /* Process request with signals blocked, but allow SIGKILL. */
allow_signal(SIGKILL); allow_signal(SIGKILL);
/* kick rpciod */
rpciod_up();
dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
if (!nlm_timeout) if (!nlm_timeout)
...@@ -202,9 +199,6 @@ lockd(struct svc_rqst *rqstp) ...@@ -202,9 +199,6 @@ lockd(struct svc_rqst *rqstp)
/* Exit the RPC thread */ /* Exit the RPC thread */
svc_exit_thread(rqstp); svc_exit_thread(rqstp);
/* release rpciod */
rpciod_down();
/* Release module */ /* Release module */
unlock_kernel(); unlock_kernel();
module_put_and_exit(0); module_put_and_exit(0);
......
...@@ -6,8 +6,8 @@ obj-$(CONFIG_NFS_FS) += nfs.o ...@@ -6,8 +6,8 @@ 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 nfs2xdr.o \
pagelist.o proc.o read.o symlink.o unlink.o \ pagelist.o proc.o read.o symlink.o unlink.o \
write.o namespace.o write.o namespace.o mount_clnt.o
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o nfs-$(CONFIG_ROOT_NFS) += nfsroot.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 \
......
...@@ -102,19 +102,10 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, ...@@ -102,19 +102,10 @@ static struct nfs_client *nfs_alloc_client(const char *hostname,
int nfsversion) int nfsversion)
{ {
struct nfs_client *clp; struct nfs_client *clp;
int error;
if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL)
goto error_0; goto error_0;
error = rpciod_up();
if (error < 0) {
dprintk("%s: couldn't start rpciod! Error = %d\n",
__FUNCTION__, error);
goto error_1;
}
__set_bit(NFS_CS_RPCIOD, &clp->cl_res_state);
if (nfsversion == 4) { if (nfsversion == 4) {
if (nfs_callback_up() < 0) if (nfs_callback_up() < 0)
goto error_2; goto error_2;
...@@ -139,8 +130,6 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, ...@@ -139,8 +130,6 @@ static struct nfs_client *nfs_alloc_client(const char *hostname,
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
init_rwsem(&clp->cl_sem); init_rwsem(&clp->cl_sem);
INIT_LIST_HEAD(&clp->cl_delegations); INIT_LIST_HEAD(&clp->cl_delegations);
INIT_LIST_HEAD(&clp->cl_state_owners);
INIT_LIST_HEAD(&clp->cl_unused);
spin_lock_init(&clp->cl_lock); spin_lock_init(&clp->cl_lock);
INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
...@@ -154,9 +143,6 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, ...@@ -154,9 +143,6 @@ static struct nfs_client *nfs_alloc_client(const char *hostname,
if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
nfs_callback_down(); nfs_callback_down();
error_2: error_2:
rpciod_down();
__clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state);
error_1:
kfree(clp); kfree(clp);
error_0: error_0:
return NULL; return NULL;
...@@ -167,16 +153,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp) ...@@ -167,16 +153,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp)
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state))
nfs4_kill_renewd(clp); nfs4_kill_renewd(clp);
while (!list_empty(&clp->cl_unused)) { BUG_ON(!RB_EMPTY_ROOT(&clp->cl_state_owners));
struct nfs4_state_owner *sp;
sp = list_entry(clp->cl_unused.next,
struct nfs4_state_owner,
so_list);
list_del(&sp->so_list);
kfree(sp);
}
BUG_ON(!list_empty(&clp->cl_state_owners));
if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state))
nfs_idmap_delete(clp); nfs_idmap_delete(clp);
#endif #endif
...@@ -198,9 +175,6 @@ static void nfs_free_client(struct nfs_client *clp) ...@@ -198,9 +175,6 @@ static void nfs_free_client(struct nfs_client *clp)
if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
nfs_callback_down(); nfs_callback_down();
if (__test_and_clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state))
rpciod_down();
kfree(clp->cl_hostname); kfree(clp->cl_hostname);
kfree(clp); kfree(clp);
......
This diff is collapsed.
...@@ -22,11 +22,12 @@ struct nfs_delegation { ...@@ -22,11 +22,12 @@ struct nfs_delegation {
long flags; long flags;
loff_t maxsize; loff_t maxsize;
__u64 change_attr; __u64 change_attr;
struct rcu_head rcu;
}; };
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
int __nfs_inode_return_delegation(struct inode *inode); int nfs_inode_return_delegation(struct inode *inode);
int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
...@@ -39,27 +40,24 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp); ...@@ -39,27 +40,24 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
/* NFSv4 delegation-related procedures */ /* NFSv4 delegation-related procedures */
int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid);
int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state); int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid);
int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl);
int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode); int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
static inline int nfs_have_delegation(struct inode *inode, int flags) static inline int nfs_have_delegation(struct inode *inode, int flags)
{ {
struct nfs_delegation *delegation;
int ret = 0;
flags &= FMODE_READ|FMODE_WRITE; flags &= FMODE_READ|FMODE_WRITE;
smp_rmb(); rcu_read_lock();
if ((NFS_I(inode)->delegation_state & flags) == flags) delegation = rcu_dereference(NFS_I(inode)->delegation);
return 1; if (delegation != NULL && (delegation->type & flags) == flags)
return 0; ret = 1;
rcu_read_unlock();
return ret;
} }
static inline int nfs_inode_return_delegation(struct inode *inode)
{
int err = 0;
if (NFS_I(inode)->delegation != NULL)
err = __nfs_inode_return_delegation(inode);
return err;
}
#else #else
static inline int nfs_have_delegation(struct inode *inode, int flags) static inline int nfs_have_delegation(struct inode *inode, int flags)
{ {
......
...@@ -897,14 +897,13 @@ int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd) ...@@ -897,14 +897,13 @@ int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
return (nd->intent.open.flags & O_EXCL) != 0; return (nd->intent.open.flags & O_EXCL) != 0;
} }
static inline int nfs_reval_fsid(struct vfsmount *mnt, struct inode *dir, static inline int nfs_reval_fsid(struct inode *dir, const struct nfs_fattr *fattr)
struct nfs_fh *fh, struct nfs_fattr *fattr)
{ {
struct nfs_server *server = NFS_SERVER(dir); struct nfs_server *server = NFS_SERVER(dir);
if (!nfs_fsid_equal(&server->fsid, &fattr->fsid)) if (!nfs_fsid_equal(&server->fsid, &fattr->fsid))
/* Revalidate fsid on root dir */ /* Revalidate fsid using the parent directory */
return __nfs_revalidate_inode(server, mnt->mnt_root->d_inode); return __nfs_revalidate_inode(server, dir);
return 0; return 0;
} }
...@@ -946,7 +945,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru ...@@ -946,7 +945,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
res = ERR_PTR(error); res = ERR_PTR(error);
goto out_unlock; goto out_unlock;
} }
error = nfs_reval_fsid(nd->mnt, dir, &fhandle, &fattr); error = nfs_reval_fsid(dir, &fattr);
if (error < 0) { if (error < 0) {
res = ERR_PTR(error); res = ERR_PTR(error);
goto out_unlock; goto out_unlock;
...@@ -1244,7 +1243,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, ...@@ -1244,7 +1243,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
attr.ia_mode = mode; attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE; attr.ia_valid = ATTR_MODE;
if (nd && (nd->flags & LOOKUP_CREATE)) if ((nd->flags & LOOKUP_CREATE) != 0)
open_flags = nd->intent.open.flags; open_flags = nd->intent.open.flags;
lock_kernel(); lock_kernel();
...@@ -1535,7 +1534,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym ...@@ -1535,7 +1534,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
lock_kernel(); lock_kernel();
page = alloc_page(GFP_KERNEL); page = alloc_page(GFP_HIGHUSER);
if (!page) { if (!page) {
unlock_kernel(); unlock_kernel();
return -ENOMEM; return -ENOMEM;
...@@ -1744,8 +1743,8 @@ int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) ...@@ -1744,8 +1743,8 @@ int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask)
struct nfs_inode *nfsi; struct nfs_inode *nfsi;
struct nfs_access_entry *cache; struct nfs_access_entry *cache;
spin_lock(&nfs_access_lru_lock);
restart: restart:
spin_lock(&nfs_access_lru_lock);
list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) {
struct inode *inode; struct inode *inode;
...@@ -1770,6 +1769,7 @@ int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) ...@@ -1770,6 +1769,7 @@ int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask)
clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags);
} }
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
spin_unlock(&nfs_access_lru_lock);
iput(inode); iput(inode);
goto restart; goto restart;
} }
......
...@@ -266,7 +266,7 @@ static const struct rpc_call_ops nfs_read_direct_ops = { ...@@ -266,7 +266,7 @@ static const struct rpc_call_ops nfs_read_direct_ops = {
static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos) static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos)
{ {
struct nfs_open_context *ctx = dreq->ctx; struct nfs_open_context *ctx = dreq->ctx;
struct inode *inode = ctx->dentry->d_inode; struct inode *inode = ctx->path.dentry->d_inode;
size_t rsize = NFS_SERVER(inode)->rsize; size_t rsize = NFS_SERVER(inode)->rsize;
unsigned int pgbase; unsigned int pgbase;
int result; int result;
...@@ -295,9 +295,14 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo ...@@ -295,9 +295,14 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo
break; break;
} }
if ((unsigned)result < data->npages) { if ((unsigned)result < data->npages) {
nfs_direct_release_pages(data->pagevec, result); bytes = result * PAGE_SIZE;
nfs_readdata_release(data); if (bytes <= pgbase) {
break; nfs_direct_release_pages(data->pagevec, result);
nfs_readdata_release(data);
break;
}
bytes -= pgbase;
data->npages = result;
} }
get_dreq(dreq); get_dreq(dreq);
...@@ -601,7 +606,7 @@ static const struct rpc_call_ops nfs_write_direct_ops = { ...@@ -601,7 +606,7 @@ static const struct rpc_call_ops nfs_write_direct_ops = {
static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos, int sync) static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos, int sync)
{ {
struct nfs_open_context *ctx = dreq->ctx; struct nfs_open_context *ctx = dreq->ctx;
struct inode *inode = ctx->dentry->d_inode; struct inode *inode = ctx->path.dentry->d_inode;
size_t wsize = NFS_SERVER(inode)->wsize; size_t wsize = NFS_SERVER(inode)->wsize;
unsigned int pgbase; unsigned int pgbase;
int result; int result;
...@@ -630,9 +635,14 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l ...@@ -630,9 +635,14 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l
break; break;
} }
if ((unsigned)result < data->npages) { if ((unsigned)result < data->npages) {
nfs_direct_release_pages(data->pagevec, result); bytes = result * PAGE_SIZE;
nfs_writedata_release(data); if (bytes <= pgbase) {
break; nfs_direct_release_pages(data->pagevec, result);
nfs_writedata_release(data);
break;
}
bytes -= pgbase;
data->npages = result;
} }
get_dreq(dreq); get_dreq(dreq);
...@@ -763,10 +773,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, ...@@ -763,10 +773,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
(unsigned long) count, (long long) pos); (unsigned long) count, (long long) pos);
if (nr_segs != 1) if (nr_segs != 1)
return -EINVAL;
if (count < 0)
goto out; goto out;
retval = -EFAULT; retval = -EFAULT;
if (!access_ok(VERIFY_WRITE, buf, count)) if (!access_ok(VERIFY_WRITE, buf, count))
goto out; goto out;
...@@ -814,7 +822,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, ...@@ -814,7 +822,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos) unsigned long nr_segs, loff_t pos)
{ {
ssize_t retval; ssize_t retval = -EINVAL;
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping; struct address_space *mapping = file->f_mapping;
/* XXX: temporary */ /* XXX: temporary */
...@@ -827,7 +835,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, ...@@ -827,7 +835,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
(unsigned long) count, (long long) pos); (unsigned long) count, (long long) pos);
if (nr_segs != 1) if (nr_segs != 1)
return -EINVAL; goto out;
retval = generic_write_checks(file, &pos, &count, 0); retval = generic_write_checks(file, &pos, &count, 0);
if (retval) if (retval)
......
...@@ -461,14 +461,14 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str ...@@ -461,14 +461,14 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (ctx != NULL) { if (ctx != NULL) {
atomic_set(&ctx->count, 1); ctx->path.dentry = dget(dentry);
ctx->dentry = dget(dentry); ctx->path.mnt = mntget(mnt);
ctx->vfsmnt = mntget(mnt);
ctx->cred = get_rpccred(cred); ctx->cred = get_rpccred(cred);
ctx->state = NULL; ctx->state = NULL;
ctx->lockowner = current->files; ctx->lockowner = current->files;
ctx->error = 0; ctx->error = 0;
ctx->dir_cookie = 0; ctx->dir_cookie = 0;
kref_init(&ctx->kref);
} }
return ctx; return ctx;
} }
...@@ -476,27 +476,33 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str ...@@ -476,27 +476,33 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str
struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
{ {
if (ctx != NULL) if (ctx != NULL)
atomic_inc(&ctx->count); kref_get(&ctx->kref);
return ctx; return ctx;
} }
void put_nfs_open_context(struct nfs_open_context *ctx) static void nfs_free_open_context(struct kref *kref)
{ {
if (atomic_dec_and_test(&ctx->count)) { struct nfs_open_context *ctx = container_of(kref,
if (!list_empty(&ctx->list)) { struct nfs_open_context, kref);
struct inode *inode = ctx->dentry->d_inode;
spin_lock(&inode->i_lock); if (!list_empty(&ctx->list)) {
list_del(&ctx->list); struct inode *inode = ctx->path.dentry->d_inode;
spin_unlock(&inode->i_lock); spin_lock(&inode->i_lock);
} list_del(&ctx->list);
if (ctx->state != NULL) spin_unlock(&inode->i_lock);
nfs4_close_state(ctx->state, ctx->mode);
if (ctx->cred != NULL)
put_rpccred(ctx->cred);
dput(ctx->dentry);
mntput(ctx->vfsmnt);
kfree(ctx);
} }
if (ctx->state != NULL)
nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
if (ctx->cred != NULL)
put_rpccred(ctx->cred);
dput(ctx->path.dentry);
mntput(ctx->path.mnt);
kfree(ctx);
}
void put_nfs_open_context(struct nfs_open_context *ctx)
{
kref_put(&ctx->kref, nfs_free_open_context);
} }
/* /*
...@@ -961,8 +967,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -961,8 +967,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
goto out_changed; goto out_changed;
server = NFS_SERVER(inode); server = NFS_SERVER(inode);
/* Update the fsid if and only if this is the root directory */ /* Update the fsid? */
if (inode == inode->i_sb->s_root->d_inode if (S_ISDIR(inode->i_mode)
&& !nfs_fsid_equal(&server->fsid, &fattr->fsid)) && !nfs_fsid_equal(&server->fsid, &fattr->fsid))
server->fsid = fattr->fsid; server->fsid = fattr->fsid;
...@@ -1066,8 +1072,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1066,8 +1072,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
invalid &= ~NFS_INO_INVALID_DATA; invalid &= ~NFS_INO_INVALID_DATA;
if (data_stable) if (data_stable)
invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME|NFS_INO_REVAL_PAGECACHE); invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME|NFS_INO_REVAL_PAGECACHE);
if (!nfs_have_delegation(inode, FMODE_READ)) if (!nfs_have_delegation(inode, FMODE_READ) ||
(nfsi->cache_validity & NFS_INO_REVAL_FORCED))
nfsi->cache_validity |= invalid; nfsi->cache_validity |= invalid;
nfsi->cache_validity &= ~NFS_INO_REVAL_FORCED;
return 0; return 0;
out_changed: out_changed:
...@@ -1103,27 +1111,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1103,27 +1111,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
*/ */
void nfs4_clear_inode(struct inode *inode) void nfs4_clear_inode(struct inode *inode)
{ {
struct nfs_inode *nfsi = NFS_I(inode);
/* If we are holding a delegation, return it! */ /* If we are holding a delegation, return it! */
nfs_inode_return_delegation(inode); nfs_inode_return_delegation(inode);
/* First call standard NFS clear_inode() code */ /* First call standard NFS clear_inode() code */
nfs_clear_inode(inode); nfs_clear_inode(inode);
/* Now clear out any remaining state */
while (!list_empty(&nfsi->open_states)) {
struct nfs4_state *state;
state = list_entry(nfsi->open_states.next,
struct nfs4_state,
inode_states);
dprintk("%s(%s/%Ld): found unclaimed NFSv4 state %p\n",
__FUNCTION__,
inode->i_sb->s_id,
(long long)NFS_FILEID(inode),
state);
BUG_ON(atomic_read(&state->count) != 1);
nfs4_close_state(state, state->state);
}
} }
#endif #endif
...@@ -1165,15 +1156,11 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag ...@@ -1165,15 +1156,11 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
struct nfs_inode *nfsi = (struct nfs_inode *) foo; struct nfs_inode *nfsi = (struct nfs_inode *) foo;
inode_init_once(&nfsi->vfs_inode); inode_init_once(&nfsi->vfs_inode);
spin_lock_init(&nfsi->req_lock);
INIT_LIST_HEAD(&nfsi->dirty);
INIT_LIST_HEAD(&nfsi->commit);
INIT_LIST_HEAD(&nfsi->open_files); INIT_LIST_HEAD(&nfsi->open_files);
INIT_LIST_HEAD(&nfsi->access_cache_entry_lru); INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
atomic_set(&nfsi->data_updates, 0); atomic_set(&nfsi->data_updates, 0);
nfsi->ndirty = 0;
nfsi->ncommit = 0; nfsi->ncommit = 0;
nfsi->npages = 0; nfsi->npages = 0;
nfs4_init_once(nfsi); nfs4_init_once(nfsi);
......
...@@ -183,9 +183,9 @@ unsigned long nfs_block_bits(unsigned long bsize, unsigned char *nrbitsp) ...@@ -183,9 +183,9 @@ unsigned long nfs_block_bits(unsigned long bsize, unsigned char *nrbitsp)
/* /*
* Calculate the number of 512byte blocks used. * Calculate the number of 512byte blocks used.
*/ */
static inline unsigned long nfs_calc_block_size(u64 tsize) static inline blkcnt_t nfs_calc_block_size(u64 tsize)
{ {
loff_t used = (tsize + 511) >> 9; blkcnt_t used = (tsize + 511) >> 9;
return (used > ULONG_MAX) ? ULONG_MAX : used; return (used > ULONG_MAX) ? ULONG_MAX : used;
} }
......
/* /*
* linux/fs/nfs/mount_clnt.c * In-kernel MOUNT protocol client
*
* MOUNT client to support NFSroot.
* *
* Copyright (C) 1997, Olaf Kirch <okir@monad.swb.de> * Copyright (C) 1997, Olaf Kirch <okir@monad.swb.de>
*/ */
...@@ -18,33 +16,31 @@ ...@@ -18,33 +16,31 @@
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
# define NFSDBG_FACILITY NFSDBG_ROOT # define NFSDBG_FACILITY NFSDBG_MOUNT
#endif #endif
/*
#define MOUNT_PROGRAM 100005
#define MOUNT_VERSION 1
#define MOUNT_MNT 1
#define MOUNT_UMNT 3
*/
static struct rpc_clnt * mnt_create(char *, struct sockaddr_in *,
int, int);
static struct rpc_program mnt_program; static struct rpc_program mnt_program;
struct mnt_fhstatus { struct mnt_fhstatus {
unsigned int status; u32 status;
struct nfs_fh * fh; struct nfs_fh *fh;
}; };
/* /**
* Obtain an NFS file handle for the given host and path * nfs_mount - Obtain an NFS file handle for the given host and path
* @addr: pointer to server's address
* @len: size of server's address
* @hostname: name of server host, or NULL
* @path: pointer to string containing export path to mount
* @version: mount version to use for this request
* @protocol: transport protocol to use for thie request
* @fh: pointer to location to place returned file handle
*
* Uses default timeout parameters specified by underlying transport.
*/ */
int int nfs_mount(struct sockaddr *addr, size_t len, char *hostname, char *path,
nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, int version, int protocol, struct nfs_fh *fh)
int version, int protocol)
{ {
struct rpc_clnt *mnt_clnt;
struct mnt_fhstatus result = { struct mnt_fhstatus result = {
.fh = fh .fh = fh
}; };
...@@ -52,16 +48,25 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, ...@@ -52,16 +48,25 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh,
.rpc_argp = path, .rpc_argp = path,
.rpc_resp = &result, .rpc_resp = &result,
}; };
char hostname[32]; struct rpc_create_args args = {
.protocol = protocol,
.address = addr,
.addrsize = len,
.servername = hostname,
.program = &mnt_program,
.version = version,
.authflavor = RPC_AUTH_UNIX,
.flags = RPC_CLNT_CREATE_INTR,
};
struct rpc_clnt *mnt_clnt;
int status; int status;
dprintk("NFS: nfs_mount(%08x:%s)\n", dprintk("NFS: sending MNT request for %s:%s\n",
(unsigned)ntohl(addr->sin_addr.s_addr), path); (hostname ? hostname : "server"), path);
sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr->sin_addr.s_addr)); mnt_clnt = rpc_create(&args);
mnt_clnt = mnt_create(hostname, addr, version, protocol);
if (IS_ERR(mnt_clnt)) if (IS_ERR(mnt_clnt))
return PTR_ERR(mnt_clnt); goto out_clnt_err;
if (version == NFS_MNT3_VERSION) if (version == NFS_MNT3_VERSION)
msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT];
...@@ -69,33 +74,39 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, ...@@ -69,33 +74,39 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh,
msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT]; msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT];
status = rpc_call_sync(mnt_clnt, &msg, 0); status = rpc_call_sync(mnt_clnt, &msg, 0);
return status < 0? status : (result.status? -EACCES : 0); rpc_shutdown_client(mnt_clnt);
}
static struct rpc_clnt * if (status < 0)
mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, goto out_call_err;
int protocol) if (result.status != 0)
{ goto out_mnt_err;
struct rpc_create_args args = {
.protocol = protocol, dprintk("NFS: MNT request succeeded\n");
.address = (struct sockaddr *)srvaddr, status = 0;
.addrsize = sizeof(*srvaddr),
.servername = hostname, out:
.program = &mnt_program, return status;
.version = version,
.authflavor = RPC_AUTH_UNIX, out_clnt_err:
.flags = (RPC_CLNT_CREATE_ONESHOT | status = PTR_ERR(mnt_clnt);
RPC_CLNT_CREATE_INTR), dprintk("NFS: failed to create RPC client, status=%d\n", status);
}; goto out;
out_call_err:
dprintk("NFS: failed to start MNT request, status=%d\n", status);
goto out;
return rpc_create(&args); out_mnt_err:
dprintk("NFS: MNT server returned result %d\n", result.status);
status = -EACCES;
goto out;
} }
/* /*
* XDR encode/decode functions for MOUNT * XDR encode/decode functions for MOUNT
*/ */
static int static int xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p,
xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, const char *path) const char *path)
{ {
p = xdr_encode_string(p, path); p = xdr_encode_string(p, path);
...@@ -103,8 +114,8 @@ xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, const char *path) ...@@ -103,8 +114,8 @@ xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, const char *path)
return 0; return 0;
} }
static int static int xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p,
xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res) struct mnt_fhstatus *res)
{ {
struct nfs_fh *fh = res->fh; struct nfs_fh *fh = res->fh;
...@@ -115,8 +126,8 @@ xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res) ...@@ -115,8 +126,8 @@ xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
return 0; return 0;
} }
static int static int xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p,
xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res) struct mnt_fhstatus *res)
{ {
struct nfs_fh *fh = res->fh; struct nfs_fh *fh = res->fh;
...@@ -135,53 +146,53 @@ xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res) ...@@ -135,53 +146,53 @@ xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
#define MNT_fhstatus_sz (1 + 8) #define MNT_fhstatus_sz (1 + 8)
#define MNT_fhstatus3_sz (1 + 16) #define MNT_fhstatus3_sz (1 + 16)
static struct rpc_procinfo mnt_procedures[] = { static struct rpc_procinfo mnt_procedures[] = {
[MNTPROC_MNT] = { [MNTPROC_MNT] = {
.p_proc = MNTPROC_MNT, .p_proc = MNTPROC_MNT,
.p_encode = (kxdrproc_t) xdr_encode_dirpath, .p_encode = (kxdrproc_t) xdr_encode_dirpath,
.p_decode = (kxdrproc_t) xdr_decode_fhstatus, .p_decode = (kxdrproc_t) xdr_decode_fhstatus,
.p_arglen = MNT_dirpath_sz, .p_arglen = MNT_dirpath_sz,
.p_replen = MNT_fhstatus_sz, .p_replen = MNT_fhstatus_sz,
.p_statidx = MNTPROC_MNT, .p_statidx = MNTPROC_MNT,
.p_name = "MOUNT", .p_name = "MOUNT",
}, },
}; };
static struct rpc_procinfo mnt3_procedures[] = { static struct rpc_procinfo mnt3_procedures[] = {
[MOUNTPROC3_MNT] = { [MOUNTPROC3_MNT] = {
.p_proc = MOUNTPROC3_MNT, .p_proc = MOUNTPROC3_MNT,
.p_encode = (kxdrproc_t) xdr_encode_dirpath, .p_encode = (kxdrproc_t) xdr_encode_dirpath,
.p_decode = (kxdrproc_t) xdr_decode_fhstatus3, .p_decode = (kxdrproc_t) xdr_decode_fhstatus3,
.p_arglen = MNT_dirpath_sz, .p_arglen = MNT_dirpath_sz,
.p_replen = MNT_fhstatus3_sz, .p_replen = MNT_fhstatus3_sz,
.p_statidx = MOUNTPROC3_MNT, .p_statidx = MOUNTPROC3_MNT,
.p_name = "MOUNT", .p_name = "MOUNT",
}, },
}; };
static struct rpc_version mnt_version1 = { static struct rpc_version mnt_version1 = {
.number = 1, .number = 1,
.nrprocs = 2, .nrprocs = 2,
.procs = mnt_procedures .procs = mnt_procedures,
}; };
static struct rpc_version mnt_version3 = { static struct rpc_version mnt_version3 = {
.number = 3, .number = 3,
.nrprocs = 2, .nrprocs = 2,
.procs = mnt3_procedures .procs = mnt3_procedures,
}; };
static struct rpc_version * mnt_version[] = { static struct rpc_version *mnt_version[] = {
NULL, NULL,
&mnt_version1, &mnt_version1,
NULL, NULL,
&mnt_version3, &mnt_version3,
}; };
static struct rpc_stat mnt_stats; static struct rpc_stat mnt_stats;
static struct rpc_program mnt_program = { static struct rpc_program mnt_program = {
.name = "mount", .name = "mount",
.number = NFS_MNT_PROGRAM, .number = NFS_MNT_PROGRAM,
.nrvers = ARRAY_SIZE(mnt_version), .nrvers = ARRAY_SIZE(mnt_version),
......
...@@ -223,7 +223,7 @@ nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args) ...@@ -223,7 +223,7 @@ nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
static int static int
nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
{ {
struct rpc_auth *auth = req->rq_task->tk_auth; struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
unsigned int replen; unsigned int replen;
u32 offset = (u32)args->offset; u32 offset = (u32)args->offset;
u32 count = args->count; u32 count = args->count;
...@@ -380,7 +380,7 @@ static int ...@@ -380,7 +380,7 @@ static int
nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args) nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
{ {
struct rpc_task *task = req->rq_task; struct rpc_task *task = req->rq_task;
struct rpc_auth *auth = task->tk_auth; struct rpc_auth *auth = task->tk_msg.rpc_cred->cr_auth;
unsigned int replen; unsigned int replen;
u32 count = args->count; u32 count = args->count;
...@@ -541,7 +541,7 @@ nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res) ...@@ -541,7 +541,7 @@ nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
static int static int
nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args) nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
{ {
struct rpc_auth *auth = req->rq_task->tk_auth; struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
unsigned int replen; unsigned int replen;
p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_fhandle(p, args->fh);
......
...@@ -335,9 +335,7 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, ...@@ -335,9 +335,7 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
* not sure this buys us anything (and I'd have * not sure this buys us anything (and I'd have
* to revamp the NFSv3 XDR code) */ * to revamp the NFSv3 XDR code) */
status = nfs3_proc_setattr(dentry, &fattr, sattr); status = nfs3_proc_setattr(dentry, &fattr, sattr);
if (status == 0) nfs_post_op_update_inode(dentry->d_inode, &fattr);
nfs_setattr_update_inode(dentry->d_inode, sattr);
nfs_refresh_inode(dentry->d_inode, &fattr);
dprintk("NFS reply setattr (post-create): %d\n", status); dprintk("NFS reply setattr (post-create): %d\n", status);
} }
if (status != 0) if (status != 0)
......
...@@ -319,7 +319,7 @@ nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *arg ...@@ -319,7 +319,7 @@ nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *arg
static int static int
nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
{ {
struct rpc_auth *auth = req->rq_task->tk_auth; struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
unsigned int replen; unsigned int replen;
u32 count = args->count; u32 count = args->count;
...@@ -458,7 +458,7 @@ nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args) ...@@ -458,7 +458,7 @@ nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
static int static int
nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args) nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
{ {
struct rpc_auth *auth = req->rq_task->tk_auth; struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
unsigned int replen; unsigned int replen;
u32 count = args->count; u32 count = args->count;
...@@ -643,7 +643,7 @@ static int ...@@ -643,7 +643,7 @@ static int
nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p, nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
struct nfs3_getaclargs *args) struct nfs3_getaclargs *args)
{ {
struct rpc_auth *auth = req->rq_task->tk_auth; struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
unsigned int replen; unsigned int replen;
p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_fhandle(p, args->fh);
...@@ -773,7 +773,7 @@ nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res) ...@@ -773,7 +773,7 @@ nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
static int static int
nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args) nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
{ {
struct rpc_auth *auth = req->rq_task->tk_auth; struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
unsigned int replen; unsigned int replen;
p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_fhandle(p, args->fh);
......
...@@ -70,19 +70,26 @@ static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status ...@@ -70,19 +70,26 @@ static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status
seqid->flags |= NFS_SEQID_CONFIRMED; seqid->flags |= NFS_SEQID_CONFIRMED;
} }
struct nfs_unique_id {
struct rb_node rb_node;
__u64 id;
};
/* /*
* NFS4 state_owners and lock_owners are simply labels for ordered * NFS4 state_owners and lock_owners are simply labels for ordered
* sequences of RPC calls. Their sole purpose is to provide once-only * sequences of RPC calls. Their sole purpose is to provide once-only
* semantics by allowing the server to identify replayed requests. * semantics by allowing the server to identify replayed requests.
*/ */
struct nfs4_state_owner { struct nfs4_state_owner {
spinlock_t so_lock; struct nfs_unique_id so_owner_id;
struct list_head so_list; /* per-clientid list of state_owners */
struct nfs_client *so_client; struct nfs_client *so_client;
u32 so_id; /* 32-bit identifier, unique */ struct nfs_server *so_server;
atomic_t so_count; struct rb_node so_client_node;
struct rpc_cred *so_cred; /* Associated cred */ struct rpc_cred *so_cred; /* Associated cred */
spinlock_t so_lock;
atomic_t so_count;
struct list_head so_states; struct list_head so_states;
struct list_head so_delegations; struct list_head so_delegations;
struct nfs_seqid_counter so_seqid; struct nfs_seqid_counter so_seqid;
...@@ -108,7 +115,7 @@ struct nfs4_lock_state { ...@@ -108,7 +115,7 @@ struct nfs4_lock_state {
#define NFS_LOCK_INITIALIZED 1 #define NFS_LOCK_INITIALIZED 1
int ls_flags; int ls_flags;
struct nfs_seqid_counter ls_seqid; struct nfs_seqid_counter ls_seqid;
u32 ls_id; struct nfs_unique_id ls_id;
nfs4_stateid ls_stateid; nfs4_stateid ls_stateid;
atomic_t ls_count; atomic_t ls_count;
}; };
...@@ -116,7 +123,10 @@ struct nfs4_lock_state { ...@@ -116,7 +123,10 @@ struct nfs4_lock_state {
/* bits for nfs4_state->flags */ /* bits for nfs4_state->flags */
enum { enum {
LK_STATE_IN_USE, LK_STATE_IN_USE,
NFS_DELEGATED_STATE, NFS_DELEGATED_STATE, /* Current stateid is delegation */
NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */
NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */
NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */
}; };
struct nfs4_state { struct nfs4_state {
...@@ -130,11 +140,14 @@ struct nfs4_state { ...@@ -130,11 +140,14 @@ struct nfs4_state {
unsigned long flags; /* Do we hold any locks? */ unsigned long flags; /* Do we hold any locks? */
spinlock_t state_lock; /* Protects the lock_states list */ spinlock_t state_lock; /* Protects the lock_states list */
nfs4_stateid stateid; seqlock_t seqlock; /* Protects the stateid/open_stateid */
nfs4_stateid stateid; /* Current stateid: may be delegation */
nfs4_stateid open_stateid; /* OPEN stateid */
unsigned int n_rdonly; /* The following 3 fields are protected by owner->so_lock */
unsigned int n_wronly; unsigned int n_rdonly; /* Number of read-only references */
unsigned int n_rdwr; unsigned int n_wronly; /* Number of write-only references */
unsigned int n_rdwr; /* Number of read/write references */
int state; /* State on the server (R,W, or RW) */ int state; /* State on the server (R,W, or RW) */
atomic_t count; atomic_t count;
}; };
...@@ -165,7 +178,7 @@ extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struc ...@@ -165,7 +178,7 @@ extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struc
extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *);
extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *);
extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *);
extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state); extern int nfs4_do_close(struct path *path, struct nfs4_state *state);
extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
...@@ -189,14 +202,13 @@ extern void nfs4_renew_state(struct work_struct *); ...@@ -189,14 +202,13 @@ extern void nfs4_renew_state(struct work_struct *);
/* nfs4state.c */ /* nfs4state.c */
struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp); struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp);
extern u32 nfs4_alloc_lockowner_id(struct nfs_client *);
extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
extern void nfs4_put_state_owner(struct nfs4_state_owner *); extern void nfs4_put_state_owner(struct nfs4_state_owner *);
extern void nfs4_drop_state_owner(struct nfs4_state_owner *); extern void nfs4_drop_state_owner(struct nfs4_state_owner *);
extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
extern void nfs4_put_open_state(struct nfs4_state *); extern void nfs4_put_open_state(struct nfs4_state *);
extern void nfs4_close_state(struct nfs4_state *, mode_t); extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t);
extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t); extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t);
extern void nfs4_schedule_state_recovery(struct nfs_client *); extern void nfs4_schedule_state_recovery(struct nfs_client *);
extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
...@@ -222,7 +234,7 @@ extern struct svc_version nfs4_callback_version1; ...@@ -222,7 +234,7 @@ extern struct svc_version nfs4_callback_version1;
#else #else
#define nfs4_close_state(a, b) do { } while (0) #define nfs4_close_state(a, b, c) do { } while (0)
#endif /* CONFIG_NFS_V4 */ #endif /* CONFIG_NFS_V4 */
#endif /* __LINUX_FS_NFS_NFS4_FS.H */ #endif /* __LINUX_FS_NFS_NFS4_FS.H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -428,7 +428,7 @@ static int __init root_nfs_getport(int program, int version, int proto) ...@@ -428,7 +428,7 @@ static int __init root_nfs_getport(int program, int version, int proto)
printk(KERN_NOTICE "Looking up port of RPC %d/%d on %u.%u.%u.%u\n", printk(KERN_NOTICE "Looking up port of RPC %d/%d on %u.%u.%u.%u\n",
program, version, NIPQUAD(servaddr)); program, version, NIPQUAD(servaddr));
set_sockaddr(&sin, servaddr, 0); set_sockaddr(&sin, servaddr, 0);
return rpcb_getport_external(&sin, program, version, proto); return rpcb_getport_sync(&sin, program, version, proto);
} }
...@@ -496,7 +496,8 @@ static int __init root_nfs_get_handle(void) ...@@ -496,7 +496,8 @@ static int __init root_nfs_get_handle(void)
NFS_MNT3_VERSION : NFS_MNT_VERSION; NFS_MNT3_VERSION : NFS_MNT_VERSION;
set_sockaddr(&sin, servaddr, htons(mount_port)); set_sockaddr(&sin, servaddr, htons(mount_port));
status = nfsroot_mount(&sin, nfs_path, &fh, version, protocol); status = nfs_mount((struct sockaddr *) &sin, sizeof(sin), NULL,
nfs_path, version, protocol, &fh);
if (status < 0) if (status < 0)
printk(KERN_ERR "Root-NFS: Server returned error %d " printk(KERN_ERR "Root-NFS: Server returned error %d "
"while mounting %s\n", status, nfs_path); "while mounting %s\n", status, nfs_path);
......
...@@ -85,9 +85,8 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, ...@@ -85,9 +85,8 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *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;
atomic_set(&req->wb_count, 1);
req->wb_context = get_nfs_open_context(ctx); req->wb_context = get_nfs_open_context(ctx);
kref_init(&req->wb_kref);
return req; return req;
} }
...@@ -109,30 +108,31 @@ void nfs_unlock_request(struct nfs_page *req) ...@@ -109,30 +108,31 @@ void nfs_unlock_request(struct nfs_page *req)
} }
/** /**
* nfs_set_page_writeback_locked - Lock a request for writeback * nfs_set_page_tag_locked - Tag a request as locked
* @req: * @req:
*/ */
int nfs_set_page_writeback_locked(struct nfs_page *req) static int nfs_set_page_tag_locked(struct nfs_page *req)
{ {
struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode);
if (!nfs_lock_request(req)) if (!nfs_lock_request(req))
return 0; return 0;
radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
return 1; return 1;
} }
/** /**
* nfs_clear_page_writeback - Unlock request and wake up sleepers * nfs_clear_page_tag_locked - Clear request tag and wake up sleepers
*/ */
void nfs_clear_page_writeback(struct nfs_page *req) void nfs_clear_page_tag_locked(struct nfs_page *req)
{ {
struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); struct inode *inode = req->wb_context->path.dentry->d_inode;
struct nfs_inode *nfsi = NFS_I(inode);
if (req->wb_page != NULL) { if (req->wb_page != NULL) {
spin_lock(&nfsi->req_lock); spin_lock(&inode->i_lock);
radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
spin_unlock(&nfsi->req_lock); spin_unlock(&inode->i_lock);
} }
nfs_unlock_request(req); nfs_unlock_request(req);
} }
...@@ -160,11 +160,9 @@ void nfs_clear_request(struct nfs_page *req) ...@@ -160,11 +160,9 @@ void nfs_clear_request(struct nfs_page *req)
* *
* Note: Should never be called with the spinlock held! * Note: Should never be called with the spinlock held!
*/ */
void static void nfs_free_request(struct kref *kref)
nfs_release_request(struct nfs_page *req)
{ {
if (!atomic_dec_and_test(&req->wb_count)) struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref);
return;
/* Release struct file or cached credential */ /* Release struct file or cached credential */
nfs_clear_request(req); nfs_clear_request(req);
...@@ -172,6 +170,11 @@ nfs_release_request(struct nfs_page *req) ...@@ -172,6 +170,11 @@ nfs_release_request(struct nfs_page *req)
nfs_page_free(req); nfs_page_free(req);
} }
void nfs_release_request(struct nfs_page *req)
{
kref_put(&req->wb_kref, nfs_free_request);
}
static int nfs_wait_bit_interruptible(void *word) static int nfs_wait_bit_interruptible(void *word)
{ {
int ret = 0; int ret = 0;
...@@ -193,7 +196,7 @@ static int nfs_wait_bit_interruptible(void *word) ...@@ -193,7 +196,7 @@ static int nfs_wait_bit_interruptible(void *word)
int int
nfs_wait_on_request(struct nfs_page *req) nfs_wait_on_request(struct nfs_page *req)
{ {
struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->dentry->d_inode); struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->path.dentry->d_inode);
sigset_t oldmask; sigset_t oldmask;
int ret = 0; int ret = 0;
...@@ -379,20 +382,20 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) ...@@ -379,20 +382,20 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
/** /**
* nfs_scan_list - Scan a list for matching requests * nfs_scan_list - Scan a list for matching requests
* @nfsi: NFS inode * @nfsi: NFS inode
* @head: One of the NFS inode request lists
* @dst: Destination list * @dst: Destination list
* @idx_start: lower bound of page->index to scan * @idx_start: lower bound of page->index to scan
* @npages: idx_start + npages sets the upper bound to scan. * @npages: idx_start + npages sets the upper bound to scan.
* @tag: tag to scan for
* *
* Moves elements from one of the inode request lists. * Moves elements from one of the inode request lists.
* If the number of requests is set to 0, the entire address_space * If the number of requests is set to 0, the entire address_space
* starting at index idx_start, is scanned. * starting at index idx_start, is scanned.
* The requests are *not* checked to ensure that they form a contiguous set. * The requests are *not* checked to ensure that they form a contiguous set.
* You must be holding the inode's req_lock when calling this function * You must be holding the inode's i_lock when calling this function
*/ */
int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, int nfs_scan_list(struct nfs_inode *nfsi,
struct list_head *dst, pgoff_t idx_start, struct list_head *dst, pgoff_t idx_start,
unsigned int npages) unsigned int npages, int tag)
{ {
struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES]; struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
struct nfs_page *req; struct nfs_page *req;
...@@ -407,9 +410,9 @@ int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, ...@@ -407,9 +410,9 @@ int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head,
idx_end = idx_start + npages - 1; idx_end = idx_start + npages - 1;
for (;;) { for (;;) {
found = radix_tree_gang_lookup(&nfsi->nfs_page_tree, found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree,
(void **)&pgvec[0], idx_start, (void **)&pgvec[0], idx_start,
NFS_SCAN_MAXENTRIES); NFS_SCAN_MAXENTRIES, tag);
if (found <= 0) if (found <= 0)
break; break;
for (i = 0; i < found; i++) { for (i = 0; i < found; i++) {
...@@ -417,15 +420,18 @@ int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, ...@@ -417,15 +420,18 @@ int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head,
if (req->wb_index > idx_end) if (req->wb_index > idx_end)
goto out; goto out;
idx_start = req->wb_index + 1; idx_start = req->wb_index + 1;
if (req->wb_list_head != head) if (nfs_set_page_tag_locked(req)) {
continue;
if (nfs_set_page_writeback_locked(req)) {
nfs_list_remove_request(req); nfs_list_remove_request(req);
radix_tree_tag_clear(&nfsi->nfs_page_tree,
req->wb_index, tag);
nfs_list_add_request(req, dst); nfs_list_add_request(req, dst);
res++; res++;
if (res == INT_MAX)
goto out;
} }
} }
/* for latency reduction */
cond_resched_lock(&nfsi->vfs_inode.i_lock);
} }
out: out:
return res; return res;
......
...@@ -145,8 +145,8 @@ static void nfs_readpage_release(struct nfs_page *req) ...@@ -145,8 +145,8 @@ static void nfs_readpage_release(struct nfs_page *req)
unlock_page(req->wb_page); unlock_page(req->wb_page);
dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", dprintk("NFS: read done (%s/%Ld %d@%Ld)\n",
req->wb_context->dentry->d_inode->i_sb->s_id, req->wb_context->path.dentry->d_inode->i_sb->s_id,
(long long)NFS_FILEID(req->wb_context->dentry->d_inode), (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
req->wb_bytes, req->wb_bytes,
(long long)req_offset(req)); (long long)req_offset(req));
nfs_clear_request(req); nfs_clear_request(req);
...@@ -164,7 +164,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, ...@@ -164,7 +164,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
int flags; int flags;
data->req = req; data->req = req;
data->inode = inode = req->wb_context->dentry->d_inode; data->inode = inode = req->wb_context->path.dentry->d_inode;
data->cred = req->wb_context->cred; data->cred = req->wb_context->cred;
data->args.fh = NFS_FH(inode); data->args.fh = NFS_FH(inode);
...@@ -483,17 +483,19 @@ int nfs_readpage(struct file *file, struct page *page) ...@@ -483,17 +483,19 @@ int nfs_readpage(struct file *file, struct page *page)
*/ */
error = nfs_wb_page(inode, page); error = nfs_wb_page(inode, page);
if (error) if (error)
goto out_error; goto out_unlock;
if (PageUptodate(page))
goto out_unlock;
error = -ESTALE; error = -ESTALE;
if (NFS_STALE(inode)) if (NFS_STALE(inode))
goto out_error; goto out_unlock;
if (file == NULL) { if (file == NULL) {
error = -EBADF; error = -EBADF;
ctx = nfs_find_open_context(inode, NULL, FMODE_READ); ctx = nfs_find_open_context(inode, NULL, FMODE_READ);
if (ctx == NULL) if (ctx == NULL)
goto out_error; goto out_unlock;
} else } else
ctx = get_nfs_open_context((struct nfs_open_context *) ctx = get_nfs_open_context((struct nfs_open_context *)
file->private_data); file->private_data);
...@@ -502,8 +504,7 @@ int nfs_readpage(struct file *file, struct page *page) ...@@ -502,8 +504,7 @@ int nfs_readpage(struct file *file, struct page *page)
put_nfs_open_context(ctx); put_nfs_open_context(ctx);
return error; return error;
out_unlock:
out_error:
unlock_page(page); unlock_page(page);
return error; return error;
} }
...@@ -520,21 +521,32 @@ readpage_async_filler(void *data, struct page *page) ...@@ -520,21 +521,32 @@ readpage_async_filler(void *data, struct page *page)
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
struct nfs_page *new; struct nfs_page *new;
unsigned int len; unsigned int len;
int error;
error = nfs_wb_page(inode, page);
if (error)
goto out_unlock;
if (PageUptodate(page))
goto out_unlock;
nfs_wb_page(inode, page);
len = nfs_page_length(page); len = nfs_page_length(page);
if (len == 0) if (len == 0)
return nfs_return_empty_page(page); return nfs_return_empty_page(page);
new = nfs_create_request(desc->ctx, inode, page, 0, len); new = nfs_create_request(desc->ctx, inode, page, 0, len);
if (IS_ERR(new)) { if (IS_ERR(new))
SetPageError(page); goto out_error;
unlock_page(page);
return PTR_ERR(new);
}
if (len < PAGE_CACHE_SIZE) if (len < PAGE_CACHE_SIZE)
zero_user_page(page, len, PAGE_CACHE_SIZE - len, KM_USER0); zero_user_page(page, len, PAGE_CACHE_SIZE - len, KM_USER0);
nfs_pageio_add_request(desc->pgio, new); nfs_pageio_add_request(desc->pgio, new);
return 0; return 0;
out_error:
error = PTR_ERR(new);
SetPageError(page);
out_unlock:
unlock_page(page);
return error;
} }
int nfs_readpages(struct file *filp, struct address_space *mapping, int nfs_readpages(struct file *filp, struct address_space *mapping,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -378,7 +378,6 @@ shutdown_callback_client(struct nfs4_client *clp) ...@@ -378,7 +378,6 @@ shutdown_callback_client(struct nfs4_client *clp)
if (clnt) { if (clnt) {
clp->cl_callback.cb_client = NULL; clp->cl_callback.cb_client = NULL;
rpc_shutdown_client(clnt); rpc_shutdown_client(clnt);
rpciod_down();
} }
} }
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
struct nlm_host { struct nlm_host {
struct hlist_node h_hash; /* doubly linked list */ struct hlist_node h_hash; /* doubly linked list */
struct sockaddr_in h_addr; /* peer address */ struct sockaddr_in h_addr; /* peer address */
struct sockaddr_in h_saddr; /* our address (optional) */
struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */ struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */
char * h_name; /* remote hostname */ char * h_name; /* remote hostname */
u32 h_version; /* interface version */ u32 h_version; /* interface version */
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/types.h> #include <linux/types.h>
#define NFS4_BITMAP_SIZE 2
#define NFS4_VERIFIER_SIZE 8 #define NFS4_VERIFIER_SIZE 8
#define NFS4_STATEID_SIZE 16 #define NFS4_STATEID_SIZE 16
#define NFS4_FHSIZE 128 #define NFS4_FHSIZE 128
......
...@@ -65,6 +65,7 @@ struct nfs4_mount_data { ...@@ -65,6 +65,7 @@ struct nfs4_mount_data {
#define NFS4_MOUNT_NOCTO 0x0010 /* 1 */ #define NFS4_MOUNT_NOCTO 0x0010 /* 1 */
#define NFS4_MOUNT_NOAC 0x0020 /* 1 */ #define NFS4_MOUNT_NOAC 0x0020 /* 1 */
#define NFS4_MOUNT_STRICTLOCK 0x1000 /* 1 */ #define NFS4_MOUNT_STRICTLOCK 0x1000 /* 1 */
#define NFS4_MOUNT_FLAGMASK 0xFFFF #define NFS4_MOUNT_UNSHARED 0x8000 /* 1 */
#define NFS4_MOUNT_FLAGMASK 0x9033
#endif #endif
This diff is collapsed.
This diff is collapsed.
...@@ -37,7 +37,7 @@ struct nfs_mount_data { ...@@ -37,7 +37,7 @@ struct nfs_mount_data {
int acdirmin; /* 1 */ int acdirmin; /* 1 */
int acdirmax; /* 1 */ int acdirmax; /* 1 */
struct sockaddr_in addr; /* 1 */ struct sockaddr_in addr; /* 1 */
char hostname[256]; /* 1 */ char hostname[NFS_MAXNAMLEN + 1]; /* 1 */
int namlen; /* 2 */ int namlen; /* 2 */
unsigned int bsize; /* 3 */ unsigned int bsize; /* 3 */
struct nfs3_fh root; /* 4 */ struct nfs3_fh root; /* 4 */
...@@ -62,6 +62,7 @@ struct nfs_mount_data { ...@@ -62,6 +62,7 @@ struct nfs_mount_data {
#define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */ #define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */
#define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */ #define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */
#define NFS_MOUNT_NORDIRPLUS 0x4000 /* 5 */ #define NFS_MOUNT_NORDIRPLUS 0x4000 /* 5 */
#define NFS_MOUNT_UNSHARED 0x8000 /* 5 */
#define NFS_MOUNT_FLAGMASK 0xFFFF #define NFS_MOUNT_FLAGMASK 0xFFFF
#endif #endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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