提交 47853e7f 编写于 作者: L Linus Torvalds
...@@ -910,6 +910,14 @@ running once the system is up. ...@@ -910,6 +910,14 @@ running once the system is up.
nfsroot= [NFS] nfs root filesystem for disk-less boxes. nfsroot= [NFS] nfs root filesystem for disk-less boxes.
See Documentation/nfsroot.txt. See Documentation/nfsroot.txt.
nfs.callback_tcpport=
[NFS] set the TCP port on which the NFSv4 callback
channel should listen.
nfs.idmap_cache_timeout=
[NFS] set the maximum lifetime for idmapper cache
entries.
nmi_watchdog= [KNL,BUGS=IA-32] Debugging features for SMP kernels nmi_watchdog= [KNL,BUGS=IA-32] Debugging features for SMP kernels
no387 [BUGS=IA-32] Tells the kernel to use the 387 maths no387 [BUGS=IA-32] Tells the kernel to use the 387 maths
......
...@@ -26,11 +26,12 @@ ...@@ -26,11 +26,12 @@
static int nlmclnt_test(struct nlm_rqst *, struct file_lock *); static int nlmclnt_test(struct nlm_rqst *, struct file_lock *);
static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *); static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *);
static int nlmclnt_unlock(struct nlm_rqst *, struct file_lock *); static int nlmclnt_unlock(struct nlm_rqst *, struct file_lock *);
static void nlmclnt_unlock_callback(struct rpc_task *);
static void nlmclnt_cancel_callback(struct rpc_task *);
static int nlm_stat_to_errno(u32 stat); static int nlm_stat_to_errno(u32 stat);
static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host); static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host);
static const struct rpc_call_ops nlmclnt_unlock_ops;
static const struct rpc_call_ops nlmclnt_cancel_ops;
/* /*
* Cookie counter for NLM requests * Cookie counter for NLM requests
*/ */
...@@ -221,8 +222,7 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) ...@@ -221,8 +222,7 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
goto done; goto done;
} }
clnt->cl_softrtry = nfssrv->client->cl_softrtry; clnt->cl_softrtry = nfssrv->client->cl_softrtry;
clnt->cl_intr = nfssrv->client->cl_intr; clnt->cl_intr = nfssrv->client->cl_intr;
clnt->cl_chatty = nfssrv->client->cl_chatty;
} }
/* Keep the old signal mask */ /* Keep the old signal mask */
...@@ -399,8 +399,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc) ...@@ -399,8 +399,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
/* /*
* Generic NLM call, async version. * Generic NLM call, async version.
*/ */
int int nlmsvc_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
nlmsvc_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
{ {
struct nlm_host *host = req->a_host; struct nlm_host *host = req->a_host;
struct rpc_clnt *clnt; struct rpc_clnt *clnt;
...@@ -419,13 +418,12 @@ nlmsvc_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback) ...@@ -419,13 +418,12 @@ nlmsvc_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
msg.rpc_proc = &clnt->cl_procinfo[proc]; msg.rpc_proc = &clnt->cl_procinfo[proc];
/* bootstrap and kick off the async RPC call */ /* bootstrap and kick off the async RPC call */
status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req); status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req);
return status; return status;
} }
static int static int nlmclnt_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
{ {
struct nlm_host *host = req->a_host; struct nlm_host *host = req->a_host;
struct rpc_clnt *clnt; struct rpc_clnt *clnt;
...@@ -448,7 +446,7 @@ nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback) ...@@ -448,7 +446,7 @@ nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
/* Increment host refcount */ /* Increment host refcount */
nlm_get_host(host); nlm_get_host(host);
/* bootstrap and kick off the async RPC call */ /* bootstrap and kick off the async RPC call */
status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req); status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req);
if (status < 0) if (status < 0)
nlm_release_host(host); nlm_release_host(host);
return status; return status;
...@@ -664,7 +662,7 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) ...@@ -664,7 +662,7 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
if (req->a_flags & RPC_TASK_ASYNC) { if (req->a_flags & RPC_TASK_ASYNC) {
status = nlmclnt_async_call(req, NLMPROC_UNLOCK, status = nlmclnt_async_call(req, NLMPROC_UNLOCK,
nlmclnt_unlock_callback); &nlmclnt_unlock_ops);
/* Hrmf... Do the unlock early since locks_remove_posix() /* Hrmf... Do the unlock early since locks_remove_posix()
* really expects us to free the lock synchronously */ * really expects us to free the lock synchronously */
do_vfs_lock(fl); do_vfs_lock(fl);
...@@ -692,10 +690,9 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) ...@@ -692,10 +690,9 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
return -ENOLCK; return -ENOLCK;
} }
static void static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
nlmclnt_unlock_callback(struct rpc_task *task)
{ {
struct nlm_rqst *req = (struct nlm_rqst *) task->tk_calldata; struct nlm_rqst *req = data;
int status = req->a_res.status; int status = req->a_res.status;
if (RPC_ASSASSINATED(task)) if (RPC_ASSASSINATED(task))
...@@ -722,6 +719,10 @@ nlmclnt_unlock_callback(struct rpc_task *task) ...@@ -722,6 +719,10 @@ nlmclnt_unlock_callback(struct rpc_task *task)
rpc_restart_call(task); rpc_restart_call(task);
} }
static const struct rpc_call_ops nlmclnt_unlock_ops = {
.rpc_call_done = nlmclnt_unlock_callback,
};
/* /*
* Cancel a blocked lock request. * Cancel a blocked lock request.
* We always use an async RPC call for this in order not to hang a * We always use an async RPC call for this in order not to hang a
...@@ -750,8 +751,7 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl) ...@@ -750,8 +751,7 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
nlmclnt_setlockargs(req, fl); nlmclnt_setlockargs(req, fl);
status = nlmclnt_async_call(req, NLMPROC_CANCEL, status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
nlmclnt_cancel_callback);
if (status < 0) { if (status < 0) {
nlmclnt_release_lockargs(req); nlmclnt_release_lockargs(req);
kfree(req); kfree(req);
...@@ -765,10 +765,9 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl) ...@@ -765,10 +765,9 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
return status; return status;
} }
static void static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
nlmclnt_cancel_callback(struct rpc_task *task)
{ {
struct nlm_rqst *req = (struct nlm_rqst *) task->tk_calldata; struct nlm_rqst *req = data;
if (RPC_ASSASSINATED(task)) if (RPC_ASSASSINATED(task))
goto die; goto die;
...@@ -807,6 +806,10 @@ nlmclnt_cancel_callback(struct rpc_task *task) ...@@ -807,6 +806,10 @@ nlmclnt_cancel_callback(struct rpc_task *task)
rpc_delay(task, 30 * HZ); rpc_delay(task, 30 * HZ);
} }
static const struct rpc_call_ops nlmclnt_cancel_ops = {
.rpc_call_done = nlmclnt_cancel_callback,
};
/* /*
* Convert an NLM status code to a generic kernel errno * Convert an NLM status code to a generic kernel errno
*/ */
......
...@@ -177,7 +177,7 @@ nlm_bind_host(struct nlm_host *host) ...@@ -177,7 +177,7 @@ nlm_bind_host(struct nlm_host *host)
if ((clnt = host->h_rpcclnt) != NULL) { if ((clnt = host->h_rpcclnt) != NULL) {
xprt = clnt->cl_xprt; xprt = clnt->cl_xprt;
if (time_after_eq(jiffies, host->h_nextrebind)) { if (time_after_eq(jiffies, host->h_nextrebind)) {
clnt->cl_port = 0; rpc_force_rebind(clnt);
host->h_nextrebind = jiffies + NLM_HOST_REBIND; host->h_nextrebind = jiffies + NLM_HOST_REBIND;
dprintk("lockd: next rebind in %ld jiffies\n", dprintk("lockd: next rebind in %ld jiffies\n",
host->h_nextrebind - jiffies); host->h_nextrebind - jiffies);
...@@ -217,7 +217,7 @@ nlm_rebind_host(struct nlm_host *host) ...@@ -217,7 +217,7 @@ nlm_rebind_host(struct nlm_host *host)
{ {
dprintk("lockd: rebind host %s\n", host->h_name); dprintk("lockd: rebind host %s\n", host->h_name);
if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) { if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) {
host->h_rpcclnt->cl_port = 0; rpc_force_rebind(host->h_rpcclnt);
host->h_nextrebind = jiffies + NLM_HOST_REBIND; host->h_nextrebind = jiffies + NLM_HOST_REBIND;
} }
} }
......
...@@ -123,7 +123,6 @@ nsm_create(void) ...@@ -123,7 +123,6 @@ nsm_create(void)
if (IS_ERR(clnt)) if (IS_ERR(clnt))
goto out_err; goto out_err;
clnt->cl_softrtry = 1; clnt->cl_softrtry = 1;
clnt->cl_chatty = 1;
clnt->cl_oneshot = 1; clnt->cl_oneshot = 1;
return clnt; return clnt;
......
...@@ -178,6 +178,8 @@ lockd(struct svc_rqst *rqstp) ...@@ -178,6 +178,8 @@ lockd(struct svc_rqst *rqstp)
} }
flush_signals(current);
/* /*
* Check whether there's a new lockd process before * Check whether there's a new lockd process before
* shutting down the hosts and clearing the slot. * shutting down the hosts and clearing the slot.
...@@ -192,8 +194,6 @@ lockd(struct svc_rqst *rqstp) ...@@ -192,8 +194,6 @@ lockd(struct svc_rqst *rqstp)
"lockd: new process, skipping host shutdown\n"); "lockd: new process, skipping host shutdown\n");
wake_up(&lockd_exit); wake_up(&lockd_exit);
flush_signals(current);
/* Exit the RPC thread */ /* Exit the RPC thread */
svc_exit_thread(rqstp); svc_exit_thread(rqstp);
......
...@@ -22,7 +22,8 @@ ...@@ -22,7 +22,8 @@
#define NLMDBG_FACILITY NLMDBG_CLIENT #define NLMDBG_FACILITY NLMDBG_CLIENT
static u32 nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *); static u32 nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *);
static void nlm4svc_callback_exit(struct rpc_task *);
static const struct rpc_call_ops nlm4svc_callback_ops;
/* /*
* Obtain client and file from arguments * Obtain client and file from arguments
...@@ -470,7 +471,6 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, ...@@ -470,7 +471,6 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp,
} }
/* /*
* This is the generic lockd callback for async RPC calls * This is the generic lockd callback for async RPC calls
*/ */
...@@ -494,7 +494,7 @@ nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp) ...@@ -494,7 +494,7 @@ nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
call->a_host = host; call->a_host = host;
memcpy(&call->a_args, resp, sizeof(*resp)); memcpy(&call->a_args, resp, sizeof(*resp));
if (nlmsvc_async_call(call, proc, nlm4svc_callback_exit) < 0) if (nlmsvc_async_call(call, proc, &nlm4svc_callback_ops) < 0)
goto error; goto error;
return rpc_success; return rpc_success;
...@@ -504,10 +504,9 @@ nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp) ...@@ -504,10 +504,9 @@ nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
return rpc_system_err; return rpc_system_err;
} }
static void static void nlm4svc_callback_exit(struct rpc_task *task, void *data)
nlm4svc_callback_exit(struct rpc_task *task)
{ {
struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata; struct nlm_rqst *call = data;
if (task->tk_status < 0) { if (task->tk_status < 0) {
dprintk("lockd: %4d callback failed (errno = %d)\n", dprintk("lockd: %4d callback failed (errno = %d)\n",
...@@ -517,6 +516,10 @@ nlm4svc_callback_exit(struct rpc_task *task) ...@@ -517,6 +516,10 @@ nlm4svc_callback_exit(struct rpc_task *task)
kfree(call); kfree(call);
} }
static const struct rpc_call_ops nlm4svc_callback_ops = {
.rpc_call_done = nlm4svc_callback_exit,
};
/* /*
* NLM Server procedures. * NLM Server procedures.
*/ */
......
...@@ -41,7 +41,8 @@ ...@@ -41,7 +41,8 @@
static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); static void nlmsvc_insert_block(struct nlm_block *block, unsigned long);
static int nlmsvc_remove_block(struct nlm_block *block); static int nlmsvc_remove_block(struct nlm_block *block);
static void nlmsvc_grant_callback(struct rpc_task *task);
static const struct rpc_call_ops nlmsvc_grant_ops;
/* /*
* The list of blocked locks to retry * The list of blocked locks to retry
...@@ -226,31 +227,27 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, ...@@ -226,31 +227,27 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
* It is the caller's responsibility to check whether the file * It is the caller's responsibility to check whether the file
* can be closed hereafter. * can be closed hereafter.
*/ */
static void static int
nlmsvc_delete_block(struct nlm_block *block, int unlock) nlmsvc_delete_block(struct nlm_block *block, int unlock)
{ {
struct file_lock *fl = &block->b_call.a_args.lock.fl; struct file_lock *fl = &block->b_call.a_args.lock.fl;
struct nlm_file *file = block->b_file; struct nlm_file *file = block->b_file;
struct nlm_block **bp; struct nlm_block **bp;
int status = 0;
dprintk("lockd: deleting block %p...\n", block); dprintk("lockd: deleting block %p...\n", block);
/* Remove block from list */ /* Remove block from list */
nlmsvc_remove_block(block); nlmsvc_remove_block(block);
if (fl->fl_next) if (unlock)
posix_unblock_lock(file->f_file, fl); status = posix_unblock_lock(file->f_file, fl);
if (unlock) {
fl->fl_type = F_UNLCK;
posix_lock_file(file->f_file, fl);
block->b_granted = 0;
}
/* If the block is in the middle of a GRANT callback, /* If the block is in the middle of a GRANT callback,
* don't kill it yet. */ * don't kill it yet. */
if (block->b_incall) { if (block->b_incall) {
nlmsvc_insert_block(block, NLM_NEVER); nlmsvc_insert_block(block, NLM_NEVER);
block->b_done = 1; block->b_done = 1;
return; return status;
} }
/* Remove block from file's list of blocks */ /* Remove block from file's list of blocks */
...@@ -265,6 +262,7 @@ nlmsvc_delete_block(struct nlm_block *block, int unlock) ...@@ -265,6 +262,7 @@ nlmsvc_delete_block(struct nlm_block *block, int unlock)
nlm_release_host(block->b_host); nlm_release_host(block->b_host);
nlmclnt_freegrantargs(&block->b_call); nlmclnt_freegrantargs(&block->b_call);
kfree(block); kfree(block);
return status;
} }
/* /*
...@@ -275,6 +273,7 @@ int ...@@ -275,6 +273,7 @@ int
nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action) nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
{ {
struct nlm_block *block, *next; struct nlm_block *block, *next;
/* XXX: Will everything get cleaned up if we don't unlock here? */
down(&file->f_sema); down(&file->f_sema);
for (block = file->f_blocks; block; block = next) { for (block = file->f_blocks; block; block = next) {
...@@ -444,6 +443,7 @@ u32 ...@@ -444,6 +443,7 @@ u32
nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
{ {
struct nlm_block *block; struct nlm_block *block;
int status = 0;
dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n", dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n",
file->f_file->f_dentry->d_inode->i_sb->s_id, file->f_file->f_dentry->d_inode->i_sb->s_id,
...@@ -454,9 +454,9 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) ...@@ -454,9 +454,9 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
down(&file->f_sema); down(&file->f_sema);
if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL)
nlmsvc_delete_block(block, 1); status = nlmsvc_delete_block(block, 1);
up(&file->f_sema); up(&file->f_sema);
return nlm_granted; return status ? nlm_lck_denied : nlm_granted;
} }
/* /*
...@@ -562,7 +562,7 @@ nlmsvc_grant_blocked(struct nlm_block *block) ...@@ -562,7 +562,7 @@ nlmsvc_grant_blocked(struct nlm_block *block)
/* Call the client */ /* Call the client */
nlm_get_host(block->b_call.a_host); nlm_get_host(block->b_call.a_host);
if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG, if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG,
nlmsvc_grant_callback) < 0) &nlmsvc_grant_ops) < 0)
nlm_release_host(block->b_call.a_host); nlm_release_host(block->b_call.a_host);
up(&file->f_sema); up(&file->f_sema);
} }
...@@ -575,10 +575,9 @@ nlmsvc_grant_blocked(struct nlm_block *block) ...@@ -575,10 +575,9 @@ nlmsvc_grant_blocked(struct nlm_block *block)
* chain once more in order to have it removed by lockd itself (which can * chain once more in order to have it removed by lockd itself (which can
* then sleep on the file semaphore without disrupting e.g. the nfs client). * then sleep on the file semaphore without disrupting e.g. the nfs client).
*/ */
static void static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
nlmsvc_grant_callback(struct rpc_task *task)
{ {
struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata; struct nlm_rqst *call = data;
struct nlm_block *block; struct nlm_block *block;
unsigned long timeout; unsigned long timeout;
struct sockaddr_in *peer_addr = RPC_PEERADDR(task->tk_client); struct sockaddr_in *peer_addr = RPC_PEERADDR(task->tk_client);
...@@ -614,6 +613,10 @@ nlmsvc_grant_callback(struct rpc_task *task) ...@@ -614,6 +613,10 @@ nlmsvc_grant_callback(struct rpc_task *task)
nlm_release_host(call->a_host); nlm_release_host(call->a_host);
} }
static const struct rpc_call_ops nlmsvc_grant_ops = {
.rpc_call_done = nlmsvc_grant_callback,
};
/* /*
* We received a GRANT_RES callback. Try to find the corresponding * We received a GRANT_RES callback. Try to find the corresponding
* block. * block.
...@@ -633,11 +636,12 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status ...@@ -633,11 +636,12 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status
file->f_count++; file->f_count++;
down(&file->f_sema); down(&file->f_sema);
if ((block = nlmsvc_find_block(cookie,&rqstp->rq_addr)) != NULL) { block = nlmsvc_find_block(cookie, &rqstp->rq_addr);
if (block) {
if (status == NLM_LCK_DENIED_GRACE_PERIOD) { if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
/* Try again in a couple of seconds */ /* Try again in a couple of seconds */
nlmsvc_insert_block(block, 10 * HZ); nlmsvc_insert_block(block, 10 * HZ);
block = NULL; up(&file->f_sema);
} else { } else {
/* Lock is now held by client, or has been rejected. /* Lock is now held by client, or has been rejected.
* In both cases, the block should be removed. */ * In both cases, the block should be removed. */
...@@ -648,8 +652,6 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status ...@@ -648,8 +652,6 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status
nlmsvc_delete_block(block, 1); nlmsvc_delete_block(block, 1);
} }
} }
if (!block)
up(&file->f_sema);
nlm_release_file(file); nlm_release_file(file);
} }
......
...@@ -23,7 +23,8 @@ ...@@ -23,7 +23,8 @@
#define NLMDBG_FACILITY NLMDBG_CLIENT #define NLMDBG_FACILITY NLMDBG_CLIENT
static u32 nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *); static u32 nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *);
static void nlmsvc_callback_exit(struct rpc_task *);
static const struct rpc_call_ops nlmsvc_callback_ops;
#ifdef CONFIG_LOCKD_V4 #ifdef CONFIG_LOCKD_V4
static u32 static u32
...@@ -518,7 +519,7 @@ nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp) ...@@ -518,7 +519,7 @@ nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
call->a_host = host; call->a_host = host;
memcpy(&call->a_args, resp, sizeof(*resp)); memcpy(&call->a_args, resp, sizeof(*resp));
if (nlmsvc_async_call(call, proc, nlmsvc_callback_exit) < 0) if (nlmsvc_async_call(call, proc, &nlmsvc_callback_ops) < 0)
goto error; goto error;
return rpc_success; return rpc_success;
...@@ -528,10 +529,9 @@ nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp) ...@@ -528,10 +529,9 @@ nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
return rpc_system_err; return rpc_system_err;
} }
static void static void nlmsvc_callback_exit(struct rpc_task *task, void *data)
nlmsvc_callback_exit(struct rpc_task *task)
{ {
struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata; struct nlm_rqst *call = data;
if (task->tk_status < 0) { if (task->tk_status < 0) {
dprintk("lockd: %4d callback failed (errno = %d)\n", dprintk("lockd: %4d callback failed (errno = %d)\n",
...@@ -541,6 +541,10 @@ nlmsvc_callback_exit(struct rpc_task *task) ...@@ -541,6 +541,10 @@ nlmsvc_callback_exit(struct rpc_task *task)
kfree(call); kfree(call);
} }
static const struct rpc_call_ops nlmsvc_callback_ops = {
.rpc_call_done = nlmsvc_callback_exit,
};
/* /*
* NLM Server procedures. * NLM Server procedures.
*/ */
......
...@@ -354,7 +354,9 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp) ...@@ -354,7 +354,9 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
return 0; return 0;
argp->state = ntohl(*p++); argp->state = ntohl(*p++);
/* Preserve the address in network byte order */ /* Preserve the address in network byte order */
argp->addr = *p++; argp->addr = *p++;
argp->vers = *p++;
argp->proto = *p++;
return xdr_argsize_check(rqstp, p); return xdr_argsize_check(rqstp, p);
} }
......
...@@ -1958,22 +1958,18 @@ EXPORT_SYMBOL(posix_block_lock); ...@@ -1958,22 +1958,18 @@ EXPORT_SYMBOL(posix_block_lock);
* *
* lockd needs to block waiting for locks. * lockd needs to block waiting for locks.
*/ */
void int
posix_unblock_lock(struct file *filp, struct file_lock *waiter) posix_unblock_lock(struct file *filp, struct file_lock *waiter)
{ {
/* int status = 0;
* A remote machine may cancel the lock request after it's been
* granted locally. If that happens, we need to delete the lock.
*/
lock_kernel(); lock_kernel();
if (waiter->fl_next) { if (waiter->fl_next)
__locks_delete_block(waiter); __locks_delete_block(waiter);
unlock_kernel(); else
} else { status = -ENOENT;
unlock_kernel(); unlock_kernel();
waiter->fl_type = F_UNLCK; return status;
posix_lock_file(filp, waiter);
}
} }
EXPORT_SYMBOL(posix_unblock_lock); EXPORT_SYMBOL(posix_unblock_lock);
......
...@@ -13,4 +13,5 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ ...@@ -13,4 +13,5 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
delegation.o idmap.o \ delegation.o idmap.o \
callback.o callback_xdr.o callback_proc.o callback.o callback_xdr.o callback_proc.o
nfs-$(CONFIG_NFS_DIRECTIO) += direct.o nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
nfs-$(CONFIG_SYSCTL) += sysctl.o
nfs-objs := $(nfs-y) nfs-objs := $(nfs-y)
...@@ -34,6 +34,7 @@ static struct nfs_callback_data nfs_callback_info; ...@@ -34,6 +34,7 @@ static struct nfs_callback_data nfs_callback_info;
static DECLARE_MUTEX(nfs_callback_sema); static DECLARE_MUTEX(nfs_callback_sema);
static struct svc_program nfs4_callback_program; static struct svc_program nfs4_callback_program;
unsigned int nfs_callback_set_tcpport;
unsigned short nfs_callback_tcpport; unsigned short nfs_callback_tcpport;
/* /*
...@@ -98,7 +99,7 @@ int nfs_callback_up(void) ...@@ -98,7 +99,7 @@ int nfs_callback_up(void)
if (!serv) if (!serv)
goto out_err; goto out_err;
/* FIXME: We don't want to register this socket with the portmapper */ /* FIXME: We don't want to register this socket with the portmapper */
ret = svc_makesock(serv, IPPROTO_TCP, 0); ret = svc_makesock(serv, IPPROTO_TCP, nfs_callback_set_tcpport);
if (ret < 0) if (ret < 0)
goto out_destroy; goto out_destroy;
if (!list_empty(&serv->sv_permsocks)) { if (!list_empty(&serv->sv_permsocks)) {
......
...@@ -65,6 +65,7 @@ extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy); ...@@ -65,6 +65,7 @@ extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
extern int nfs_callback_up(void); extern int nfs_callback_up(void);
extern int nfs_callback_down(void); extern int nfs_callback_down(void);
extern unsigned int nfs_callback_set_tcpport;
extern unsigned short nfs_callback_tcpport; extern unsigned short nfs_callback_tcpport;
#endif /* __LINUX_FS_NFS_CALLBACK_H */ #endif /* __LINUX_FS_NFS_CALLBACK_H */
...@@ -35,7 +35,9 @@ unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres ...@@ -35,7 +35,9 @@ unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres
if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0) if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0)
goto out_iput; goto out_iput;
res->size = i_size_read(inode); res->size = i_size_read(inode);
res->change_attr = NFS_CHANGE_ATTR(inode); res->change_attr = delegation->change_attr;
if (nfsi->npages != 0)
res->change_attr++;
res->ctime = inode->i_ctime; res->ctime = inode->i_ctime;
res->mtime = inode->i_mtime; res->mtime = inode->i_mtime;
res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) & res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) &
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/kthread.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
...@@ -130,6 +131,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct ...@@ -130,6 +131,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
sizeof(delegation->stateid.data)); sizeof(delegation->stateid.data));
delegation->type = res->delegation_type; delegation->type = res->delegation_type;
delegation->maxsize = res->maxsize; delegation->maxsize = res->maxsize;
delegation->change_attr = nfsi->change_attr;
delegation->cred = get_rpccred(cred); delegation->cred = get_rpccred(cred);
delegation->inode = inode; delegation->inode = inode;
...@@ -157,8 +159,6 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation * ...@@ -157,8 +159,6 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *
{ {
int res = 0; int res = 0;
__nfs_revalidate_inode(NFS_SERVER(inode), inode);
res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid); res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid);
nfs_free_delegation(delegation); nfs_free_delegation(delegation);
return res; return res;
...@@ -231,6 +231,49 @@ void nfs_return_all_delegations(struct super_block *sb) ...@@ -231,6 +231,49 @@ void nfs_return_all_delegations(struct super_block *sb)
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
} }
int nfs_do_expire_all_delegations(void *ptr)
{
struct nfs4_client *clp = ptr;
struct nfs_delegation *delegation;
struct inode *inode;
allow_signal(SIGKILL);
restart:
spin_lock(&clp->cl_lock);
if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0)
goto out;
if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0)
goto out;
list_for_each_entry(delegation, &clp->cl_delegations, super_list) {
inode = igrab(delegation->inode);
if (inode == NULL)
continue;
spin_unlock(&clp->cl_lock);
nfs_inode_return_delegation(inode);
iput(inode);
goto restart;
}
out:
spin_unlock(&clp->cl_lock);
nfs4_put_client(clp);
module_put_and_exit(0);
}
void nfs_expire_all_delegations(struct nfs4_client *clp)
{
struct task_struct *task;
__module_get(THIS_MODULE);
atomic_inc(&clp->cl_count);
task = kthread_run(nfs_do_expire_all_delegations, clp,
"%u.%u.%u.%u-delegreturn",
NIPQUAD(clp->cl_addr));
if (!IS_ERR(task))
return;
nfs4_put_client(clp);
module_put(THIS_MODULE);
}
/* /*
* Return all delegations following an NFS4ERR_CB_PATH_DOWN error. * Return all delegations following an NFS4ERR_CB_PATH_DOWN error.
*/ */
......
...@@ -21,6 +21,7 @@ struct nfs_delegation { ...@@ -21,6 +21,7 @@ struct nfs_delegation {
#define NFS_DELEGATION_NEED_RECLAIM 1 #define NFS_DELEGATION_NEED_RECLAIM 1
long flags; long flags;
loff_t maxsize; loff_t maxsize;
__u64 change_attr;
}; };
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);
...@@ -30,6 +31,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s ...@@ -30,6 +31,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s
struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle);
void nfs_return_all_delegations(struct super_block *sb); void nfs_return_all_delegations(struct super_block *sb);
void nfs_expire_all_delegations(struct nfs4_client *clp);
void nfs_handle_cb_pathdown(struct nfs4_client *clp); void nfs_handle_cb_pathdown(struct nfs4_client *clp);
void nfs_delegation_mark_reclaim(struct nfs4_client *clp); void nfs_delegation_mark_reclaim(struct nfs4_client *clp);
......
...@@ -1550,8 +1550,10 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1550,8 +1550,10 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
} }
nfs_inode_return_delegation(old_inode); nfs_inode_return_delegation(old_inode);
if (new_inode) if (new_inode != NULL) {
nfs_inode_return_delegation(new_inode);
d_delete(new_dentry); d_delete(new_dentry);
}
nfs_begin_data_update(old_dir); nfs_begin_data_update(old_dir);
nfs_begin_data_update(new_dir); nfs_begin_data_update(new_dir);
......
...@@ -122,9 +122,10 @@ nfs_free_user_pages(struct page **pages, int npages, int do_dirty) ...@@ -122,9 +122,10 @@ nfs_free_user_pages(struct page **pages, int npages, int do_dirty)
{ {
int i; int i;
for (i = 0; i < npages; i++) { for (i = 0; i < npages; i++) {
if (do_dirty) struct page *page = pages[i];
set_page_dirty_lock(pages[i]); if (do_dirty && !PageCompound(page))
page_cache_release(pages[i]); set_page_dirty_lock(page);
page_cache_release(page);
} }
kfree(pages); kfree(pages);
} }
...@@ -154,6 +155,7 @@ static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, unsigned int ...@@ -154,6 +155,7 @@ static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, unsigned int
struct list_head *list; struct list_head *list;
struct nfs_direct_req *dreq; struct nfs_direct_req *dreq;
unsigned int reads = 0; unsigned int reads = 0;
unsigned int rpages = (rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
dreq = kmem_cache_alloc(nfs_direct_cachep, SLAB_KERNEL); dreq = kmem_cache_alloc(nfs_direct_cachep, SLAB_KERNEL);
if (!dreq) if (!dreq)
...@@ -167,7 +169,7 @@ static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, unsigned int ...@@ -167,7 +169,7 @@ static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, unsigned int
list = &dreq->list; list = &dreq->list;
for(;;) { for(;;) {
struct nfs_read_data *data = nfs_readdata_alloc(); struct nfs_read_data *data = nfs_readdata_alloc(rpages);
if (unlikely(!data)) { if (unlikely(!data)) {
while (!list_empty(list)) { while (!list_empty(list)) {
...@@ -268,8 +270,6 @@ static void nfs_direct_read_schedule(struct nfs_direct_req *dreq, ...@@ -268,8 +270,6 @@ static void nfs_direct_read_schedule(struct nfs_direct_req *dreq,
NFS_PROTO(inode)->read_setup(data); NFS_PROTO(inode)->read_setup(data);
data->task.tk_cookie = (unsigned long) inode; data->task.tk_cookie = (unsigned long) inode;
data->task.tk_calldata = data;
data->task.tk_release = nfs_readdata_release;
data->complete = nfs_direct_read_result; data->complete = nfs_direct_read_result;
lock_kernel(); lock_kernel();
...@@ -433,7 +433,7 @@ static ssize_t nfs_direct_write_seg(struct inode *inode, ...@@ -433,7 +433,7 @@ static ssize_t nfs_direct_write_seg(struct inode *inode,
struct nfs_writeverf first_verf; struct nfs_writeverf first_verf;
struct nfs_write_data *wdata; struct nfs_write_data *wdata;
wdata = nfs_writedata_alloc(); wdata = nfs_writedata_alloc(NFS_SERVER(inode)->wpages);
if (!wdata) if (!wdata)
return -ENOMEM; return -ENOMEM;
...@@ -662,10 +662,10 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t ...@@ -662,10 +662,10 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t
.iov_len = count, .iov_len = count,
}; };
dprintk("nfs: direct read(%s/%s, %lu@%lu)\n", dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n",
file->f_dentry->d_parent->d_name.name, file->f_dentry->d_parent->d_name.name,
file->f_dentry->d_name.name, file->f_dentry->d_name.name,
(unsigned long) count, (unsigned long) pos); (unsigned long) count, (long long) pos);
if (!is_sync_kiocb(iocb)) if (!is_sync_kiocb(iocb))
goto out; goto out;
...@@ -718,9 +718,7 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t ...@@ -718,9 +718,7 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t
ssize_t ssize_t
nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
{ {
ssize_t retval = -EINVAL; ssize_t retval;
loff_t *ppos = &iocb->ki_pos;
unsigned long limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct nfs_open_context *ctx = struct nfs_open_context *ctx =
(struct nfs_open_context *) file->private_data; (struct nfs_open_context *) file->private_data;
...@@ -728,35 +726,32 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, ...@@ -728,35 +726,32 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count,
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
struct iovec iov = { struct iovec iov = {
.iov_base = (char __user *)buf, .iov_base = (char __user *)buf,
.iov_len = count,
}; };
dfprintk(VFS, "nfs: direct write(%s/%s(%ld), %lu@%lu)\n", dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n",
file->f_dentry->d_parent->d_name.name, file->f_dentry->d_parent->d_name.name,
file->f_dentry->d_name.name, inode->i_ino, file->f_dentry->d_name.name,
(unsigned long) count, (unsigned long) pos); (unsigned long) count, (long long) pos);
retval = -EINVAL;
if (!is_sync_kiocb(iocb)) if (!is_sync_kiocb(iocb))
goto out; goto out;
if (count < 0)
goto out; retval = generic_write_checks(file, &pos, &count, 0);
if (pos < 0) if (retval)
goto out; goto out;
retval = -EFAULT;
if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) retval = -EINVAL;
if ((ssize_t) count < 0)
goto out; goto out;
retval = -EFBIG;
if (limit != RLIM_INFINITY) {
if (pos >= limit) {
send_sig(SIGXFSZ, current, 0);
goto out;
}
if (count > limit - (unsigned long) pos)
count = limit - (unsigned long) pos;
}
retval = 0; retval = 0;
if (!count) if (!count)
goto out; goto out;
iov.iov_len = count,
retval = -EFAULT;
if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len))
goto out;
retval = nfs_sync_mapping(mapping); retval = nfs_sync_mapping(mapping);
if (retval) if (retval)
...@@ -766,7 +761,7 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, ...@@ -766,7 +761,7 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count,
if (mapping->nrpages) if (mapping->nrpages)
invalidate_inode_pages2(mapping); invalidate_inode_pages2(mapping);
if (retval > 0) if (retval > 0)
*ppos = pos + retval; iocb->ki_pos = pos + retval;
out: out:
return retval; return retval;
......
...@@ -54,7 +54,11 @@ ...@@ -54,7 +54,11 @@
#define IDMAP_HASH_SZ 128 #define IDMAP_HASH_SZ 128
/* Default cache timeout is 10 minutes */
unsigned int nfs_idmap_cache_timeout = 600 * HZ;
struct idmap_hashent { struct idmap_hashent {
unsigned long ih_expires;
__u32 ih_id; __u32 ih_id;
int ih_namelen; int ih_namelen;
char ih_name[IDMAP_NAMESZ]; char ih_name[IDMAP_NAMESZ];
...@@ -149,6 +153,8 @@ idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len) ...@@ -149,6 +153,8 @@ idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len)
if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0) if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0)
return NULL; return NULL;
if (time_after(jiffies, he->ih_expires))
return NULL;
return he; return he;
} }
...@@ -164,6 +170,8 @@ idmap_lookup_id(struct idmap_hashtable *h, __u32 id) ...@@ -164,6 +170,8 @@ idmap_lookup_id(struct idmap_hashtable *h, __u32 id)
struct idmap_hashent *he = idmap_id_hash(h, id); struct idmap_hashent *he = idmap_id_hash(h, id);
if (he->ih_id != id || he->ih_namelen == 0) if (he->ih_id != id || he->ih_namelen == 0)
return NULL; return NULL;
if (time_after(jiffies, he->ih_expires))
return NULL;
return he; return he;
} }
...@@ -192,6 +200,7 @@ idmap_update_entry(struct idmap_hashent *he, const char *name, ...@@ -192,6 +200,7 @@ idmap_update_entry(struct idmap_hashent *he, const char *name,
memcpy(he->ih_name, name, namelen); memcpy(he->ih_name, name, namelen);
he->ih_name[namelen] = '\0'; he->ih_name[namelen] = '\0';
he->ih_namelen = namelen; he->ih_namelen = namelen;
he->ih_expires = jiffies + nfs_idmap_cache_timeout;
} }
/* /*
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "nfs4_fs.h" #include "nfs4_fs.h"
#include "callback.h"
#include "delegation.h" #include "delegation.h"
#define NFSDBG_FACILITY NFSDBG_VFS #define NFSDBG_FACILITY NFSDBG_VFS
...@@ -221,10 +222,10 @@ nfs_calc_block_size(u64 tsize) ...@@ -221,10 +222,10 @@ nfs_calc_block_size(u64 tsize)
static inline unsigned long static inline unsigned long
nfs_block_size(unsigned long bsize, unsigned char *nrbitsp) nfs_block_size(unsigned long bsize, unsigned char *nrbitsp)
{ {
if (bsize < 1024) if (bsize < NFS_MIN_FILE_IO_SIZE)
bsize = NFS_DEF_FILE_IO_BUFFER_SIZE; bsize = NFS_DEF_FILE_IO_SIZE;
else if (bsize >= NFS_MAX_FILE_IO_BUFFER_SIZE) else if (bsize >= NFS_MAX_FILE_IO_SIZE)
bsize = NFS_MAX_FILE_IO_BUFFER_SIZE; bsize = NFS_MAX_FILE_IO_SIZE;
return nfs_block_bits(bsize, nrbitsp); return nfs_block_bits(bsize, nrbitsp);
} }
...@@ -307,20 +308,15 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) ...@@ -307,20 +308,15 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL); max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
if (server->rsize > max_rpc_payload) if (server->rsize > max_rpc_payload)
server->rsize = max_rpc_payload; server->rsize = max_rpc_payload;
if (server->wsize > max_rpc_payload) if (server->rsize > NFS_MAX_FILE_IO_SIZE)
server->wsize = max_rpc_payload; server->rsize = NFS_MAX_FILE_IO_SIZE;
server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
if (server->rpages > NFS_READ_MAXIOV) {
server->rpages = NFS_READ_MAXIOV;
server->rsize = server->rpages << PAGE_CACHE_SHIFT;
}
if (server->wsize > max_rpc_payload)
server->wsize = max_rpc_payload;
if (server->wsize > NFS_MAX_FILE_IO_SIZE)
server->wsize = NFS_MAX_FILE_IO_SIZE;
server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
if (server->wpages > NFS_WRITE_MAXIOV) {
server->wpages = NFS_WRITE_MAXIOV;
server->wsize = server->wpages << PAGE_CACHE_SHIFT;
}
if (sb->s_blocksize == 0) if (sb->s_blocksize == 0)
sb->s_blocksize = nfs_block_bits(server->wsize, sb->s_blocksize = nfs_block_bits(server->wsize,
...@@ -417,7 +413,6 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) ...@@ -417,7 +413,6 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data)
clnt->cl_intr = 1; clnt->cl_intr = 1;
clnt->cl_softrtry = 1; clnt->cl_softrtry = 1;
clnt->cl_chatty = 1;
return clnt; return clnt;
...@@ -575,11 +570,10 @@ nfs_statfs(struct super_block *sb, struct kstatfs *buf) ...@@ -575,11 +570,10 @@ nfs_statfs(struct super_block *sb, struct kstatfs *buf)
buf->f_namelen = server->namelen; buf->f_namelen = server->namelen;
out: out:
unlock_kernel(); unlock_kernel();
return 0; return 0;
out_err: out_err:
printk(KERN_WARNING "nfs_statfs: statfs error = %d\n", -error); dprintk("%s: statfs error = %d\n", __FUNCTION__, -error);
buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
goto out; goto out;
...@@ -958,6 +952,8 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) ...@@ -958,6 +952,8 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
int err; int err;
/* Flush out writes to the server in order to update c/mtime */
nfs_sync_inode(inode, 0, 0, FLUSH_WAIT|FLUSH_NOCOMMIT);
if (__IS_FLG(inode, MS_NOATIME)) if (__IS_FLG(inode, MS_NOATIME))
need_atime = 0; need_atime = 0;
else if (__IS_FLG(inode, MS_NODIRATIME) && S_ISDIR(inode->i_mode)) else if (__IS_FLG(inode, MS_NODIRATIME) && S_ISDIR(inode->i_mode))
...@@ -1252,6 +1248,33 @@ void nfs_end_data_update(struct inode *inode) ...@@ -1252,6 +1248,33 @@ void nfs_end_data_update(struct inode *inode)
atomic_dec(&nfsi->data_updates); atomic_dec(&nfsi->data_updates);
} }
static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{
struct nfs_inode *nfsi = NFS_I(inode);
if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0
&& nfsi->change_attr == fattr->pre_change_attr) {
nfsi->change_attr = fattr->change_attr;
nfsi->cache_change_attribute = jiffies;
}
/* If we have atomic WCC data, we may update some attributes */
if ((fattr->valid & NFS_ATTR_WCC) != 0) {
if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) {
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
nfsi->cache_change_attribute = jiffies;
}
if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
nfsi->cache_change_attribute = jiffies;
}
if (inode->i_size == fattr->pre_size && nfsi->npages == 0) {
inode->i_size = fattr->size;
nfsi->cache_change_attribute = jiffies;
}
}
}
/** /**
* nfs_check_inode_attributes - verify consistency of the inode attribute cache * nfs_check_inode_attributes - verify consistency of the inode attribute cache
* @inode - pointer to inode * @inode - pointer to inode
...@@ -1268,22 +1291,20 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat ...@@ -1268,22 +1291,20 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
int data_unstable; int data_unstable;
if ((fattr->valid & NFS_ATTR_FATTR) == 0)
return 0;
/* Are we in the process of updating data on the server? */ /* Are we in the process of updating data on the server? */
data_unstable = nfs_caches_unstable(inode); data_unstable = nfs_caches_unstable(inode);
if (fattr->valid & NFS_ATTR_FATTR_V4) { /* Do atomic weak cache consistency updates */
if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0 nfs_wcc_update_inode(inode, fattr);
&& nfsi->change_attr == fattr->pre_change_attr)
nfsi->change_attr = fattr->change_attr;
if (nfsi->change_attr != fattr->change_attr) {
nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
if (!data_unstable)
nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE;
}
}
if ((fattr->valid & NFS_ATTR_FATTR) == 0) { if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
return 0; nfsi->change_attr != fattr->change_attr) {
nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
if (!data_unstable)
nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE;
} }
/* Has the inode gone and changed behind our back? */ /* Has the inode gone and changed behind our back? */
...@@ -1295,14 +1316,6 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat ...@@ -1295,14 +1316,6 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
cur_size = i_size_read(inode); cur_size = i_size_read(inode);
new_isize = nfs_size_to_loff_t(fattr->size); new_isize = nfs_size_to_loff_t(fattr->size);
/* If we have atomic WCC data, we may update some attributes */
if ((fattr->valid & NFS_ATTR_WCC) != 0) {
if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime))
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
}
/* Verify a few of the more important attributes */ /* Verify a few of the more important attributes */
if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
nfsi->cache_validity |= NFS_INO_INVALID_ATTR; nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
...@@ -1410,14 +1423,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1410,14 +1423,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
if ((fattr->valid & NFS_ATTR_FATTR) == 0) if ((fattr->valid & NFS_ATTR_FATTR) == 0)
return 0; return 0;
if (nfsi->fileid != fattr->fileid) { if (nfsi->fileid != fattr->fileid)
printk(KERN_ERR "%s: inode number mismatch\n" goto out_fileid;
"expected (%s/0x%Lx), got (%s/0x%Lx)\n",
__FUNCTION__,
inode->i_sb->s_id, (long long)nfsi->fileid,
inode->i_sb->s_id, (long long)fattr->fileid);
goto out_err;
}
/* /*
* Make sure the inode's type hasn't changed. * Make sure the inode's type hasn't changed.
...@@ -1436,6 +1443,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1436,6 +1443,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
if (data_stable) if (data_stable)
nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME);
/* Do atomic weak cache consistency updates */
nfs_wcc_update_inode(inode, fattr);
/* Check if our cached file size is stale */ /* Check if our cached file size is stale */
new_isize = nfs_size_to_loff_t(fattr->size); new_isize = nfs_size_to_loff_t(fattr->size);
cur_isize = i_size_read(inode); cur_isize = i_size_read(inode);
...@@ -1539,6 +1549,13 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1539,6 +1549,13 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
*/ */
nfs_invalidate_inode(inode); nfs_invalidate_inode(inode);
return -ESTALE; return -ESTALE;
out_fileid:
printk(KERN_ERR "NFS: server %s error: fileid changed\n"
"fsid %s: expected fileid 0x%Lx, got 0x%Lx\n",
NFS_SERVER(inode)->hostname, inode->i_sb->s_id,
(long long)nfsi->fileid, (long long)fattr->fileid);
goto out_err;
} }
/* /*
...@@ -1820,25 +1837,10 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, ...@@ -1820,25 +1837,10 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
} }
clnt->cl_intr = 1; clnt->cl_intr = 1;
clnt->cl_softrtry = 1; clnt->cl_softrtry = 1;
clnt->cl_chatty = 1;
clp->cl_rpcclient = clnt; clp->cl_rpcclient = clnt;
clp->cl_cred = rpcauth_lookupcred(clnt->cl_auth, 0);
if (IS_ERR(clp->cl_cred)) {
up_write(&clp->cl_sem);
err = PTR_ERR(clp->cl_cred);
clp->cl_cred = NULL;
goto out_fail;
}
memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr)); memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
nfs_idmap_new(clp); nfs_idmap_new(clp);
} }
if (list_empty(&clp->cl_superblocks)) {
err = nfs4_init_client(clp);
if (err != 0) {
up_write(&clp->cl_sem);
goto out_fail;
}
}
list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks); list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
clnt = rpc_clone_client(clp->cl_rpcclient); clnt = rpc_clone_client(clp->cl_rpcclient);
if (!IS_ERR(clnt)) if (!IS_ERR(clnt))
...@@ -2033,6 +2035,35 @@ static struct file_system_type nfs4_fs_type = { ...@@ -2033,6 +2035,35 @@ static struct file_system_type nfs4_fs_type = {
.fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
}; };
static const int nfs_set_port_min = 0;
static const int nfs_set_port_max = 65535;
static int param_set_port(const char *val, struct kernel_param *kp)
{
char *endp;
int num = simple_strtol(val, &endp, 0);
if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max)
return -EINVAL;
*((int *)kp->arg) = num;
return 0;
}
module_param_call(callback_tcpport, param_set_port, param_get_int,
&nfs_callback_set_tcpport, 0644);
static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
{
char *endp;
int num = simple_strtol(val, &endp, 0);
int jif = num * HZ;
if (endp == val || *endp || num < 0 || jif < num)
return -EINVAL;
*((int *)kp->arg) = jif;
return 0;
}
module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
&nfs_idmap_cache_timeout, 0644);
#define nfs4_init_once(nfsi) \ #define nfs4_init_once(nfsi) \
do { \ do { \
INIT_LIST_HEAD(&(nfsi)->open_states); \ INIT_LIST_HEAD(&(nfsi)->open_states); \
...@@ -2040,8 +2071,25 @@ static struct file_system_type nfs4_fs_type = { ...@@ -2040,8 +2071,25 @@ static struct file_system_type nfs4_fs_type = {
nfsi->delegation_state = 0; \ nfsi->delegation_state = 0; \
init_rwsem(&nfsi->rwsem); \ init_rwsem(&nfsi->rwsem); \
} while(0) } while(0)
#define register_nfs4fs() register_filesystem(&nfs4_fs_type)
#define unregister_nfs4fs() unregister_filesystem(&nfs4_fs_type) static inline int register_nfs4fs(void)
{
int ret;
ret = nfs_register_sysctl();
if (ret != 0)
return ret;
ret = register_filesystem(&nfs4_fs_type);
if (ret != 0)
nfs_unregister_sysctl();
return ret;
}
static inline void unregister_nfs4fs(void)
{
unregister_filesystem(&nfs4_fs_type);
nfs_unregister_sysctl();
}
#else #else
#define nfs4_init_once(nfsi) \ #define nfs4_init_once(nfsi) \
do { } while (0) do { } while (0)
...@@ -2166,11 +2214,11 @@ static int __init init_nfs_fs(void) ...@@ -2166,11 +2214,11 @@ static int __init init_nfs_fs(void)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
rpc_proc_unregister("nfs"); rpc_proc_unregister("nfs");
#endif #endif
nfs_destroy_writepagecache();
#ifdef CONFIG_NFS_DIRECTIO #ifdef CONFIG_NFS_DIRECTIO
out0:
nfs_destroy_directcache(); nfs_destroy_directcache();
out0:
#endif #endif
nfs_destroy_writepagecache();
out1: out1:
nfs_destroy_readpagecache(); nfs_destroy_readpagecache();
out2: out2:
......
...@@ -82,7 +82,6 @@ mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, ...@@ -82,7 +82,6 @@ mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version,
RPC_AUTH_UNIX); RPC_AUTH_UNIX);
if (!IS_ERR(clnt)) { if (!IS_ERR(clnt)) {
clnt->cl_softrtry = 1; clnt->cl_softrtry = 1;
clnt->cl_chatty = 1;
clnt->cl_oneshot = 1; clnt->cl_oneshot = 1;
clnt->cl_intr = 1; clnt->cl_intr = 1;
} }
......
...@@ -146,23 +146,23 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr) ...@@ -146,23 +146,23 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
return p; return p;
} }
#define SATTR(p, attr, flag, field) \
*p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
static inline u32 * static inline u32 *
xdr_encode_sattr(u32 *p, struct iattr *attr) xdr_encode_sattr(u32 *p, struct iattr *attr)
{ {
SATTR(p, attr, ATTR_MODE, ia_mode); const u32 not_set = __constant_htonl(0xFFFFFFFF);
SATTR(p, attr, ATTR_UID, ia_uid);
SATTR(p, attr, ATTR_GID, ia_gid); *p++ = (attr->ia_valid & ATTR_MODE) ? htonl(attr->ia_mode) : not_set;
SATTR(p, attr, ATTR_SIZE, ia_size); *p++ = (attr->ia_valid & ATTR_UID) ? htonl(attr->ia_uid) : not_set;
*p++ = (attr->ia_valid & ATTR_GID) ? htonl(attr->ia_gid) : not_set;
*p++ = (attr->ia_valid & ATTR_SIZE) ? htonl(attr->ia_size) : not_set;
if (attr->ia_valid & ATTR_ATIME_SET) { if (attr->ia_valid & ATTR_ATIME_SET) {
p = xdr_encode_time(p, &attr->ia_atime); p = xdr_encode_time(p, &attr->ia_atime);
} else if (attr->ia_valid & ATTR_ATIME) { } else if (attr->ia_valid & ATTR_ATIME) {
p = xdr_encode_current_server_time(p, &attr->ia_atime); p = xdr_encode_current_server_time(p, &attr->ia_atime);
} else { } else {
*p++ = ~(u32) 0; *p++ = not_set;
*p++ = ~(u32) 0; *p++ = not_set;
} }
if (attr->ia_valid & ATTR_MTIME_SET) { if (attr->ia_valid & ATTR_MTIME_SET) {
...@@ -170,12 +170,11 @@ xdr_encode_sattr(u32 *p, struct iattr *attr) ...@@ -170,12 +170,11 @@ xdr_encode_sattr(u32 *p, struct iattr *attr)
} else if (attr->ia_valid & ATTR_MTIME) { } else if (attr->ia_valid & ATTR_MTIME) {
p = xdr_encode_current_server_time(p, &attr->ia_mtime); p = xdr_encode_current_server_time(p, &attr->ia_mtime);
} else { } else {
*p++ = ~(u32) 0; *p++ = not_set;
*p++ = ~(u32) 0; *p++ = not_set;
} }
return p; return p;
} }
#undef SATTR
/* /*
* NFS encode functions * NFS encode functions
......
...@@ -68,26 +68,38 @@ nfs3_async_handle_jukebox(struct rpc_task *task) ...@@ -68,26 +68,38 @@ nfs3_async_handle_jukebox(struct rpc_task *task)
return 1; return 1;
} }
/*
* Bare-bones access to getattr: this is for nfs_read_super.
*/
static int static int
nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle,
struct nfs_fsinfo *info) struct nfs_fsinfo *info)
{ {
int status; int status;
dprintk("%s: call fsinfo\n", __FUNCTION__); dprintk("%s: call fsinfo\n", __FUNCTION__);
nfs_fattr_init(info->fattr); nfs_fattr_init(info->fattr);
status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0); status = rpc_call(client, NFS3PROC_FSINFO, fhandle, info, 0);
dprintk("%s: reply fsinfo: %d\n", __FUNCTION__, status); dprintk("%s: reply fsinfo: %d\n", __FUNCTION__, status);
if (!(info->fattr->valid & NFS_ATTR_FATTR)) { if (!(info->fattr->valid & NFS_ATTR_FATTR)) {
status = rpc_call(server->client_sys, NFS3PROC_GETATTR, fhandle, info->fattr, 0); status = rpc_call(client, NFS3PROC_GETATTR, fhandle, info->fattr, 0);
dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); dprintk("%s: reply getattr: %d\n", __FUNCTION__, status);
} }
return status; return status;
} }
/*
* Bare-bones access to getattr: this is for nfs_read_super.
*/
static int
nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info)
{
int status;
status = do_proc_get_root(server->client, fhandle, info);
if (status && server->client_sys != server->client)
status = do_proc_get_root(server->client_sys, fhandle, info);
return status;
}
/* /*
* One function for each procedure in the NFS protocol. * One function for each procedure in the NFS protocol.
*/ */
...@@ -732,19 +744,23 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -732,19 +744,23 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int); extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
static void static void nfs3_read_done(struct rpc_task *task, void *calldata)
nfs3_read_done(struct rpc_task *task)
{ {
struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata; struct nfs_read_data *data = calldata;
if (nfs3_async_handle_jukebox(task)) if (nfs3_async_handle_jukebox(task))
return; return;
/* Call back common NFS readpage processing */ /* Call back common NFS readpage processing */
if (task->tk_status >= 0) if (task->tk_status >= 0)
nfs_refresh_inode(data->inode, &data->fattr); nfs_refresh_inode(data->inode, &data->fattr);
nfs_readpage_result(task); nfs_readpage_result(task, calldata);
} }
static const struct rpc_call_ops nfs3_read_ops = {
.rpc_call_done = nfs3_read_done,
.rpc_release = nfs_readdata_release,
};
static void static void
nfs3_proc_read_setup(struct nfs_read_data *data) nfs3_proc_read_setup(struct nfs_read_data *data)
{ {
...@@ -762,23 +778,26 @@ nfs3_proc_read_setup(struct nfs_read_data *data) ...@@ -762,23 +778,26 @@ nfs3_proc_read_setup(struct nfs_read_data *data)
flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
/* Finalize the task. */ /* Finalize the task. */
rpc_init_task(task, NFS_CLIENT(inode), nfs3_read_done, flags); rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs3_read_ops, data);
rpc_call_setup(task, &msg, 0); rpc_call_setup(task, &msg, 0);
} }
static void static void nfs3_write_done(struct rpc_task *task, void *calldata)
nfs3_write_done(struct rpc_task *task)
{ {
struct nfs_write_data *data; struct nfs_write_data *data = calldata;
if (nfs3_async_handle_jukebox(task)) if (nfs3_async_handle_jukebox(task))
return; return;
data = (struct nfs_write_data *)task->tk_calldata;
if (task->tk_status >= 0) if (task->tk_status >= 0)
nfs_post_op_update_inode(data->inode, data->res.fattr); nfs_post_op_update_inode(data->inode, data->res.fattr);
nfs_writeback_done(task); nfs_writeback_done(task, calldata);
} }
static const struct rpc_call_ops nfs3_write_ops = {
.rpc_call_done = nfs3_write_done,
.rpc_release = nfs_writedata_release,
};
static void static void
nfs3_proc_write_setup(struct nfs_write_data *data, int how) nfs3_proc_write_setup(struct nfs_write_data *data, int how)
{ {
...@@ -806,23 +825,26 @@ nfs3_proc_write_setup(struct nfs_write_data *data, int how) ...@@ -806,23 +825,26 @@ nfs3_proc_write_setup(struct nfs_write_data *data, int how)
flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
/* Finalize the task. */ /* Finalize the task. */
rpc_init_task(task, NFS_CLIENT(inode), nfs3_write_done, flags); rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs3_write_ops, data);
rpc_call_setup(task, &msg, 0); rpc_call_setup(task, &msg, 0);
} }
static void static void nfs3_commit_done(struct rpc_task *task, void *calldata)
nfs3_commit_done(struct rpc_task *task)
{ {
struct nfs_write_data *data; struct nfs_write_data *data = calldata;
if (nfs3_async_handle_jukebox(task)) if (nfs3_async_handle_jukebox(task))
return; return;
data = (struct nfs_write_data *)task->tk_calldata;
if (task->tk_status >= 0) if (task->tk_status >= 0)
nfs_post_op_update_inode(data->inode, data->res.fattr); nfs_post_op_update_inode(data->inode, data->res.fattr);
nfs_commit_done(task); nfs_commit_done(task, calldata);
} }
static const struct rpc_call_ops nfs3_commit_ops = {
.rpc_call_done = nfs3_commit_done,
.rpc_release = nfs_commit_release,
};
static void static void
nfs3_proc_commit_setup(struct nfs_write_data *data, int how) nfs3_proc_commit_setup(struct nfs_write_data *data, int how)
{ {
...@@ -840,7 +862,7 @@ nfs3_proc_commit_setup(struct nfs_write_data *data, int how) ...@@ -840,7 +862,7 @@ nfs3_proc_commit_setup(struct nfs_write_data *data, int how)
flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
/* Finalize the task. */ /* Finalize the task. */
rpc_init_task(task, NFS_CLIENT(inode), nfs3_commit_done, flags); rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs3_commit_ops, data);
rpc_call_setup(task, &msg, 0); rpc_call_setup(task, &msg, 0);
} }
......
...@@ -182,7 +182,7 @@ xdr_encode_sattr(u32 *p, struct iattr *attr) ...@@ -182,7 +182,7 @@ xdr_encode_sattr(u32 *p, struct iattr *attr)
{ {
if (attr->ia_valid & ATTR_MODE) { if (attr->ia_valid & ATTR_MODE) {
*p++ = xdr_one; *p++ = xdr_one;
*p++ = htonl(attr->ia_mode); *p++ = htonl(attr->ia_mode & S_IALLUGO);
} else { } else {
*p++ = xdr_zero; *p++ = xdr_zero;
} }
......
...@@ -38,7 +38,8 @@ struct idmap; ...@@ -38,7 +38,8 @@ struct idmap;
((err) != NFSERR_NOFILEHANDLE)) ((err) != NFSERR_NOFILEHANDLE))
enum nfs4_client_state { enum nfs4_client_state {
NFS4CLNT_OK = 0, NFS4CLNT_STATE_RECOVER = 0,
NFS4CLNT_LEASE_EXPIRED,
}; };
/* /*
...@@ -67,7 +68,6 @@ struct nfs4_client { ...@@ -67,7 +68,6 @@ struct nfs4_client {
atomic_t cl_count; atomic_t cl_count;
struct rpc_clnt * cl_rpcclient; struct rpc_clnt * cl_rpcclient;
struct rpc_cred * cl_cred;
struct list_head cl_superblocks; /* List of nfs_server structs */ struct list_head cl_superblocks; /* List of nfs_server structs */
...@@ -76,7 +76,6 @@ struct nfs4_client { ...@@ -76,7 +76,6 @@ struct nfs4_client {
struct work_struct cl_renewd; struct work_struct cl_renewd;
struct work_struct cl_recoverd; struct work_struct cl_recoverd;
wait_queue_head_t cl_waitq;
struct rpc_wait_queue cl_rpcwaitq; struct rpc_wait_queue cl_rpcwaitq;
/* used for the setclientid verifier */ /* used for the setclientid verifier */
...@@ -182,8 +181,9 @@ struct nfs4_state { ...@@ -182,8 +181,9 @@ struct nfs4_state {
nfs4_stateid stateid; nfs4_stateid stateid;
unsigned int nreaders; unsigned int n_rdonly;
unsigned int nwriters; unsigned int n_wronly;
unsigned int n_rdwr;
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;
}; };
...@@ -210,10 +210,10 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t); ...@@ -210,10 +210,10 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t);
/* nfs4proc.c */ /* nfs4proc.c */
extern int nfs4_map_errors(int err); extern int nfs4_map_errors(int err);
extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short); extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short, struct rpc_cred *);
extern int nfs4_proc_setclientid_confirm(struct nfs4_client *); extern int nfs4_proc_setclientid_confirm(struct nfs4_client *, struct rpc_cred *);
extern int nfs4_proc_async_renew(struct nfs4_client *); extern int nfs4_proc_async_renew(struct nfs4_client *, struct rpc_cred *);
extern int nfs4_proc_renew(struct nfs4_client *); extern int nfs4_proc_renew(struct nfs4_client *, struct rpc_cred *);
extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state); extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state);
extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
...@@ -237,8 +237,8 @@ extern void init_nfsv4_state(struct nfs_server *); ...@@ -237,8 +237,8 @@ extern void init_nfsv4_state(struct nfs_server *);
extern void destroy_nfsv4_state(struct nfs_server *); extern void destroy_nfsv4_state(struct nfs_server *);
extern struct nfs4_client *nfs4_get_client(struct in_addr *); extern struct nfs4_client *nfs4_get_client(struct in_addr *);
extern void nfs4_put_client(struct nfs4_client *clp); extern void nfs4_put_client(struct nfs4_client *clp);
extern int nfs4_init_client(struct nfs4_client *clp);
extern struct nfs4_client *nfs4_find_client(struct in_addr *); extern struct nfs4_client *nfs4_find_client(struct in_addr *);
struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp);
extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *); extern u32 nfs4_alloc_lockowner_id(struct nfs4_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 *);
......
此差异已折叠。
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#include <linux/nfs4.h> #include <linux/nfs4.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include "nfs4_fs.h" #include "nfs4_fs.h"
#include "delegation.h"
#define NFSDBG_FACILITY NFSDBG_PROC #define NFSDBG_FACILITY NFSDBG_PROC
...@@ -61,6 +62,7 @@ void ...@@ -61,6 +62,7 @@ void
nfs4_renew_state(void *data) nfs4_renew_state(void *data)
{ {
struct nfs4_client *clp = (struct nfs4_client *)data; struct nfs4_client *clp = (struct nfs4_client *)data;
struct rpc_cred *cred;
long lease, timeout; long lease, timeout;
unsigned long last, now; unsigned long last, now;
...@@ -68,7 +70,7 @@ nfs4_renew_state(void *data) ...@@ -68,7 +70,7 @@ nfs4_renew_state(void *data)
dprintk("%s: start\n", __FUNCTION__); dprintk("%s: start\n", __FUNCTION__);
/* Are there any active superblocks? */ /* Are there any active superblocks? */
if (list_empty(&clp->cl_superblocks)) if (list_empty(&clp->cl_superblocks))
goto out; goto out;
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
lease = clp->cl_lease_time; lease = clp->cl_lease_time;
last = clp->cl_last_renewal; last = clp->cl_last_renewal;
...@@ -76,9 +78,17 @@ nfs4_renew_state(void *data) ...@@ -76,9 +78,17 @@ nfs4_renew_state(void *data)
timeout = (2 * lease) / 3 + (long)last - (long)now; timeout = (2 * lease) / 3 + (long)last - (long)now;
/* Are we close to a lease timeout? */ /* Are we close to a lease timeout? */
if (time_after(now, last + lease/3)) { if (time_after(now, last + lease/3)) {
cred = nfs4_get_renew_cred(clp);
if (cred == NULL) {
set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
spin_unlock(&clp->cl_lock);
nfs_expire_all_delegations(clp);
goto out;
}
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
/* Queue an asynchronous RENEW. */ /* Queue an asynchronous RENEW. */
nfs4_proc_async_renew(clp); nfs4_proc_async_renew(clp, cred);
put_rpccred(cred);
timeout = (2 * lease) / 3; timeout = (2 * lease) / 3;
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
} else } else
......
...@@ -43,6 +43,8 @@ ...@@ -43,6 +43,8 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfs_idmap.h> #include <linux/nfs_idmap.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/bitops.h> #include <linux/bitops.h>
...@@ -57,8 +59,6 @@ const nfs4_stateid zero_stateid; ...@@ -57,8 +59,6 @@ const nfs4_stateid zero_stateid;
static DEFINE_SPINLOCK(state_spinlock); static DEFINE_SPINLOCK(state_spinlock);
static LIST_HEAD(nfs4_clientid_list); static LIST_HEAD(nfs4_clientid_list);
static void nfs4_recover_state(void *);
void void
init_nfsv4_state(struct nfs_server *server) init_nfsv4_state(struct nfs_server *server)
{ {
...@@ -91,11 +91,10 @@ nfs4_alloc_client(struct in_addr *addr) ...@@ -91,11 +91,10 @@ nfs4_alloc_client(struct in_addr *addr)
if (nfs_callback_up() < 0) if (nfs_callback_up() < 0)
return NULL; return NULL;
if ((clp = kmalloc(sizeof(*clp), GFP_KERNEL)) == NULL) { if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) {
nfs_callback_down(); nfs_callback_down();
return NULL; return NULL;
} }
memset(clp, 0, sizeof(*clp));
memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr)); memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr));
init_rwsem(&clp->cl_sem); init_rwsem(&clp->cl_sem);
INIT_LIST_HEAD(&clp->cl_delegations); INIT_LIST_HEAD(&clp->cl_delegations);
...@@ -103,14 +102,12 @@ nfs4_alloc_client(struct in_addr *addr) ...@@ -103,14 +102,12 @@ nfs4_alloc_client(struct in_addr *addr)
INIT_LIST_HEAD(&clp->cl_unused); INIT_LIST_HEAD(&clp->cl_unused);
spin_lock_init(&clp->cl_lock); spin_lock_init(&clp->cl_lock);
atomic_set(&clp->cl_count, 1); atomic_set(&clp->cl_count, 1);
INIT_WORK(&clp->cl_recoverd, nfs4_recover_state, clp);
INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp); INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
INIT_LIST_HEAD(&clp->cl_superblocks); INIT_LIST_HEAD(&clp->cl_superblocks);
init_waitqueue_head(&clp->cl_waitq);
rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client");
clp->cl_rpcclient = ERR_PTR(-EINVAL); clp->cl_rpcclient = ERR_PTR(-EINVAL);
clp->cl_boot_time = CURRENT_TIME; clp->cl_boot_time = CURRENT_TIME;
clp->cl_state = 1 << NFS4CLNT_OK; clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
return clp; return clp;
} }
...@@ -127,8 +124,6 @@ nfs4_free_client(struct nfs4_client *clp) ...@@ -127,8 +124,6 @@ nfs4_free_client(struct nfs4_client *clp)
kfree(sp); kfree(sp);
} }
BUG_ON(!list_empty(&clp->cl_state_owners)); BUG_ON(!list_empty(&clp->cl_state_owners));
if (clp->cl_cred)
put_rpccred(clp->cl_cred);
nfs_idmap_delete(clp); nfs_idmap_delete(clp);
if (!IS_ERR(clp->cl_rpcclient)) if (!IS_ERR(clp->cl_rpcclient))
rpc_shutdown_client(clp->cl_rpcclient); rpc_shutdown_client(clp->cl_rpcclient);
...@@ -193,27 +188,22 @@ nfs4_put_client(struct nfs4_client *clp) ...@@ -193,27 +188,22 @@ nfs4_put_client(struct nfs4_client *clp)
list_del(&clp->cl_servers); list_del(&clp->cl_servers);
spin_unlock(&state_spinlock); spin_unlock(&state_spinlock);
BUG_ON(!list_empty(&clp->cl_superblocks)); BUG_ON(!list_empty(&clp->cl_superblocks));
wake_up_all(&clp->cl_waitq);
rpc_wake_up(&clp->cl_rpcwaitq); rpc_wake_up(&clp->cl_rpcwaitq);
nfs4_kill_renewd(clp); nfs4_kill_renewd(clp);
nfs4_free_client(clp); nfs4_free_client(clp);
} }
static int __nfs4_init_client(struct nfs4_client *clp) static int nfs4_init_client(struct nfs4_client *clp, struct rpc_cred *cred)
{ {
int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, nfs_callback_tcpport); int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK,
nfs_callback_tcpport, cred);
if (status == 0) if (status == 0)
status = nfs4_proc_setclientid_confirm(clp); status = nfs4_proc_setclientid_confirm(clp, cred);
if (status == 0) if (status == 0)
nfs4_schedule_state_renewal(clp); nfs4_schedule_state_renewal(clp);
return status; return status;
} }
int nfs4_init_client(struct nfs4_client *clp)
{
return nfs4_map_errors(__nfs4_init_client(clp));
}
u32 u32
nfs4_alloc_lockowner_id(struct nfs4_client *clp) nfs4_alloc_lockowner_id(struct nfs4_client *clp)
{ {
...@@ -235,6 +225,32 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred) ...@@ -235,6 +225,32 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred)
return sp; return sp;
} }
struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp)
{
struct nfs4_state_owner *sp;
struct rpc_cred *cred = NULL;
list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
if (list_empty(&sp->so_states))
continue;
cred = get_rpccred(sp->so_cred);
break;
}
return cred;
}
struct rpc_cred *nfs4_get_setclientid_cred(struct nfs4_client *clp)
{
struct nfs4_state_owner *sp;
if (!list_empty(&clp->cl_state_owners)) {
sp = list_entry(clp->cl_state_owners.next,
struct nfs4_state_owner, so_list);
return get_rpccred(sp->so_cred);
}
return NULL;
}
static struct nfs4_state_owner * static struct nfs4_state_owner *
nfs4_find_state_owner(struct nfs4_client *clp, struct rpc_cred *cred) nfs4_find_state_owner(struct nfs4_client *clp, struct rpc_cred *cred)
{ {
...@@ -349,14 +365,9 @@ nfs4_alloc_open_state(void) ...@@ -349,14 +365,9 @@ nfs4_alloc_open_state(void)
{ {
struct nfs4_state *state; struct nfs4_state *state;
state = kmalloc(sizeof(*state), GFP_KERNEL); state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state) if (!state)
return NULL; return NULL;
state->state = 0;
state->nreaders = 0;
state->nwriters = 0;
state->flags = 0;
memset(state->stateid.data, 0, sizeof(state->stateid.data));
atomic_set(&state->count, 1); atomic_set(&state->count, 1);
INIT_LIST_HEAD(&state->lock_states); INIT_LIST_HEAD(&state->lock_states);
spin_lock_init(&state->state_lock); spin_lock_init(&state->state_lock);
...@@ -475,15 +486,23 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode) ...@@ -475,15 +486,23 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode)
/* Protect against nfs4_find_state() */ /* Protect against nfs4_find_state() */
spin_lock(&owner->so_lock); spin_lock(&owner->so_lock);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
if (mode & FMODE_READ) switch (mode & (FMODE_READ | FMODE_WRITE)) {
state->nreaders--; case FMODE_READ:
if (mode & FMODE_WRITE) state->n_rdonly--;
state->nwriters--; break;
case FMODE_WRITE:
state->n_wronly--;
break;
case FMODE_READ|FMODE_WRITE:
state->n_rdwr--;
}
oldstate = newstate = state->state; oldstate = newstate = state->state;
if (state->nreaders == 0) if (state->n_rdwr == 0) {
newstate &= ~FMODE_READ; if (state->n_rdonly == 0)
if (state->nwriters == 0) newstate &= ~FMODE_READ;
newstate &= ~FMODE_WRITE; if (state->n_wronly == 0)
newstate &= ~FMODE_WRITE;
}
if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
nfs4_state_set_mode_locked(state, newstate); nfs4_state_set_mode_locked(state, newstate);
oldstate = newstate; oldstate = newstate;
...@@ -733,45 +752,43 @@ int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) ...@@ -733,45 +752,43 @@ int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
} }
static int reclaimer(void *); static int reclaimer(void *);
struct reclaimer_args {
struct nfs4_client *clp; static inline void nfs4_clear_recover_bit(struct nfs4_client *clp)
struct completion complete; {
}; smp_mb__before_clear_bit();
clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state);
smp_mb__after_clear_bit();
wake_up_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER);
rpc_wake_up(&clp->cl_rpcwaitq);
}
/* /*
* State recovery routine * State recovery routine
*/ */
void static void nfs4_recover_state(struct nfs4_client *clp)
nfs4_recover_state(void *data)
{ {
struct nfs4_client *clp = (struct nfs4_client *)data; struct task_struct *task;
struct reclaimer_args args = {
.clp = clp,
};
might_sleep();
init_completion(&args.complete);
if (kernel_thread(reclaimer, &args, CLONE_KERNEL) < 0) __module_get(THIS_MODULE);
goto out_failed_clear; atomic_inc(&clp->cl_count);
wait_for_completion(&args.complete); task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim",
return; NIPQUAD(clp->cl_addr));
out_failed_clear: if (!IS_ERR(task))
set_bit(NFS4CLNT_OK, &clp->cl_state); return;
wake_up_all(&clp->cl_waitq); nfs4_clear_recover_bit(clp);
rpc_wake_up(&clp->cl_rpcwaitq); nfs4_put_client(clp);
module_put(THIS_MODULE);
} }
/* /*
* Schedule a state recovery attempt * Schedule a state recovery attempt
*/ */
void void nfs4_schedule_state_recovery(struct nfs4_client *clp)
nfs4_schedule_state_recovery(struct nfs4_client *clp)
{ {
if (!clp) if (!clp)
return; return;
if (test_and_clear_bit(NFS4CLNT_OK, &clp->cl_state)) if (test_and_set_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0)
schedule_work(&clp->cl_recoverd); nfs4_recover_state(clp);
} }
static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_state *state) static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_state *state)
...@@ -887,18 +904,14 @@ static void nfs4_state_mark_reclaim(struct nfs4_client *clp) ...@@ -887,18 +904,14 @@ static void nfs4_state_mark_reclaim(struct nfs4_client *clp)
static int reclaimer(void *ptr) static int reclaimer(void *ptr)
{ {
struct reclaimer_args *args = (struct reclaimer_args *)ptr; struct nfs4_client *clp = ptr;
struct nfs4_client *clp = args->clp;
struct nfs4_state_owner *sp; struct nfs4_state_owner *sp;
struct nfs4_state_recovery_ops *ops; struct nfs4_state_recovery_ops *ops;
struct rpc_cred *cred;
int status = 0; int status = 0;
daemonize("%u.%u.%u.%u-reclaim", NIPQUAD(clp->cl_addr));
allow_signal(SIGKILL); allow_signal(SIGKILL);
atomic_inc(&clp->cl_count);
complete(&args->complete);
/* Ensure exclusive access to NFSv4 state */ /* Ensure exclusive access to NFSv4 state */
lock_kernel(); lock_kernel();
down_write(&clp->cl_sem); down_write(&clp->cl_sem);
...@@ -906,20 +919,33 @@ static int reclaimer(void *ptr) ...@@ -906,20 +919,33 @@ static int reclaimer(void *ptr)
if (list_empty(&clp->cl_superblocks)) if (list_empty(&clp->cl_superblocks))
goto out; goto out;
restart_loop: restart_loop:
status = nfs4_proc_renew(clp); ops = &nfs4_network_partition_recovery_ops;
switch (status) { /* Are there any open files on this volume? */
case 0: cred = nfs4_get_renew_cred(clp);
case -NFS4ERR_CB_PATH_DOWN: if (cred != NULL) {
goto out; /* Yes there are: try to renew the old lease */
case -NFS4ERR_STALE_CLIENTID: status = nfs4_proc_renew(clp, cred);
case -NFS4ERR_LEASE_MOVED: switch (status) {
ops = &nfs4_reboot_recovery_ops; case 0:
break; case -NFS4ERR_CB_PATH_DOWN:
default: put_rpccred(cred);
ops = &nfs4_network_partition_recovery_ops; goto out;
}; case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_LEASE_MOVED:
ops = &nfs4_reboot_recovery_ops;
}
} else {
/* "reboot" to ensure we clear all state on the server */
clp->cl_boot_time = CURRENT_TIME;
cred = nfs4_get_setclientid_cred(clp);
}
/* We're going to have to re-establish a clientid */
nfs4_state_mark_reclaim(clp); nfs4_state_mark_reclaim(clp);
status = __nfs4_init_client(clp); status = -ENOENT;
if (cred != NULL) {
status = nfs4_init_client(clp, cred);
put_rpccred(cred);
}
if (status) if (status)
goto out_error; goto out_error;
/* Mark all delegations for reclaim */ /* Mark all delegations for reclaim */
...@@ -940,14 +966,13 @@ static int reclaimer(void *ptr) ...@@ -940,14 +966,13 @@ static int reclaimer(void *ptr)
} }
nfs_delegation_reap_unclaimed(clp); nfs_delegation_reap_unclaimed(clp);
out: out:
set_bit(NFS4CLNT_OK, &clp->cl_state);
up_write(&clp->cl_sem); up_write(&clp->cl_sem);
unlock_kernel(); unlock_kernel();
wake_up_all(&clp->cl_waitq);
rpc_wake_up(&clp->cl_rpcwaitq);
if (status == -NFS4ERR_CB_PATH_DOWN) if (status == -NFS4ERR_CB_PATH_DOWN)
nfs_handle_cb_pathdown(clp); nfs_handle_cb_pathdown(clp);
nfs4_clear_recover_bit(clp);
nfs4_put_client(clp); nfs4_put_client(clp);
module_put_and_exit(0);
return 0; return 0;
out_error: out_error:
printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n",
......
...@@ -392,9 +392,11 @@ static int nfs_stat_to_errno(int); ...@@ -392,9 +392,11 @@ static int nfs_stat_to_errno(int);
decode_getattr_maxsz) decode_getattr_maxsz)
#define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \ encode_putfh_maxsz + \
encode_delegreturn_maxsz) encode_delegreturn_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
decode_delegreturn_maxsz) decode_delegreturn_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \ encode_putfh_maxsz + \
encode_getattr_maxsz) encode_getattr_maxsz)
...@@ -564,7 +566,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s ...@@ -564,7 +566,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
} }
if (iap->ia_valid & ATTR_MODE) { if (iap->ia_valid & ATTR_MODE) {
bmval1 |= FATTR4_WORD1_MODE; bmval1 |= FATTR4_WORD1_MODE;
WRITE32(iap->ia_mode); WRITE32(iap->ia_mode & S_IALLUGO);
} }
if (iap->ia_valid & ATTR_UID) { if (iap->ia_valid & ATTR_UID) {
bmval1 |= FATTR4_WORD1_OWNER; bmval1 |= FATTR4_WORD1_OWNER;
...@@ -742,69 +744,80 @@ static int encode_link(struct xdr_stream *xdr, const struct qstr *name) ...@@ -742,69 +744,80 @@ static int encode_link(struct xdr_stream *xdr, const struct qstr *name)
return 0; return 0;
} }
static inline int nfs4_lock_type(struct file_lock *fl, int block)
{
if ((fl->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) == F_RDLCK)
return block ? NFS4_READW_LT : NFS4_READ_LT;
return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT;
}
static inline uint64_t nfs4_lock_length(struct file_lock *fl)
{
if (fl->fl_end == OFFSET_MAX)
return ~(uint64_t)0;
return fl->fl_end - fl->fl_start + 1;
}
/* /*
* opcode,type,reclaim,offset,length,new_lock_owner = 32 * opcode,type,reclaim,offset,length,new_lock_owner = 32
* open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40 * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
*/ */
static int encode_lock(struct xdr_stream *xdr, const struct nfs_lockargs *arg) static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args)
{ {
uint32_t *p; uint32_t *p;
struct nfs_lock_opargs *opargs = arg->u.lock;
RESERVE_SPACE(32); RESERVE_SPACE(32);
WRITE32(OP_LOCK); WRITE32(OP_LOCK);
WRITE32(arg->type); WRITE32(nfs4_lock_type(args->fl, args->block));
WRITE32(opargs->reclaim); WRITE32(args->reclaim);
WRITE64(arg->offset); WRITE64(args->fl->fl_start);
WRITE64(arg->length); WRITE64(nfs4_lock_length(args->fl));
WRITE32(opargs->new_lock_owner); WRITE32(args->new_lock_owner);
if (opargs->new_lock_owner){ if (args->new_lock_owner){
RESERVE_SPACE(40); RESERVE_SPACE(40);
WRITE32(opargs->open_seqid->sequence->counter); WRITE32(args->open_seqid->sequence->counter);
WRITEMEM(opargs->open_stateid->data, sizeof(opargs->open_stateid->data)); WRITEMEM(args->open_stateid->data, sizeof(args->open_stateid->data));
WRITE32(opargs->lock_seqid->sequence->counter); WRITE32(args->lock_seqid->sequence->counter);
WRITE64(opargs->lock_owner.clientid); WRITE64(args->lock_owner.clientid);
WRITE32(4); WRITE32(4);
WRITE32(opargs->lock_owner.id); WRITE32(args->lock_owner.id);
} }
else { else {
RESERVE_SPACE(20); RESERVE_SPACE(20);
WRITEMEM(opargs->lock_stateid->data, sizeof(opargs->lock_stateid->data)); WRITEMEM(args->lock_stateid->data, sizeof(args->lock_stateid->data));
WRITE32(opargs->lock_seqid->sequence->counter); WRITE32(args->lock_seqid->sequence->counter);
} }
return 0; return 0;
} }
static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockargs *arg) static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args)
{ {
uint32_t *p; uint32_t *p;
struct nfs_lowner *opargs = arg->u.lockt;
RESERVE_SPACE(40); RESERVE_SPACE(40);
WRITE32(OP_LOCKT); WRITE32(OP_LOCKT);
WRITE32(arg->type); WRITE32(nfs4_lock_type(args->fl, 0));
WRITE64(arg->offset); WRITE64(args->fl->fl_start);
WRITE64(arg->length); WRITE64(nfs4_lock_length(args->fl));
WRITE64(opargs->clientid); WRITE64(args->lock_owner.clientid);
WRITE32(4); WRITE32(4);
WRITE32(opargs->id); WRITE32(args->lock_owner.id);
return 0; return 0;
} }
static int encode_locku(struct xdr_stream *xdr, const struct nfs_lockargs *arg) static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args)
{ {
uint32_t *p; uint32_t *p;
struct nfs_locku_opargs *opargs = arg->u.locku;
RESERVE_SPACE(44); RESERVE_SPACE(44);
WRITE32(OP_LOCKU); WRITE32(OP_LOCKU);
WRITE32(arg->type); WRITE32(nfs4_lock_type(args->fl, 0));
WRITE32(opargs->seqid->sequence->counter); WRITE32(args->seqid->sequence->counter);
WRITEMEM(opargs->stateid->data, sizeof(opargs->stateid->data)); WRITEMEM(args->stateid->data, sizeof(args->stateid->data));
WRITE64(arg->offset); WRITE64(args->fl->fl_start);
WRITE64(arg->length); WRITE64(nfs4_lock_length(args->fl));
return 0; return 0;
} }
...@@ -964,9 +977,9 @@ static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_con ...@@ -964,9 +977,9 @@ static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_con
{ {
uint32_t *p; uint32_t *p;
RESERVE_SPACE(8+sizeof(arg->stateid.data)); RESERVE_SPACE(8+sizeof(arg->stateid->data));
WRITE32(OP_OPEN_CONFIRM); WRITE32(OP_OPEN_CONFIRM);
WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data)); WRITEMEM(arg->stateid->data, sizeof(arg->stateid->data));
WRITE32(arg->seqid->sequence->counter); WRITE32(arg->seqid->sequence->counter);
return 0; return 0;
...@@ -1499,9 +1512,6 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_opena ...@@ -1499,9 +1512,6 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_opena
}; };
int status; int status;
status = nfs_wait_on_sequence(args->seqid, req->rq_task);
if (status != 0)
goto out;
xdr_init_encode(&xdr, &req->rq_snd_buf, p); xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr); encode_compound_hdr(&xdr, &hdr);
status = encode_putfh(&xdr, args->fh); status = encode_putfh(&xdr, args->fh);
...@@ -1538,9 +1548,6 @@ static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct n ...@@ -1538,9 +1548,6 @@ static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct n
}; };
int status; int status;
status = nfs_wait_on_sequence(args->seqid, req->rq_task);
if (status != 0)
goto out;
xdr_init_encode(&xdr, &req->rq_snd_buf, p); xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr); encode_compound_hdr(&xdr, &hdr);
status = encode_putfh(&xdr, args->fh); status = encode_putfh(&xdr, args->fh);
...@@ -1558,19 +1565,19 @@ static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, uint32_t *p, struct nf ...@@ -1558,19 +1565,19 @@ static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, uint32_t *p, struct nf
{ {
struct xdr_stream xdr; struct xdr_stream xdr;
struct compound_hdr hdr = { struct compound_hdr hdr = {
.nops = 2, .nops = 3,
}; };
int status; int status;
status = nfs_wait_on_sequence(args->seqid, req->rq_task);
if (status != 0)
goto out;
xdr_init_encode(&xdr, &req->rq_snd_buf, p); xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr); encode_compound_hdr(&xdr, &hdr);
status = encode_putfh(&xdr, args->fh); status = encode_putfh(&xdr, args->fh);
if (status) if (status)
goto out; goto out;
status = encode_open(&xdr, args); status = encode_open(&xdr, args);
if (status)
goto out;
status = encode_getfattr(&xdr, args->bitmask);
out: out:
return status; return status;
} }
...@@ -1602,21 +1609,14 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct ...@@ -1602,21 +1609,14 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct
/* /*
* Encode a LOCK request * Encode a LOCK request
*/ */
static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lock_args *args)
{ {
struct xdr_stream xdr; struct xdr_stream xdr;
struct compound_hdr hdr = { struct compound_hdr hdr = {
.nops = 2, .nops = 2,
}; };
struct nfs_lock_opargs *opargs = args->u.lock;
int status; int status;
status = nfs_wait_on_sequence(opargs->lock_seqid, req->rq_task);
if (status != 0)
goto out;
/* Do we need to do an open_to_lock_owner? */
if (opargs->lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)
opargs->new_lock_owner = 0;
xdr_init_encode(&xdr, &req->rq_snd_buf, p); xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr); encode_compound_hdr(&xdr, &hdr);
status = encode_putfh(&xdr, args->fh); status = encode_putfh(&xdr, args->fh);
...@@ -1630,7 +1630,7 @@ static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_locka ...@@ -1630,7 +1630,7 @@ static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_locka
/* /*
* Encode a LOCKT request * Encode a LOCKT request
*/ */
static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockt_args *args)
{ {
struct xdr_stream xdr; struct xdr_stream xdr;
struct compound_hdr hdr = { struct compound_hdr hdr = {
...@@ -1651,7 +1651,7 @@ static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lock ...@@ -1651,7 +1651,7 @@ static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lock
/* /*
* Encode a LOCKU request * Encode a LOCKU request
*/ */
static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args) static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_locku_args *args)
{ {
struct xdr_stream xdr; struct xdr_stream xdr;
struct compound_hdr hdr = { struct compound_hdr hdr = {
...@@ -1985,14 +1985,20 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, uint32_t *p, const str ...@@ -1985,14 +1985,20 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, uint32_t *p, const str
{ {
struct xdr_stream xdr; struct xdr_stream xdr;
struct compound_hdr hdr = { struct compound_hdr hdr = {
.nops = 2, .nops = 3,
}; };
int status; int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p); xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr); encode_compound_hdr(&xdr, &hdr);
if ((status = encode_putfh(&xdr, args->fhandle)) == 0) status = encode_putfh(&xdr, args->fhandle);
status = encode_delegreturn(&xdr, args->stateid); if (status != 0)
goto out;
status = encode_delegreturn(&xdr, args->stateid);
if (status != 0)
goto out;
status = encode_getfattr(&xdr, args->bitmask);
out:
return status; return status;
} }
...@@ -2955,55 +2961,64 @@ static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) ...@@ -2955,55 +2961,64 @@ static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
/* /*
* We create the owner, so we know a proper owner.id length is 4. * We create the owner, so we know a proper owner.id length is 4.
*/ */
static int decode_lock_denied (struct xdr_stream *xdr, struct nfs_lock_denied *denied) static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
{ {
uint64_t offset, length, clientid;
uint32_t *p; uint32_t *p;
uint32_t namelen; uint32_t namelen, type;
READ_BUF(32); READ_BUF(32);
READ64(denied->offset); READ64(offset);
READ64(denied->length); READ64(length);
READ32(denied->type); READ32(type);
READ64(denied->owner.clientid); if (fl != NULL) {
fl->fl_start = (loff_t)offset;
fl->fl_end = fl->fl_start + (loff_t)length - 1;
if (length == ~(uint64_t)0)
fl->fl_end = OFFSET_MAX;
fl->fl_type = F_WRLCK;
if (type & 1)
fl->fl_type = F_RDLCK;
fl->fl_pid = 0;
}
READ64(clientid);
READ32(namelen); READ32(namelen);
READ_BUF(namelen); READ_BUF(namelen);
if (namelen == 4)
READ32(denied->owner.id);
return -NFS4ERR_DENIED; return -NFS4ERR_DENIED;
} }
static int decode_lock(struct xdr_stream *xdr, struct nfs_lockres *res) static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
{ {
uint32_t *p; uint32_t *p;
int status; int status;
status = decode_op_hdr(xdr, OP_LOCK); status = decode_op_hdr(xdr, OP_LOCK);
if (status == 0) { if (status == 0) {
READ_BUF(sizeof(res->u.stateid.data)); READ_BUF(sizeof(res->stateid.data));
COPYMEM(res->u.stateid.data, sizeof(res->u.stateid.data)); COPYMEM(res->stateid.data, sizeof(res->stateid.data));
} else if (status == -NFS4ERR_DENIED) } else if (status == -NFS4ERR_DENIED)
return decode_lock_denied(xdr, &res->u.denied); return decode_lock_denied(xdr, NULL);
return status; return status;
} }
static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockres *res) static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res)
{ {
int status; int status;
status = decode_op_hdr(xdr, OP_LOCKT); status = decode_op_hdr(xdr, OP_LOCKT);
if (status == -NFS4ERR_DENIED) if (status == -NFS4ERR_DENIED)
return decode_lock_denied(xdr, &res->u.denied); return decode_lock_denied(xdr, res->denied);
return status; return status;
} }
static int decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res) static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
{ {
uint32_t *p; uint32_t *p;
int status; int status;
status = decode_op_hdr(xdr, OP_LOCKU); status = decode_op_hdr(xdr, OP_LOCKU);
if (status == 0) { if (status == 0) {
READ_BUF(sizeof(res->u.stateid.data)); READ_BUF(sizeof(res->stateid.data));
COPYMEM(res->u.stateid.data, sizeof(res->u.stateid.data)); COPYMEM(res->stateid.data, sizeof(res->stateid.data));
} }
return status; return status;
} }
...@@ -3831,6 +3846,9 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, uint32_t *p, struct ...@@ -3831,6 +3846,9 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, uint32_t *p, struct
if (status) if (status)
goto out; goto out;
status = decode_open(&xdr, res); status = decode_open(&xdr, res);
if (status)
goto out;
decode_getfattr(&xdr, res->f_attr, res->server);
out: out:
return status; return status;
} }
...@@ -3864,7 +3882,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_ ...@@ -3864,7 +3882,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_
/* /*
* Decode LOCK response * Decode LOCK response
*/ */
static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res) static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lock_res *res)
{ {
struct xdr_stream xdr; struct xdr_stream xdr;
struct compound_hdr hdr; struct compound_hdr hdr;
...@@ -3885,7 +3903,7 @@ static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_loc ...@@ -3885,7 +3903,7 @@ static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_loc
/* /*
* Decode LOCKT response * Decode LOCKT response
*/ */
static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res) static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockt_res *res)
{ {
struct xdr_stream xdr; struct xdr_stream xdr;
struct compound_hdr hdr; struct compound_hdr hdr;
...@@ -3906,7 +3924,7 @@ static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lo ...@@ -3906,7 +3924,7 @@ static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lo
/* /*
* Decode LOCKU response * Decode LOCKU response
*/ */
static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res) static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_locku_res *res)
{ {
struct xdr_stream xdr; struct xdr_stream xdr;
struct compound_hdr hdr; struct compound_hdr hdr;
...@@ -4174,7 +4192,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s ...@@ -4174,7 +4192,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s
/* /*
* DELEGRETURN request * DELEGRETURN request
*/ */
static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, void *dummy) static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_delegreturnres *res)
{ {
struct xdr_stream xdr; struct xdr_stream xdr;
struct compound_hdr hdr; struct compound_hdr hdr;
...@@ -4182,11 +4200,14 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, void *d ...@@ -4182,11 +4200,14 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, void *d
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
status = decode_compound_hdr(&xdr, &hdr); status = decode_compound_hdr(&xdr, &hdr);
if (status == 0) { if (status != 0)
status = decode_putfh(&xdr); goto out;
if (status == 0) status = decode_putfh(&xdr);
status = decode_delegreturn(&xdr); if (status != 0)
} goto out;
status = decode_delegreturn(&xdr);
decode_getfattr(&xdr, res->fattr, res->server);
out:
return status; return status;
} }
......
...@@ -296,8 +296,8 @@ static int __init root_nfs_name(char *name) ...@@ -296,8 +296,8 @@ static int __init root_nfs_name(char *name)
nfs_port = -1; nfs_port = -1;
nfs_data.version = NFS_MOUNT_VERSION; nfs_data.version = NFS_MOUNT_VERSION;
nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */ nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */
nfs_data.rsize = NFS_DEF_FILE_IO_BUFFER_SIZE; nfs_data.rsize = NFS_DEF_FILE_IO_SIZE;
nfs_data.wsize = NFS_DEF_FILE_IO_BUFFER_SIZE; nfs_data.wsize = NFS_DEF_FILE_IO_SIZE;
nfs_data.acregmin = 3; nfs_data.acregmin = 3;
nfs_data.acregmax = 60; nfs_data.acregmax = 60;
nfs_data.acdirmin = 30; nfs_data.acdirmin = 30;
......
...@@ -111,6 +111,9 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, ...@@ -111,6 +111,9 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
}; };
int status; int status;
/* Mask out the non-modebit related stuff from attr->ia_mode */
sattr->ia_mode &= S_IALLUGO;
dprintk("NFS call setattr\n"); dprintk("NFS call setattr\n");
nfs_fattr_init(fattr); nfs_fattr_init(fattr);
status = rpc_call(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, 0); status = rpc_call(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, 0);
...@@ -547,10 +550,9 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -547,10 +550,9 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int); extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
static void static void nfs_read_done(struct rpc_task *task, void *calldata)
nfs_read_done(struct rpc_task *task)
{ {
struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata; struct nfs_read_data *data = calldata;
if (task->tk_status >= 0) { if (task->tk_status >= 0) {
nfs_refresh_inode(data->inode, data->res.fattr); nfs_refresh_inode(data->inode, data->res.fattr);
...@@ -560,9 +562,14 @@ nfs_read_done(struct rpc_task *task) ...@@ -560,9 +562,14 @@ nfs_read_done(struct rpc_task *task)
if (data->args.offset + data->args.count >= data->res.fattr->size) if (data->args.offset + data->args.count >= data->res.fattr->size)
data->res.eof = 1; data->res.eof = 1;
} }
nfs_readpage_result(task); nfs_readpage_result(task, calldata);
} }
static const struct rpc_call_ops nfs_read_ops = {
.rpc_call_done = nfs_read_done,
.rpc_release = nfs_readdata_release,
};
static void static void
nfs_proc_read_setup(struct nfs_read_data *data) nfs_proc_read_setup(struct nfs_read_data *data)
{ {
...@@ -580,20 +587,24 @@ nfs_proc_read_setup(struct nfs_read_data *data) ...@@ -580,20 +587,24 @@ nfs_proc_read_setup(struct nfs_read_data *data)
flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
/* Finalize the task. */ /* Finalize the task. */
rpc_init_task(task, NFS_CLIENT(inode), nfs_read_done, flags); rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs_read_ops, data);
rpc_call_setup(task, &msg, 0); rpc_call_setup(task, &msg, 0);
} }
static void static void nfs_write_done(struct rpc_task *task, void *calldata)
nfs_write_done(struct rpc_task *task)
{ {
struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; struct nfs_write_data *data = calldata;
if (task->tk_status >= 0) if (task->tk_status >= 0)
nfs_post_op_update_inode(data->inode, data->res.fattr); nfs_post_op_update_inode(data->inode, data->res.fattr);
nfs_writeback_done(task); nfs_writeback_done(task, calldata);
} }
static const struct rpc_call_ops nfs_write_ops = {
.rpc_call_done = nfs_write_done,
.rpc_release = nfs_writedata_release,
};
static void static void
nfs_proc_write_setup(struct nfs_write_data *data, int how) nfs_proc_write_setup(struct nfs_write_data *data, int how)
{ {
...@@ -614,7 +625,7 @@ nfs_proc_write_setup(struct nfs_write_data *data, int how) ...@@ -614,7 +625,7 @@ nfs_proc_write_setup(struct nfs_write_data *data, int how)
flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
/* Finalize the task. */ /* Finalize the task. */
rpc_init_task(task, NFS_CLIENT(inode), nfs_write_done, flags); rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs_write_ops, data);
rpc_call_setup(task, &msg, 0); rpc_call_setup(task, &msg, 0);
} }
......
...@@ -42,9 +42,8 @@ mempool_t *nfs_rdata_mempool; ...@@ -42,9 +42,8 @@ mempool_t *nfs_rdata_mempool;
#define MIN_POOL_READ (32) #define MIN_POOL_READ (32)
void nfs_readdata_release(struct rpc_task *task) void nfs_readdata_release(void *data)
{ {
struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata;
nfs_readdata_free(data); nfs_readdata_free(data);
} }
...@@ -84,7 +83,7 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode, ...@@ -84,7 +83,7 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode,
int result; int result;
struct nfs_read_data *rdata; struct nfs_read_data *rdata;
rdata = nfs_readdata_alloc(); rdata = nfs_readdata_alloc(1);
if (!rdata) if (!rdata)
return -ENOMEM; return -ENOMEM;
...@@ -220,9 +219,6 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, ...@@ -220,9 +219,6 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
NFS_PROTO(inode)->read_setup(data); NFS_PROTO(inode)->read_setup(data);
data->task.tk_cookie = (unsigned long)inode; data->task.tk_cookie = (unsigned long)inode;
data->task.tk_calldata = data;
/* Release requests */
data->task.tk_release = nfs_readdata_release;
dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n",
data->task.tk_pid, data->task.tk_pid,
...@@ -287,7 +283,7 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode) ...@@ -287,7 +283,7 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode)
nbytes = req->wb_bytes; nbytes = req->wb_bytes;
for(;;) { for(;;) {
data = nfs_readdata_alloc(); data = nfs_readdata_alloc(1);
if (!data) if (!data)
goto out_bad; goto out_bad;
INIT_LIST_HEAD(&data->pages); INIT_LIST_HEAD(&data->pages);
...@@ -343,7 +339,7 @@ static int nfs_pagein_one(struct list_head *head, struct inode *inode) ...@@ -343,7 +339,7 @@ static int nfs_pagein_one(struct list_head *head, struct inode *inode)
if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
return nfs_pagein_multi(head, inode); return nfs_pagein_multi(head, inode);
data = nfs_readdata_alloc(); data = nfs_readdata_alloc(NFS_SERVER(inode)->rpages);
if (!data) if (!data)
goto out_bad; goto out_bad;
...@@ -452,9 +448,9 @@ static void nfs_readpage_result_full(struct nfs_read_data *data, int status) ...@@ -452,9 +448,9 @@ static void nfs_readpage_result_full(struct nfs_read_data *data, int status)
* This is the callback from RPC telling us whether a reply was * This is the callback from RPC telling us whether a reply was
* received or some error occurred (timeout or socket shutdown). * received or some error occurred (timeout or socket shutdown).
*/ */
void nfs_readpage_result(struct rpc_task *task) void nfs_readpage_result(struct rpc_task *task, void *calldata)
{ {
struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata; struct nfs_read_data *data = calldata;
struct nfs_readargs *argp = &data->args; struct nfs_readargs *argp = &data->args;
struct nfs_readres *resp = &data->res; struct nfs_readres *resp = &data->res;
int status = task->tk_status; int status = task->tk_status;
......
/*
* linux/fs/nfs/sysctl.c
*
* Sysctl interface to NFS parameters
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/linkage.h>
#include <linux/ctype.h>
#include <linux/fs.h>
#include <linux/sysctl.h>
#include <linux/module.h>
#include <linux/nfs4.h>
#include <linux/nfs_idmap.h>
#include "callback.h"
static const int nfs_set_port_min = 0;
static const int nfs_set_port_max = 65535;
static struct ctl_table_header *nfs_callback_sysctl_table;
/*
* Something that isn't CTL_ANY, CTL_NONE or a value that may clash.
* Use the same values as fs/lockd/svc.c
*/
#define CTL_UNNUMBERED -2
static ctl_table nfs_cb_sysctls[] = {
#ifdef CONFIG_NFS_V4
{
.ctl_name = CTL_UNNUMBERED,
.procname = "nfs_callback_tcpport",
.data = &nfs_callback_set_tcpport,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_minmax,
.extra1 = (int *)&nfs_set_port_min,
.extra2 = (int *)&nfs_set_port_max,
},
{
.ctl_name = CTL_UNNUMBERED,
.procname = "idmap_cache_timeout",
.data = &nfs_idmap_cache_timeout,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
},
#endif
{ .ctl_name = 0 }
};
static ctl_table nfs_cb_sysctl_dir[] = {
{
.ctl_name = CTL_UNNUMBERED,
.procname = "nfs",
.mode = 0555,
.child = nfs_cb_sysctls,
},
{ .ctl_name = 0 }
};
static ctl_table nfs_cb_sysctl_root[] = {
{
.ctl_name = CTL_FS,
.procname = "fs",
.mode = 0555,
.child = nfs_cb_sysctl_dir,
},
{ .ctl_name = 0 }
};
int nfs_register_sysctl(void)
{
nfs_callback_sysctl_table = register_sysctl_table(nfs_cb_sysctl_root, 0);
if (nfs_callback_sysctl_table == NULL)
return -ENOMEM;
return 0;
}
void nfs_unregister_sysctl(void)
{
unregister_sysctl_table(nfs_callback_sysctl_table);
nfs_callback_sysctl_table = NULL;
}
...@@ -87,10 +87,9 @@ nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data) ...@@ -87,10 +87,9 @@ nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
* We delay initializing RPC info until after the call to dentry_iput() * We delay initializing RPC info until after the call to dentry_iput()
* in order to minimize races against rename(). * in order to minimize races against rename().
*/ */
static void static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
nfs_async_unlink_init(struct rpc_task *task)
{ {
struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata; struct nfs_unlinkdata *data = calldata;
struct dentry *dir = data->dir; struct dentry *dir = data->dir;
struct rpc_message msg = { struct rpc_message msg = {
.rpc_cred = data->cred, .rpc_cred = data->cred,
...@@ -116,10 +115,9 @@ nfs_async_unlink_init(struct rpc_task *task) ...@@ -116,10 +115,9 @@ nfs_async_unlink_init(struct rpc_task *task)
* *
* Do the directory attribute update. * Do the directory attribute update.
*/ */
static void static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
nfs_async_unlink_done(struct rpc_task *task)
{ {
struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata; struct nfs_unlinkdata *data = calldata;
struct dentry *dir = data->dir; struct dentry *dir = data->dir;
struct inode *dir_i; struct inode *dir_i;
...@@ -141,13 +139,18 @@ nfs_async_unlink_done(struct rpc_task *task) ...@@ -141,13 +139,18 @@ nfs_async_unlink_done(struct rpc_task *task)
* We need to call nfs_put_unlinkdata as a 'tk_release' task since the * We need to call nfs_put_unlinkdata as a 'tk_release' task since the
* rpc_task would be freed too. * rpc_task would be freed too.
*/ */
static void static void nfs_async_unlink_release(void *calldata)
nfs_async_unlink_release(struct rpc_task *task)
{ {
struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata; struct nfs_unlinkdata *data = calldata;
nfs_put_unlinkdata(data); nfs_put_unlinkdata(data);
} }
static const struct rpc_call_ops nfs_unlink_ops = {
.rpc_call_prepare = nfs_async_unlink_init,
.rpc_call_done = nfs_async_unlink_done,
.rpc_release = nfs_async_unlink_release,
};
/** /**
* nfs_async_unlink - asynchronous unlinking of a file * nfs_async_unlink - asynchronous unlinking of a file
* @dentry: dentry to unlink * @dentry: dentry to unlink
...@@ -157,7 +160,6 @@ nfs_async_unlink(struct dentry *dentry) ...@@ -157,7 +160,6 @@ nfs_async_unlink(struct dentry *dentry)
{ {
struct dentry *dir = dentry->d_parent; struct dentry *dir = dentry->d_parent;
struct nfs_unlinkdata *data; struct nfs_unlinkdata *data;
struct rpc_task *task;
struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode); struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode);
int status = -ENOMEM; int status = -ENOMEM;
...@@ -178,17 +180,13 @@ nfs_async_unlink(struct dentry *dentry) ...@@ -178,17 +180,13 @@ nfs_async_unlink(struct dentry *dentry)
nfs_deletes = data; nfs_deletes = data;
data->count = 1; data->count = 1;
task = &data->task; rpc_init_task(&data->task, clnt, RPC_TASK_ASYNC, &nfs_unlink_ops, data);
rpc_init_task(task, clnt, nfs_async_unlink_done , RPC_TASK_ASYNC);
task->tk_calldata = data;
task->tk_action = nfs_async_unlink_init;
task->tk_release = nfs_async_unlink_release;
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
dentry->d_flags |= DCACHE_NFSFS_RENAMED; dentry->d_flags |= DCACHE_NFSFS_RENAMED;
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
rpc_sleep_on(&nfs_delete_queue, task, NULL, NULL); rpc_sleep_on(&nfs_delete_queue, &data->task, NULL, NULL);
status = 0; status = 0;
out: out:
return status; return status;
......
...@@ -89,24 +89,38 @@ static mempool_t *nfs_commit_mempool; ...@@ -89,24 +89,38 @@ static mempool_t *nfs_commit_mempool;
static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion); static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion);
static inline struct nfs_write_data *nfs_commit_alloc(void) static inline struct nfs_write_data *nfs_commit_alloc(unsigned int pagecount)
{ {
struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS); struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS);
if (p) { if (p) {
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->pages); INIT_LIST_HEAD(&p->pages);
if (pagecount < NFS_PAGEVEC_SIZE)
p->pagevec = &p->page_array[0];
else {
size_t size = ++pagecount * sizeof(struct page *);
p->pagevec = kmalloc(size, GFP_NOFS);
if (p->pagevec) {
memset(p->pagevec, 0, size);
} else {
mempool_free(p, nfs_commit_mempool);
p = NULL;
}
}
} }
return p; return p;
} }
static inline void nfs_commit_free(struct nfs_write_data *p) static inline void nfs_commit_free(struct nfs_write_data *p)
{ {
if (p && (p->pagevec != &p->page_array[0]))
kfree(p->pagevec);
mempool_free(p, nfs_commit_mempool); mempool_free(p, nfs_commit_mempool);
} }
static void nfs_writedata_release(struct rpc_task *task) void nfs_writedata_release(void *wdata)
{ {
struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata;
nfs_writedata_free(wdata); nfs_writedata_free(wdata);
} }
...@@ -168,7 +182,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode, ...@@ -168,7 +182,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode,
int result, written = 0; int result, written = 0;
struct nfs_write_data *wdata; struct nfs_write_data *wdata;
wdata = nfs_writedata_alloc(); wdata = nfs_writedata_alloc(1);
if (!wdata) if (!wdata)
return -ENOMEM; return -ENOMEM;
...@@ -232,19 +246,16 @@ static int nfs_writepage_async(struct nfs_open_context *ctx, ...@@ -232,19 +246,16 @@ static int nfs_writepage_async(struct nfs_open_context *ctx,
unsigned int offset, unsigned int count) unsigned int offset, unsigned int count)
{ {
struct nfs_page *req; struct nfs_page *req;
int status;
req = nfs_update_request(ctx, inode, page, offset, count); req = nfs_update_request(ctx, inode, page, offset, count);
status = (IS_ERR(req)) ? PTR_ERR(req) : 0; if (IS_ERR(req))
if (status < 0) return PTR_ERR(req);
goto out;
/* Update file length */ /* Update file length */
nfs_grow_file(page, offset, count); nfs_grow_file(page, offset, count);
/* Set the PG_uptodate flag? */ /* Set the PG_uptodate flag? */
nfs_mark_uptodate(page, offset, count); nfs_mark_uptodate(page, offset, count);
nfs_unlock_request(req); nfs_unlock_request(req);
out: return 0;
return status;
} }
static int wb_priority(struct writeback_control *wbc) static int wb_priority(struct writeback_control *wbc)
...@@ -304,11 +315,8 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc) ...@@ -304,11 +315,8 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc)
lock_kernel(); lock_kernel();
if (!IS_SYNC(inode) && inode_referenced) { if (!IS_SYNC(inode) && inode_referenced) {
err = nfs_writepage_async(ctx, inode, page, 0, offset); err = nfs_writepage_async(ctx, inode, page, 0, offset);
if (err >= 0) { if (!wbc->for_writepages)
err = 0; nfs_flush_inode(inode, 0, 0, wb_priority(wbc));
if (wbc->for_reclaim)
nfs_flush_inode(inode, 0, 0, FLUSH_STABLE);
}
} else { } else {
err = nfs_writepage_sync(ctx, inode, page, 0, err = nfs_writepage_sync(ctx, inode, page, 0,
offset, priority); offset, priority);
...@@ -877,9 +885,6 @@ static void nfs_write_rpcsetup(struct nfs_page *req, ...@@ -877,9 +885,6 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
data->task.tk_priority = flush_task_priority(how); data->task.tk_priority = flush_task_priority(how);
data->task.tk_cookie = (unsigned long)inode; data->task.tk_cookie = (unsigned long)inode;
data->task.tk_calldata = data;
/* Release requests */
data->task.tk_release = nfs_writedata_release;
dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n", dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n",
data->task.tk_pid, data->task.tk_pid,
...@@ -919,7 +924,7 @@ static int nfs_flush_multi(struct list_head *head, struct inode *inode, int how) ...@@ -919,7 +924,7 @@ static int nfs_flush_multi(struct list_head *head, struct inode *inode, int how)
nbytes = req->wb_bytes; nbytes = req->wb_bytes;
for (;;) { for (;;) {
data = nfs_writedata_alloc(); data = nfs_writedata_alloc(1);
if (!data) if (!data)
goto out_bad; goto out_bad;
list_add(&data->pages, &list); list_add(&data->pages, &list);
...@@ -983,7 +988,7 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) ...@@ -983,7 +988,7 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how)
if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE) if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE)
return nfs_flush_multi(head, inode, how); return nfs_flush_multi(head, inode, how);
data = nfs_writedata_alloc(); data = nfs_writedata_alloc(NFS_SERVER(inode)->wpages);
if (!data) if (!data)
goto out_bad; goto out_bad;
...@@ -1137,9 +1142,9 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status) ...@@ -1137,9 +1142,9 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status)
/* /*
* This function is called when the WRITE call is complete. * This function is called when the WRITE call is complete.
*/ */
void nfs_writeback_done(struct rpc_task *task) void nfs_writeback_done(struct rpc_task *task, void *calldata)
{ {
struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; struct nfs_write_data *data = calldata;
struct nfs_writeargs *argp = &data->args; struct nfs_writeargs *argp = &data->args;
struct nfs_writeres *resp = &data->res; struct nfs_writeres *resp = &data->res;
...@@ -1206,9 +1211,8 @@ void nfs_writeback_done(struct rpc_task *task) ...@@ -1206,9 +1211,8 @@ void nfs_writeback_done(struct rpc_task *task)
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
static void nfs_commit_release(struct rpc_task *task) void nfs_commit_release(void *wdata)
{ {
struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata;
nfs_commit_free(wdata); nfs_commit_free(wdata);
} }
...@@ -1244,9 +1248,6 @@ static void nfs_commit_rpcsetup(struct list_head *head, ...@@ -1244,9 +1248,6 @@ static void nfs_commit_rpcsetup(struct list_head *head,
data->task.tk_priority = flush_task_priority(how); data->task.tk_priority = flush_task_priority(how);
data->task.tk_cookie = (unsigned long)inode; data->task.tk_cookie = (unsigned long)inode;
data->task.tk_calldata = data;
/* Release requests */
data->task.tk_release = nfs_commit_release;
dprintk("NFS: %4d initiated commit call\n", data->task.tk_pid); dprintk("NFS: %4d initiated commit call\n", data->task.tk_pid);
} }
...@@ -1255,12 +1256,12 @@ static void nfs_commit_rpcsetup(struct list_head *head, ...@@ -1255,12 +1256,12 @@ static void nfs_commit_rpcsetup(struct list_head *head,
* Commit dirty pages * Commit dirty pages
*/ */
static int static int
nfs_commit_list(struct list_head *head, int how) nfs_commit_list(struct inode *inode, struct list_head *head, int how)
{ {
struct nfs_write_data *data; struct nfs_write_data *data;
struct nfs_page *req; struct nfs_page *req;
data = nfs_commit_alloc(); data = nfs_commit_alloc(NFS_SERVER(inode)->wpages);
if (!data) if (!data)
goto out_bad; goto out_bad;
...@@ -1283,10 +1284,9 @@ nfs_commit_list(struct list_head *head, int how) ...@@ -1283,10 +1284,9 @@ nfs_commit_list(struct list_head *head, int how)
/* /*
* COMMIT call returned * COMMIT call returned
*/ */
void void nfs_commit_done(struct rpc_task *task, void *calldata)
nfs_commit_done(struct rpc_task *task)
{ {
struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata; struct nfs_write_data *data = calldata;
struct nfs_page *req; struct nfs_page *req;
int res = 0; int res = 0;
...@@ -1366,7 +1366,7 @@ int nfs_commit_inode(struct inode *inode, int how) ...@@ -1366,7 +1366,7 @@ int nfs_commit_inode(struct inode *inode, int how)
res = nfs_scan_commit(inode, &head, 0, 0); res = nfs_scan_commit(inode, &head, 0, 0);
spin_unlock(&nfsi->req_lock); spin_unlock(&nfsi->req_lock);
if (res) { if (res) {
error = nfs_commit_list(&head, how); error = nfs_commit_list(inode, &head, how);
if (error < 0) if (error < 0)
return error; return error;
} }
...@@ -1377,22 +1377,23 @@ int nfs_commit_inode(struct inode *inode, int how) ...@@ -1377,22 +1377,23 @@ int nfs_commit_inode(struct inode *inode, int how)
int nfs_sync_inode(struct inode *inode, unsigned long idx_start, int nfs_sync_inode(struct inode *inode, unsigned long idx_start,
unsigned int npages, int how) unsigned int npages, int how)
{ {
int error, int nocommit = how & FLUSH_NOCOMMIT;
wait; int wait = how & FLUSH_WAIT;
int error;
wait = how & FLUSH_WAIT; how &= ~(FLUSH_WAIT|FLUSH_NOCOMMIT);
how &= ~FLUSH_WAIT;
do { do {
error = 0; if (wait) {
if (wait)
error = nfs_wait_on_requests(inode, idx_start, npages); error = nfs_wait_on_requests(inode, idx_start, npages);
if (error == 0) if (error != 0)
error = nfs_flush_inode(inode, idx_start, npages, how); continue;
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) }
if (error == 0) error = nfs_flush_inode(inode, idx_start, npages, how);
if (error != 0)
continue;
if (!nocommit)
error = nfs_commit_inode(inode, how); error = nfs_commit_inode(inode, how);
#endif
} while (error > 0); } while (error > 0);
return error; return error;
} }
......
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
#define NFSPROC4_CB_COMPOUND 1 #define NFSPROC4_CB_COMPOUND 1
/* declarations */ /* declarations */
static void nfs4_cb_null(struct rpc_task *task); static const struct rpc_call_ops nfs4_cb_null_ops;
/* Index of predefined Linux callback client operations */ /* Index of predefined Linux callback client operations */
...@@ -431,7 +431,6 @@ nfsd4_probe_callback(struct nfs4_client *clp) ...@@ -431,7 +431,6 @@ nfsd4_probe_callback(struct nfs4_client *clp)
} }
clnt->cl_intr = 0; clnt->cl_intr = 0;
clnt->cl_softrtry = 1; clnt->cl_softrtry = 1;
clnt->cl_chatty = 1;
/* Kick rpciod, put the call on the wire. */ /* Kick rpciod, put the call on the wire. */
...@@ -447,7 +446,7 @@ nfsd4_probe_callback(struct nfs4_client *clp) ...@@ -447,7 +446,7 @@ nfsd4_probe_callback(struct nfs4_client *clp)
msg.rpc_cred = nfsd4_lookupcred(clp,0); msg.rpc_cred = nfsd4_lookupcred(clp,0);
if (IS_ERR(msg.rpc_cred)) if (IS_ERR(msg.rpc_cred))
goto out_rpciod; goto out_rpciod;
status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, nfs4_cb_null, NULL); status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL);
put_rpccred(msg.rpc_cred); put_rpccred(msg.rpc_cred);
if (status != 0) { if (status != 0) {
...@@ -469,7 +468,7 @@ nfsd4_probe_callback(struct nfs4_client *clp) ...@@ -469,7 +468,7 @@ nfsd4_probe_callback(struct nfs4_client *clp)
} }
static void static void
nfs4_cb_null(struct rpc_task *task) nfs4_cb_null(struct rpc_task *task, void *dummy)
{ {
struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp; struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp;
struct nfs4_callback *cb = &clp->cl_callback; struct nfs4_callback *cb = &clp->cl_callback;
...@@ -488,6 +487,10 @@ nfs4_cb_null(struct rpc_task *task) ...@@ -488,6 +487,10 @@ nfs4_cb_null(struct rpc_task *task)
put_nfs4_client(clp); put_nfs4_client(clp);
} }
static const struct rpc_call_ops nfs4_cb_null_ops = {
.rpc_call_done = nfs4_cb_null,
};
/* /*
* called with dp->dl_count inc'ed. * called with dp->dl_count inc'ed.
* nfs4_lock_state() may or may not have been called. * nfs4_lock_state() may or may not have been called.
......
...@@ -760,7 +760,7 @@ extern struct file_lock *posix_test_lock(struct file *, struct file_lock *); ...@@ -760,7 +760,7 @@ extern struct file_lock *posix_test_lock(struct file *, struct file_lock *);
extern int posix_lock_file(struct file *, struct file_lock *); extern int posix_lock_file(struct file *, struct file_lock *);
extern int posix_lock_file_wait(struct file *, struct file_lock *); extern int posix_lock_file_wait(struct file *, struct file_lock *);
extern void posix_block_lock(struct file_lock *, struct file_lock *); extern void posix_block_lock(struct file_lock *, struct file_lock *);
extern void posix_unblock_lock(struct file *, struct file_lock *); extern int posix_unblock_lock(struct file *, struct file_lock *);
extern int posix_locks_deadlock(struct file_lock *, struct file_lock *); extern int posix_locks_deadlock(struct file_lock *, struct file_lock *);
extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl); extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
extern int __break_lease(struct inode *inode, unsigned int flags); extern int __break_lease(struct inode *inode, unsigned int flags);
......
...@@ -172,7 +172,7 @@ extern struct nlm_host *nlm_find_client(void); ...@@ -172,7 +172,7 @@ extern struct nlm_host *nlm_find_client(void);
/* /*
* Server-side lock handling * Server-side lock handling
*/ */
int nlmsvc_async_call(struct nlm_rqst *, u32, rpc_action); int nlmsvc_async_call(struct nlm_rqst *, u32, const struct rpc_call_ops *);
u32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *, u32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
struct nlm_lock *, int, struct nlm_cookie *); struct nlm_lock *, int, struct nlm_cookie *);
u32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *); u32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
......
...@@ -38,9 +38,6 @@ ...@@ -38,9 +38,6 @@
# define NFS_DEBUG # define NFS_DEBUG
#endif #endif
#define NFS_MAX_FILE_IO_BUFFER_SIZE 32768
#define NFS_DEF_FILE_IO_BUFFER_SIZE 4096
/* Default timeout values */ /* Default timeout values */
#define NFS_MAX_UDP_TIMEOUT (60*HZ) #define NFS_MAX_UDP_TIMEOUT (60*HZ)
#define NFS_MAX_TCP_TIMEOUT (600*HZ) #define NFS_MAX_TCP_TIMEOUT (600*HZ)
...@@ -65,6 +62,7 @@ ...@@ -65,6 +62,7 @@
#define FLUSH_STABLE 4 /* commit to stable storage */ #define FLUSH_STABLE 4 /* commit to stable storage */
#define FLUSH_LOWPRI 8 /* low priority background flush */ #define FLUSH_LOWPRI 8 /* low priority background flush */
#define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */ #define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */
#define FLUSH_NOCOMMIT 32 /* Don't send the NFSv3/v4 COMMIT */
#ifdef __KERNEL__ #ifdef __KERNEL__
...@@ -393,6 +391,17 @@ extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_ ...@@ -393,6 +391,17 @@ extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_
*/ */
extern struct inode_operations nfs_symlink_inode_operations; extern struct inode_operations nfs_symlink_inode_operations;
/*
* linux/fs/nfs/sysctl.c
*/
#ifdef CONFIG_SYSCTL
extern int nfs_register_sysctl(void);
extern void nfs_unregister_sysctl(void);
#else
#define nfs_register_sysctl() do { } while(0)
#define nfs_unregister_sysctl() do { } while(0)
#endif
/* /*
* linux/fs/nfs/unlink.c * linux/fs/nfs/unlink.c
*/ */
...@@ -406,10 +415,12 @@ extern int nfs_writepage(struct page *page, struct writeback_control *wbc); ...@@ -406,10 +415,12 @@ extern int nfs_writepage(struct page *page, struct writeback_control *wbc);
extern int nfs_writepages(struct address_space *, struct writeback_control *); extern int nfs_writepages(struct address_space *, struct writeback_control *);
extern int nfs_flush_incompatible(struct file *file, struct page *page); extern int nfs_flush_incompatible(struct file *file, struct page *page);
extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
extern void nfs_writeback_done(struct rpc_task *task); extern void nfs_writeback_done(struct rpc_task *task, void *data);
extern void nfs_writedata_release(void *data);
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
extern void nfs_commit_done(struct rpc_task *); extern void nfs_commit_done(struct rpc_task *, void *data);
extern void nfs_commit_release(void *data);
#endif #endif
/* /*
...@@ -460,18 +471,33 @@ static inline int nfs_wb_page(struct inode *inode, struct page* page) ...@@ -460,18 +471,33 @@ static inline int nfs_wb_page(struct inode *inode, struct page* page)
*/ */
extern mempool_t *nfs_wdata_mempool; extern mempool_t *nfs_wdata_mempool;
static inline struct nfs_write_data *nfs_writedata_alloc(void) static inline struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
{ {
struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, SLAB_NOFS); struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, SLAB_NOFS);
if (p) { if (p) {
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->pages); INIT_LIST_HEAD(&p->pages);
if (pagecount < NFS_PAGEVEC_SIZE)
p->pagevec = &p->page_array[0];
else {
size_t size = ++pagecount * sizeof(struct page *);
p->pagevec = kmalloc(size, GFP_NOFS);
if (p->pagevec) {
memset(p->pagevec, 0, size);
} else {
mempool_free(p, nfs_wdata_mempool);
p = NULL;
}
}
} }
return p; return p;
} }
static inline void nfs_writedata_free(struct nfs_write_data *p) static inline void nfs_writedata_free(struct nfs_write_data *p)
{ {
if (p && (p->pagevec != &p->page_array[0]))
kfree(p->pagevec);
mempool_free(p, nfs_wdata_mempool); mempool_free(p, nfs_wdata_mempool);
} }
...@@ -481,28 +507,45 @@ static inline void nfs_writedata_free(struct nfs_write_data *p) ...@@ -481,28 +507,45 @@ static inline void nfs_writedata_free(struct nfs_write_data *p)
extern int nfs_readpage(struct file *, struct page *); extern int nfs_readpage(struct file *, struct page *);
extern int nfs_readpages(struct file *, struct address_space *, extern int nfs_readpages(struct file *, struct address_space *,
struct list_head *, unsigned); struct list_head *, unsigned);
extern void nfs_readpage_result(struct rpc_task *); extern void nfs_readpage_result(struct rpc_task *, void *);
extern void nfs_readdata_release(void *data);
/* /*
* Allocate and free nfs_read_data structures * Allocate and free nfs_read_data structures
*/ */
extern mempool_t *nfs_rdata_mempool; extern mempool_t *nfs_rdata_mempool;
static inline struct nfs_read_data *nfs_readdata_alloc(void) static inline struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
{ {
struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, SLAB_NOFS); struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, SLAB_NOFS);
if (p)
if (p) {
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->pages);
if (pagecount < NFS_PAGEVEC_SIZE)
p->pagevec = &p->page_array[0];
else {
size_t size = ++pagecount * sizeof(struct page *);
p->pagevec = kmalloc(size, GFP_NOFS);
if (p->pagevec) {
memset(p->pagevec, 0, size);
} else {
mempool_free(p, nfs_rdata_mempool);
p = NULL;
}
}
}
return p; return p;
} }
static inline void nfs_readdata_free(struct nfs_read_data *p) static inline void nfs_readdata_free(struct nfs_read_data *p)
{ {
if (p && (p->pagevec != &p->page_array[0]))
kfree(p->pagevec);
mempool_free(p, nfs_rdata_mempool); mempool_free(p, nfs_rdata_mempool);
} }
extern void nfs_readdata_release(struct rpc_task *task);
/* /*
* linux/fs/nfs3proc.c * linux/fs/nfs3proc.c
*/ */
......
...@@ -71,6 +71,8 @@ int nfs_map_name_to_uid(struct nfs4_client *, const char *, size_t, __u32 *); ...@@ -71,6 +71,8 @@ int nfs_map_name_to_uid(struct nfs4_client *, const char *, size_t, __u32 *);
int nfs_map_group_to_gid(struct nfs4_client *, const char *, size_t, __u32 *); int nfs_map_group_to_gid(struct nfs4_client *, const char *, size_t, __u32 *);
int nfs_map_uid_to_name(struct nfs4_client *, __u32, char *); int nfs_map_uid_to_name(struct nfs4_client *, __u32, char *);
int nfs_map_gid_to_group(struct nfs4_client *, __u32, char *); int nfs_map_gid_to_group(struct nfs4_client *, __u32, char *);
extern unsigned int nfs_idmap_cache_timeout;
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* NFS_IDMAP_H */ #endif /* NFS_IDMAP_H */
...@@ -79,9 +79,7 @@ extern void nfs_clear_page_writeback(struct nfs_page *req); ...@@ -79,9 +79,7 @@ extern void nfs_clear_page_writeback(struct nfs_page *req);
static inline int static inline int
nfs_lock_request_dontget(struct nfs_page *req) nfs_lock_request_dontget(struct nfs_page *req)
{ {
if (test_and_set_bit(PG_BUSY, &req->wb_flags)) return !test_and_set_bit(PG_BUSY, &req->wb_flags);
return 0;
return 1;
} }
/* /*
...@@ -125,9 +123,7 @@ nfs_list_remove_request(struct nfs_page *req) ...@@ -125,9 +123,7 @@ nfs_list_remove_request(struct nfs_page *req)
static inline int static inline int
nfs_defer_commit(struct nfs_page *req) nfs_defer_commit(struct nfs_page *req)
{ {
if (test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags)) return !test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags);
return 0;
return 1;
} }
static inline void static inline void
...@@ -141,9 +137,7 @@ nfs_clear_commit(struct nfs_page *req) ...@@ -141,9 +137,7 @@ nfs_clear_commit(struct nfs_page *req)
static inline int static inline int
nfs_defer_reschedule(struct nfs_page *req) nfs_defer_reschedule(struct nfs_page *req)
{ {
if (test_and_set_bit(PG_NEED_RESCHED, &req->wb_flags)) return !test_and_set_bit(PG_NEED_RESCHED, &req->wb_flags);
return 0;
return 1;
} }
static inline void static inline void
......
...@@ -4,6 +4,16 @@ ...@@ -4,6 +4,16 @@
#include <linux/sunrpc/xprt.h> #include <linux/sunrpc/xprt.h>
#include <linux/nfsacl.h> #include <linux/nfsacl.h>
/*
* To change the maximum rsize and wsize supported by the NFS client, adjust
* NFS_MAX_FILE_IO_SIZE. 64KB is a typical maximum, but some servers can
* support a megabyte or more. The default is left at 4096 bytes, which is
* reasonable for NFS over UDP.
*/
#define NFS_MAX_FILE_IO_SIZE (1048576U)
#define NFS_DEF_FILE_IO_SIZE (4096U)
#define NFS_MIN_FILE_IO_SIZE (1024U)
struct nfs4_fsid { struct nfs4_fsid {
__u64 major; __u64 major;
__u64 minor; __u64 minor;
...@@ -137,7 +147,7 @@ struct nfs_openres { ...@@ -137,7 +147,7 @@ struct nfs_openres {
*/ */
struct nfs_open_confirmargs { struct nfs_open_confirmargs {
const struct nfs_fh * fh; const struct nfs_fh * fh;
nfs4_stateid stateid; nfs4_stateid * stateid;
struct nfs_seqid * seqid; struct nfs_seqid * seqid;
}; };
...@@ -165,66 +175,62 @@ struct nfs_closeres { ...@@ -165,66 +175,62 @@ struct nfs_closeres {
* * Arguments to the lock,lockt, and locku call. * * Arguments to the lock,lockt, and locku call.
* */ * */
struct nfs_lowner { struct nfs_lowner {
__u64 clientid; __u64 clientid;
u32 id; u32 id;
}; };
struct nfs_lock_opargs { struct nfs_lock_args {
struct nfs_fh * fh;
struct file_lock * fl;
struct nfs_seqid * lock_seqid; struct nfs_seqid * lock_seqid;
nfs4_stateid * lock_stateid; nfs4_stateid * lock_stateid;
struct nfs_seqid * open_seqid; struct nfs_seqid * open_seqid;
nfs4_stateid * open_stateid; nfs4_stateid * open_stateid;
struct nfs_lowner lock_owner; struct nfs_lowner lock_owner;
__u32 reclaim; unsigned char block : 1;
__u32 new_lock_owner; unsigned char reclaim : 1;
unsigned char new_lock_owner : 1;
}; };
struct nfs_locku_opargs { struct nfs_lock_res {
nfs4_stateid stateid;
};
struct nfs_locku_args {
struct nfs_fh * fh;
struct file_lock * fl;
struct nfs_seqid * seqid; struct nfs_seqid * seqid;
nfs4_stateid * stateid; nfs4_stateid * stateid;
}; };
struct nfs_lockargs { struct nfs_locku_res {
struct nfs_fh * fh; nfs4_stateid stateid;
__u32 type;
__u64 offset;
__u64 length;
union {
struct nfs_lock_opargs *lock; /* LOCK */
struct nfs_lowner *lockt; /* LOCKT */
struct nfs_locku_opargs *locku; /* LOCKU */
} u;
}; };
struct nfs_lock_denied { struct nfs_lockt_args {
__u64 offset; struct nfs_fh * fh;
__u64 length; struct file_lock * fl;
__u32 type; struct nfs_lowner lock_owner;
struct nfs_lowner owner;
}; };
struct nfs_lockres { struct nfs_lockt_res {
union { struct file_lock * denied; /* LOCK, LOCKT failed */
nfs4_stateid stateid;/* LOCK success, LOCKU */
struct nfs_lock_denied denied; /* LOCK failed, LOCKT success */
} u;
const struct nfs_server * server;
}; };
struct nfs4_delegreturnargs { struct nfs4_delegreturnargs {
const struct nfs_fh *fhandle; const struct nfs_fh *fhandle;
const nfs4_stateid *stateid; const nfs4_stateid *stateid;
const u32 * bitmask;
};
struct nfs4_delegreturnres {
struct nfs_fattr * fattr;
const struct nfs_server *server;
}; };
/* /*
* Arguments to the read call. * Arguments to the read call.
*/ */
#define NFS_READ_MAXIOV (9U)
#if (NFS_READ_MAXIOV > (MAX_IOVEC -2))
#error "NFS_READ_MAXIOV is too large"
#endif
struct nfs_readargs { struct nfs_readargs {
struct nfs_fh * fh; struct nfs_fh * fh;
struct nfs_open_context *context; struct nfs_open_context *context;
...@@ -243,11 +249,6 @@ struct nfs_readres { ...@@ -243,11 +249,6 @@ struct nfs_readres {
/* /*
* Arguments to the write call. * Arguments to the write call.
*/ */
#define NFS_WRITE_MAXIOV (9U)
#if (NFS_WRITE_MAXIOV > (MAX_IOVEC -2))
#error "NFS_WRITE_MAXIOV is too large"
#endif
struct nfs_writeargs { struct nfs_writeargs {
struct nfs_fh * fh; struct nfs_fh * fh;
struct nfs_open_context *context; struct nfs_open_context *context;
...@@ -678,6 +679,8 @@ struct nfs4_server_caps_res { ...@@ -678,6 +679,8 @@ struct nfs4_server_caps_res {
struct nfs_page; struct nfs_page;
#define NFS_PAGEVEC_SIZE (8U)
struct nfs_read_data { struct nfs_read_data {
int flags; int flags;
struct rpc_task task; struct rpc_task task;
...@@ -686,13 +689,14 @@ struct nfs_read_data { ...@@ -686,13 +689,14 @@ struct nfs_read_data {
struct nfs_fattr fattr; /* fattr storage */ struct nfs_fattr fattr; /* fattr storage */
struct list_head pages; /* Coalesced read requests */ struct list_head pages; /* Coalesced read requests */
struct nfs_page *req; /* multi ops per nfs_page */ struct nfs_page *req; /* multi ops per nfs_page */
struct page *pagevec[NFS_READ_MAXIOV]; struct page **pagevec;
struct nfs_readargs args; struct nfs_readargs args;
struct nfs_readres res; struct nfs_readres res;
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
unsigned long timestamp; /* For lease renewal */ unsigned long timestamp; /* For lease renewal */
#endif #endif
void (*complete) (struct nfs_read_data *, int); void (*complete) (struct nfs_read_data *, int);
struct page *page_array[NFS_PAGEVEC_SIZE + 1];
}; };
struct nfs_write_data { struct nfs_write_data {
...@@ -704,13 +708,14 @@ struct nfs_write_data { ...@@ -704,13 +708,14 @@ struct nfs_write_data {
struct nfs_writeverf verf; struct nfs_writeverf verf;
struct list_head pages; /* Coalesced requests we wish to flush */ struct list_head pages; /* Coalesced requests we wish to flush */
struct nfs_page *req; /* multi ops per nfs_page */ struct nfs_page *req; /* multi ops per nfs_page */
struct page *pagevec[NFS_WRITE_MAXIOV]; struct page **pagevec;
struct nfs_writeargs args; /* argument struct */ struct nfs_writeargs args; /* argument struct */
struct nfs_writeres res; /* result struct */ struct nfs_writeres res; /* result struct */
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
unsigned long timestamp; /* For lease renewal */ unsigned long timestamp; /* For lease renewal */
#endif #endif
void (*complete) (struct nfs_write_data *, int); void (*complete) (struct nfs_write_data *, int);
struct page *page_array[NFS_PAGEVEC_SIZE + 1];
}; };
struct nfs_access_entry; struct nfs_access_entry;
......
...@@ -49,7 +49,6 @@ struct rpc_clnt { ...@@ -49,7 +49,6 @@ struct rpc_clnt {
unsigned int cl_softrtry : 1,/* soft timeouts */ unsigned int cl_softrtry : 1,/* soft timeouts */
cl_intr : 1,/* interruptible */ cl_intr : 1,/* interruptible */
cl_chatty : 1,/* be verbose */
cl_autobind : 1,/* use getport() */ cl_autobind : 1,/* use getport() */
cl_oneshot : 1,/* dispose after use */ cl_oneshot : 1,/* dispose after use */
cl_dead : 1;/* abandoned */ cl_dead : 1;/* abandoned */
...@@ -126,7 +125,8 @@ int rpc_register(u32, u32, int, unsigned short, int *); ...@@ -126,7 +125,8 @@ int rpc_register(u32, u32, int, unsigned short, int *);
void rpc_call_setup(struct rpc_task *, struct rpc_message *, int); void rpc_call_setup(struct rpc_task *, struct rpc_message *, int);
int rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg,
int flags, rpc_action callback, void *clntdata); int flags, const struct rpc_call_ops *tk_ops,
void *calldata);
int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg,
int flags); int flags);
void rpc_restart_call(struct rpc_task *); void rpc_restart_call(struct rpc_task *);
...@@ -134,6 +134,7 @@ void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset); ...@@ -134,6 +134,7 @@ void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset);
void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset); void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset);
void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
size_t rpc_max_payload(struct rpc_clnt *); size_t rpc_max_payload(struct rpc_clnt *);
void rpc_force_rebind(struct rpc_clnt *);
int rpc_ping(struct rpc_clnt *clnt, int flags); int rpc_ping(struct rpc_clnt *clnt, int flags);
static __inline__ static __inline__
......
...@@ -48,7 +48,7 @@ u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, struc ...@@ -48,7 +48,7 @@ u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, struc
#define CKSUMTYPE_RSA_MD5 0x0007 #define CKSUMTYPE_RSA_MD5 0x0007
s32 make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, s32 make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
struct xdr_netobj *cksum); int body_offset, struct xdr_netobj *cksum);
void asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits); void asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits);
int decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, int decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen,
int explen); int explen);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -95,7 +95,7 @@ spkm3_read_token(struct spkm3_ctx *ctx, ...@@ -95,7 +95,7 @@ spkm3_read_token(struct spkm3_ctx *ctx,
ret = GSS_S_DEFECTIVE_TOKEN; ret = GSS_S_DEFECTIVE_TOKEN;
code = make_checksum(CKSUMTYPE_RSA_MD5, ptr + 2, code = make_checksum(CKSUMTYPE_RSA_MD5, ptr + 2,
mic_hdrlen + 2, mic_hdrlen + 2,
message_buffer, &md5cksum); message_buffer, 0, &md5cksum);
if (code) if (code)
goto out; goto out;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册