提交 53846a21 编写于 作者: L Linus Torvalds

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

* git://git.linux-nfs.org/pub/linux/nfs-2.6: (103 commits)
  SUNRPC,RPCSEC_GSS: spkm3--fix config dependencies
  SUNRPC,RPCSEC_GSS: spkm3: import contexts using NID_cast5_cbc
  LOCKD: Make nlmsvc_traverse_shares return void
  LOCKD: nlmsvc_traverse_blocks return is unused
  SUNRPC,RPCSEC_GSS: fix krb5 sequence numbers.
  NFSv4: Dont list system.nfs4_acl for filesystems that don't support it.
  SUNRPC,RPCSEC_GSS: remove unnecessary kmalloc of a checksum
  SUNRPC: Ensure rpc_call_async() always calls tk_ops->rpc_release()
  SUNRPC: Fix memory barriers for req->rq_received
  NFS: Fix a race in nfs_sync_inode()
  NFS: Clean up nfs_flush_list()
  NFS: Fix a race with PG_private and nfs_release_page()
  NFSv4: Ensure the callback daemon flushes signals
  SUNRPC: Fix a 'Busy inodes' error in rpc_pipefs
  NFS, NLM: Allow blocking locks to respect signals
  NFS: Make nfs_fhget() return appropriate error values
  NFSv4: Fix an oops in nfs4_fill_super
  lockd: blocks should hold a reference to the nlm_file
  NFSv4: SETCLIENTID_CONFIRM should handle NFS4ERR_DELAY/NFS4ERR_RESOURCE
  NFSv4: Send the delegation stateid for SETATTR calls
  ...
...@@ -1555,6 +1555,7 @@ config RPCSEC_GSS_SPKM3 ...@@ -1555,6 +1555,7 @@ config RPCSEC_GSS_SPKM3
select CRYPTO select CRYPTO
select CRYPTO_MD5 select CRYPTO_MD5
select CRYPTO_DES select CRYPTO_DES
select CRYPTO_CAST5
help help
Provides for secure RPC calls by means of a gss-api Provides for secure RPC calls by means of a gss-api
mechanism based on the SPKM3 public-key mechanism. mechanism based on the SPKM3 public-key mechanism.
......
...@@ -44,32 +44,25 @@ static LIST_HEAD(nlm_blocked); ...@@ -44,32 +44,25 @@ static LIST_HEAD(nlm_blocked);
/* /*
* Queue up a lock for blocking so that the GRANTED request can see it * Queue up a lock for blocking so that the GRANTED request can see it
*/ */
int nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl) struct nlm_wait *nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl)
{ {
struct nlm_wait *block; struct nlm_wait *block;
BUG_ON(req->a_block != NULL);
block = kmalloc(sizeof(*block), GFP_KERNEL); block = kmalloc(sizeof(*block), GFP_KERNEL);
if (block == NULL) if (block != NULL) {
return -ENOMEM;
block->b_host = host; block->b_host = host;
block->b_lock = fl; block->b_lock = fl;
init_waitqueue_head(&block->b_wait); init_waitqueue_head(&block->b_wait);
block->b_status = NLM_LCK_BLOCKED; block->b_status = NLM_LCK_BLOCKED;
list_add(&block->b_list, &nlm_blocked); list_add(&block->b_list, &nlm_blocked);
req->a_block = block; }
return block;
return 0;
} }
void nlmclnt_finish_block(struct nlm_rqst *req) void nlmclnt_finish_block(struct nlm_wait *block)
{ {
struct nlm_wait *block = req->a_block;
if (block == NULL) if (block == NULL)
return; return;
req->a_block = NULL;
list_del(&block->b_list); list_del(&block->b_list);
kfree(block); kfree(block);
} }
...@@ -77,15 +70,14 @@ void nlmclnt_finish_block(struct nlm_rqst *req) ...@@ -77,15 +70,14 @@ void nlmclnt_finish_block(struct nlm_rqst *req)
/* /*
* Block on a lock * Block on a lock
*/ */
long nlmclnt_block(struct nlm_rqst *req, long timeout) int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
{ {
struct nlm_wait *block = req->a_block;
long ret; long ret;
/* A borken server might ask us to block even if we didn't /* A borken server might ask us to block even if we didn't
* request it. Just say no! * request it. Just say no!
*/ */
if (!req->a_args.block) if (block == NULL)
return -EAGAIN; return -EAGAIN;
/* Go to sleep waiting for GRANT callback. Some servers seem /* Go to sleep waiting for GRANT callback. Some servers seem
...@@ -99,13 +91,10 @@ long nlmclnt_block(struct nlm_rqst *req, long timeout) ...@@ -99,13 +91,10 @@ long nlmclnt_block(struct nlm_rqst *req, long timeout)
ret = wait_event_interruptible_timeout(block->b_wait, ret = wait_event_interruptible_timeout(block->b_wait,
block->b_status != NLM_LCK_BLOCKED, block->b_status != NLM_LCK_BLOCKED,
timeout); timeout);
if (ret < 0)
if (block->b_status != NLM_LCK_BLOCKED) { return -ERESTARTSYS;
req->a_res.status = block->b_status; req->a_res.status = block->b_status;
block->b_status = NLM_LCK_BLOCKED; return 0;
}
return ret;
} }
/* /*
...@@ -125,7 +114,15 @@ u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock) ...@@ -125,7 +114,15 @@ u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
list_for_each_entry(block, &nlm_blocked, b_list) { list_for_each_entry(block, &nlm_blocked, b_list) {
struct file_lock *fl_blocked = block->b_lock; struct file_lock *fl_blocked = block->b_lock;
if (!nlm_compare_locks(fl_blocked, fl)) if (fl_blocked->fl_start != fl->fl_start)
continue;
if (fl_blocked->fl_end != fl->fl_end)
continue;
/*
* Careful! The NLM server will return the 32-bit "pid" that
* we put on the wire: in this case the lockowner "pid".
*/
if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid)
continue; continue;
if (!nlm_cmp_addr(&block->b_host->h_addr, addr)) if (!nlm_cmp_addr(&block->b_host->h_addr, addr))
continue; continue;
...@@ -146,34 +143,6 @@ u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock) ...@@ -146,34 +143,6 @@ u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
* server crash. * server crash.
*/ */
/*
* Mark the locks for reclaiming.
* FIXME: In 2.5 we don't want to iterate through any global file_lock_list.
* Maintain NLM lock reclaiming lists in the nlm_host instead.
*/
static
void nlmclnt_mark_reclaim(struct nlm_host *host)
{
struct file_lock *fl;
struct inode *inode;
struct list_head *tmp;
list_for_each(tmp, &file_lock_list) {
fl = list_entry(tmp, struct file_lock, fl_link);
inode = fl->fl_file->f_dentry->d_inode;
if (inode->i_sb->s_magic != NFS_SUPER_MAGIC)
continue;
if (fl->fl_u.nfs_fl.owner == NULL)
continue;
if (fl->fl_u.nfs_fl.owner->host != host)
continue;
if (!(fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED))
continue;
fl->fl_u.nfs_fl.flags |= NFS_LCK_RECLAIM;
}
}
/* /*
* Someone has sent us an SM_NOTIFY. Ensure we bind to the new port number, * Someone has sent us an SM_NOTIFY. Ensure we bind to the new port number,
* that we mark locks for reclaiming, and that we bump the pseudo NSM state. * that we mark locks for reclaiming, and that we bump the pseudo NSM state.
...@@ -186,7 +155,12 @@ void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate) ...@@ -186,7 +155,12 @@ void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
host->h_state++; host->h_state++;
host->h_nextrebind = 0; host->h_nextrebind = 0;
nlm_rebind_host(host); nlm_rebind_host(host);
nlmclnt_mark_reclaim(host);
/*
* Mark the locks for reclaiming.
*/
list_splice_init(&host->h_granted, &host->h_reclaim);
dprintk("NLM: reclaiming locks for host %s", host->h_name); dprintk("NLM: reclaiming locks for host %s", host->h_name);
} }
...@@ -215,9 +189,7 @@ reclaimer(void *ptr) ...@@ -215,9 +189,7 @@ reclaimer(void *ptr)
{ {
struct nlm_host *host = (struct nlm_host *) ptr; struct nlm_host *host = (struct nlm_host *) ptr;
struct nlm_wait *block; struct nlm_wait *block;
struct list_head *tmp; struct file_lock *fl, *next;
struct file_lock *fl;
struct inode *inode;
daemonize("%s-reclaim", host->h_name); daemonize("%s-reclaim", host->h_name);
allow_signal(SIGKILL); allow_signal(SIGKILL);
...@@ -229,23 +201,13 @@ reclaimer(void *ptr) ...@@ -229,23 +201,13 @@ reclaimer(void *ptr)
/* First, reclaim all locks that have been marked. */ /* First, reclaim all locks that have been marked. */
restart: restart:
list_for_each(tmp, &file_lock_list) { list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
fl = list_entry(tmp, struct file_lock, fl_link); list_del_init(&fl->fl_u.nfs_fl.list);
inode = fl->fl_file->f_dentry->d_inode;
if (inode->i_sb->s_magic != NFS_SUPER_MAGIC)
continue;
if (fl->fl_u.nfs_fl.owner == NULL)
continue;
if (fl->fl_u.nfs_fl.owner->host != host)
continue;
if (!(fl->fl_u.nfs_fl.flags & NFS_LCK_RECLAIM))
continue;
fl->fl_u.nfs_fl.flags &= ~NFS_LCK_RECLAIM;
nlmclnt_reclaim(host, fl);
if (signalled()) if (signalled())
break; continue;
if (nlmclnt_reclaim(host, fl) == 0)
list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
goto restart; goto restart;
} }
......
...@@ -132,59 +132,18 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) ...@@ -132,59 +132,18 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh)); memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh));
lock->caller = system_utsname.nodename; lock->caller = system_utsname.nodename;
lock->oh.data = req->a_owner; lock->oh.data = req->a_owner;
lock->oh.len = sprintf(req->a_owner, "%d@%s", lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s",
current->pid, system_utsname.nodename); (unsigned int)fl->fl_u.nfs_fl.owner->pid,
locks_copy_lock(&lock->fl, fl); system_utsname.nodename);
lock->svid = fl->fl_u.nfs_fl.owner->pid;
lock->fl.fl_start = fl->fl_start;
lock->fl.fl_end = fl->fl_end;
lock->fl.fl_type = fl->fl_type;
} }
static void nlmclnt_release_lockargs(struct nlm_rqst *req) static void nlmclnt_release_lockargs(struct nlm_rqst *req)
{ {
struct file_lock *fl = &req->a_args.lock.fl; BUG_ON(req->a_args.lock.fl.fl_ops != NULL);
if (fl->fl_ops && fl->fl_ops->fl_release_private)
fl->fl_ops->fl_release_private(fl);
}
/*
* Initialize arguments for GRANTED call. The nlm_rqst structure
* has been cleared already.
*/
int
nlmclnt_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
{
locks_copy_lock(&call->a_args.lock.fl, &lock->fl);
memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh));
call->a_args.lock.caller = system_utsname.nodename;
call->a_args.lock.oh.len = lock->oh.len;
/* set default data area */
call->a_args.lock.oh.data = call->a_owner;
if (lock->oh.len > NLMCLNT_OHSIZE) {
void *data = kmalloc(lock->oh.len, GFP_KERNEL);
if (!data) {
nlmclnt_freegrantargs(call);
return 0;
}
call->a_args.lock.oh.data = (u8 *) data;
}
memcpy(call->a_args.lock.oh.data, lock->oh.data, lock->oh.len);
return 1;
}
void
nlmclnt_freegrantargs(struct nlm_rqst *call)
{
struct file_lock *fl = &call->a_args.lock.fl;
/*
* Check whether we allocated memory for the owner.
*/
if (call->a_args.lock.oh.data != (u8 *) call->a_owner) {
kfree(call->a_args.lock.oh.data);
}
if (fl->fl_ops && fl->fl_ops->fl_release_private)
fl->fl_ops->fl_release_private(fl);
} }
/* /*
...@@ -193,9 +152,8 @@ nlmclnt_freegrantargs(struct nlm_rqst *call) ...@@ -193,9 +152,8 @@ nlmclnt_freegrantargs(struct nlm_rqst *call)
int int
nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
{ {
struct nfs_server *nfssrv = NFS_SERVER(inode);
struct nlm_host *host; struct nlm_host *host;
struct nlm_rqst reqst, *call = &reqst; struct nlm_rqst *call;
sigset_t oldset; sigset_t oldset;
unsigned long flags; unsigned long flags;
int status, proto, vers; int status, proto, vers;
...@@ -209,23 +167,17 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) ...@@ -209,23 +167,17 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
/* Retrieve transport protocol from NFS client */ /* Retrieve transport protocol from NFS client */
proto = NFS_CLIENT(inode)->cl_xprt->prot; proto = NFS_CLIENT(inode)->cl_xprt->prot;
if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers))) host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers);
if (host == NULL)
return -ENOLCK; return -ENOLCK;
/* Create RPC client handle if not there, and copy soft call = nlm_alloc_call(host);
* and intr flags from NFS client. */ if (call == NULL)
if (host->h_rpcclnt == NULL) { return -ENOMEM;
struct rpc_clnt *clnt;
/* Bind an rpc client to this host handle (does not nlmclnt_locks_init_private(fl, host);
* perform a portmapper lookup) */ /* Set up the argument struct */
if (!(clnt = nlm_bind_host(host))) { nlmclnt_setlockargs(call, fl);
status = -ENOLCK;
goto done;
}
clnt->cl_softrtry = nfssrv->client->cl_softrtry;
clnt->cl_intr = nfssrv->client->cl_intr;
}
/* Keep the old signal mask */ /* Keep the old signal mask */
spin_lock_irqsave(&current->sighand->siglock, flags); spin_lock_irqsave(&current->sighand->siglock, flags);
...@@ -238,26 +190,10 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) ...@@ -238,26 +190,10 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
&& (current->flags & PF_EXITING)) { && (current->flags & PF_EXITING)) {
sigfillset(&current->blocked); /* Mask all signals */ sigfillset(&current->blocked); /* Mask all signals */
recalc_sigpending(); recalc_sigpending();
spin_unlock_irqrestore(&current->sighand->siglock, flags);
call = nlmclnt_alloc_call();
if (!call) {
status = -ENOMEM;
goto out_restore;
}
call->a_flags = RPC_TASK_ASYNC; call->a_flags = RPC_TASK_ASYNC;
} else {
spin_unlock_irqrestore(&current->sighand->siglock, flags);
memset(call, 0, sizeof(*call));
locks_init_lock(&call->a_args.lock.fl);
locks_init_lock(&call->a_res.lock.fl);
} }
call->a_host = host; spin_unlock_irqrestore(&current->sighand->siglock, flags);
nlmclnt_locks_init_private(fl, host);
/* Set up the argument struct */
nlmclnt_setlockargs(call, fl);
if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
if (fl->fl_type != F_UNLCK) { if (fl->fl_type != F_UNLCK) {
...@@ -270,41 +206,58 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) ...@@ -270,41 +206,58 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
else else
status = -EINVAL; status = -EINVAL;
out_restore: fl->fl_ops->fl_release_private(fl);
fl->fl_ops = NULL;
spin_lock_irqsave(&current->sighand->siglock, flags); spin_lock_irqsave(&current->sighand->siglock, flags);
current->blocked = oldset; current->blocked = oldset;
recalc_sigpending(); recalc_sigpending();
spin_unlock_irqrestore(&current->sighand->siglock, flags); spin_unlock_irqrestore(&current->sighand->siglock, flags);
done:
dprintk("lockd: clnt proc returns %d\n", status); dprintk("lockd: clnt proc returns %d\n", status);
nlm_release_host(host);
return status; return status;
} }
EXPORT_SYMBOL(nlmclnt_proc); EXPORT_SYMBOL(nlmclnt_proc);
/* /*
* Allocate an NLM RPC call struct * Allocate an NLM RPC call struct
*
* Note: the caller must hold a reference to host. In case of failure,
* this reference will be released.
*/ */
struct nlm_rqst * struct nlm_rqst *nlm_alloc_call(struct nlm_host *host)
nlmclnt_alloc_call(void)
{ {
struct nlm_rqst *call; struct nlm_rqst *call;
while (!signalled()) { for(;;) {
call = (struct nlm_rqst *) kmalloc(sizeof(struct nlm_rqst), GFP_KERNEL); call = kzalloc(sizeof(*call), GFP_KERNEL);
if (call) { if (call != NULL) {
memset(call, 0, sizeof(*call));
locks_init_lock(&call->a_args.lock.fl); locks_init_lock(&call->a_args.lock.fl);
locks_init_lock(&call->a_res.lock.fl); locks_init_lock(&call->a_res.lock.fl);
call->a_host = host;
return call; return call;
} }
printk("nlmclnt_alloc_call: failed, waiting for memory\n"); if (signalled())
break;
printk("nlm_alloc_call: failed, waiting for memory\n");
schedule_timeout_interruptible(5*HZ); schedule_timeout_interruptible(5*HZ);
} }
nlm_release_host(host);
return NULL; return NULL;
} }
void nlm_release_call(struct nlm_rqst *call)
{
nlm_release_host(call->a_host);
nlmclnt_release_lockargs(call);
kfree(call);
}
static void nlmclnt_rpc_release(void *data)
{
return nlm_release_call(data);
}
static int nlm_wait_on_grace(wait_queue_head_t *queue) static int nlm_wait_on_grace(wait_queue_head_t *queue)
{ {
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
...@@ -401,57 +354,45 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc) ...@@ -401,57 +354,45 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
/* /*
* Generic NLM call, async version. * Generic NLM call, async version.
*/ */
int nlmsvc_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops)
{ {
struct nlm_host *host = req->a_host; struct nlm_host *host = req->a_host;
struct rpc_clnt *clnt; struct rpc_clnt *clnt;
struct rpc_message msg = { int status = -ENOLCK;
.rpc_argp = &req->a_args,
.rpc_resp = &req->a_res,
};
int status;
dprintk("lockd: call procedure %d on %s (async)\n", dprintk("lockd: call procedure %d on %s (async)\n",
(int)proc, host->h_name); (int)proc, host->h_name);
/* If we have no RPC client yet, create one. */ /* If we have no RPC client yet, create one. */
if ((clnt = nlm_bind_host(host)) == NULL) clnt = nlm_bind_host(host);
return -ENOLCK; if (clnt == NULL)
msg.rpc_proc = &clnt->cl_procinfo[proc]; goto out_err;
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, tk_ops, req); status = rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req);
if (status == 0)
return 0;
out_err:
nlm_release_call(req);
return status; return status;
} }
static int nlmclnt_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
{ {
struct nlm_host *host = req->a_host;
struct rpc_clnt *clnt;
struct nlm_args *argp = &req->a_args;
struct nlm_res *resp = &req->a_res;
struct rpc_message msg = { struct rpc_message msg = {
.rpc_argp = argp, .rpc_argp = &req->a_args,
.rpc_resp = resp, .rpc_resp = &req->a_res,
}; };
int status; return __nlm_async_call(req, proc, &msg, tk_ops);
}
dprintk("lockd: call procedure %d on %s (async)\n",
(int)proc, host->h_name);
/* If we have no RPC client yet, create one. */
if ((clnt = nlm_bind_host(host)) == NULL)
return -ENOLCK;
msg.rpc_proc = &clnt->cl_procinfo[proc];
/* Increment host refcount */ int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
nlm_get_host(host); {
/* bootstrap and kick off the async RPC call */ struct rpc_message msg = {
status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req); .rpc_argp = &req->a_res,
if (status < 0) };
nlm_release_host(host); return __nlm_async_call(req, proc, &msg, tk_ops);
return status;
} }
/* /*
...@@ -463,36 +404,41 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl) ...@@ -463,36 +404,41 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
int status; int status;
status = nlmclnt_call(req, NLMPROC_TEST); status = nlmclnt_call(req, NLMPROC_TEST);
nlmclnt_release_lockargs(req);
if (status < 0) if (status < 0)
return status; goto out;
status = req->a_res.status; switch (req->a_res.status) {
if (status == NLM_LCK_GRANTED) { case NLM_LCK_GRANTED:
fl->fl_type = F_UNLCK; fl->fl_type = F_UNLCK;
} if (status == NLM_LCK_DENIED) { break;
case NLM_LCK_DENIED:
/* /*
* Report the conflicting lock back to the application. * Report the conflicting lock back to the application.
*/ */
locks_copy_lock(fl, &req->a_res.lock.fl); fl->fl_start = req->a_res.lock.fl.fl_start;
fl->fl_end = req->a_res.lock.fl.fl_start;
fl->fl_type = req->a_res.lock.fl.fl_type;
fl->fl_pid = 0; fl->fl_pid = 0;
} else { break;
return nlm_stat_to_errno(req->a_res.status); default:
status = nlm_stat_to_errno(req->a_res.status);
} }
out:
return 0; nlm_release_call(req);
return status;
} }
static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl) static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl)
{ {
memcpy(&new->fl_u.nfs_fl, &fl->fl_u.nfs_fl, sizeof(new->fl_u.nfs_fl)); new->fl_u.nfs_fl.state = fl->fl_u.nfs_fl.state;
nlm_get_lockowner(new->fl_u.nfs_fl.owner); new->fl_u.nfs_fl.owner = nlm_get_lockowner(fl->fl_u.nfs_fl.owner);
list_add_tail(&new->fl_u.nfs_fl.list, &fl->fl_u.nfs_fl.owner->host->h_granted);
} }
static void nlmclnt_locks_release_private(struct file_lock *fl) static void nlmclnt_locks_release_private(struct file_lock *fl)
{ {
list_del(&fl->fl_u.nfs_fl.list);
nlm_put_lockowner(fl->fl_u.nfs_fl.owner); nlm_put_lockowner(fl->fl_u.nfs_fl.owner);
fl->fl_ops = NULL;
} }
static struct file_lock_operations nlmclnt_lock_ops = { static struct file_lock_operations nlmclnt_lock_ops = {
...@@ -504,8 +450,8 @@ static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *ho ...@@ -504,8 +450,8 @@ static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *ho
{ {
BUG_ON(fl->fl_ops != NULL); BUG_ON(fl->fl_ops != NULL);
fl->fl_u.nfs_fl.state = 0; fl->fl_u.nfs_fl.state = 0;
fl->fl_u.nfs_fl.flags = 0;
fl->fl_u.nfs_fl.owner = nlm_find_lockowner(host, fl->fl_owner); fl->fl_u.nfs_fl.owner = nlm_find_lockowner(host, fl->fl_owner);
INIT_LIST_HEAD(&fl->fl_u.nfs_fl.list);
fl->fl_ops = &nlmclnt_lock_ops; fl->fl_ops = &nlmclnt_lock_ops;
} }
...@@ -552,57 +498,52 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) ...@@ -552,57 +498,52 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
{ {
struct nlm_host *host = req->a_host; struct nlm_host *host = req->a_host;
struct nlm_res *resp = &req->a_res; struct nlm_res *resp = &req->a_res;
long timeout; struct nlm_wait *block = NULL;
int status; int status = -ENOLCK;
if (!host->h_monitored && nsm_monitor(host) < 0) { if (!host->h_monitored && nsm_monitor(host) < 0) {
printk(KERN_NOTICE "lockd: failed to monitor %s\n", printk(KERN_NOTICE "lockd: failed to monitor %s\n",
host->h_name); host->h_name);
status = -ENOLCK;
goto out; goto out;
} }
if (req->a_args.block) { block = nlmclnt_prepare_block(host, fl);
status = nlmclnt_prepare_block(req, host, fl);
if (status < 0)
goto out;
}
for(;;) { for(;;) {
status = nlmclnt_call(req, NLMPROC_LOCK); status = nlmclnt_call(req, NLMPROC_LOCK);
if (status < 0) if (status < 0)
goto out_unblock; goto out_unblock;
if (resp->status != NLM_LCK_BLOCKED) if (!req->a_args.block)
break; break;
/* Wait on an NLM blocking lock */
timeout = nlmclnt_block(req, NLMCLNT_POLL_TIMEOUT);
/* Did a reclaimer thread notify us of a server reboot? */ /* Did a reclaimer thread notify us of a server reboot? */
if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD)
continue; continue;
if (resp->status != NLM_LCK_BLOCKED) if (resp->status != NLM_LCK_BLOCKED)
break; break;
if (timeout >= 0) /* Wait on an NLM blocking lock */
continue; status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT);
/* We were interrupted. Send a CANCEL request to the server /* if we were interrupted. Send a CANCEL request to the server
* and exit * and exit
*/ */
status = (int)timeout; if (status < 0)
goto out_unblock; goto out_unblock;
if (resp->status != NLM_LCK_BLOCKED)
break;
} }
if (resp->status == NLM_LCK_GRANTED) { if (resp->status == NLM_LCK_GRANTED) {
fl->fl_u.nfs_fl.state = host->h_state; fl->fl_u.nfs_fl.state = host->h_state;
fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED;
fl->fl_flags |= FL_SLEEP; fl->fl_flags |= FL_SLEEP;
/* Ensure the resulting lock will get added to granted list */
do_vfs_lock(fl); do_vfs_lock(fl);
} }
status = nlm_stat_to_errno(resp->status); status = nlm_stat_to_errno(resp->status);
out_unblock: out_unblock:
nlmclnt_finish_block(req); nlmclnt_finish_block(block);
/* Cancel the blocked request if it is still pending */ /* Cancel the blocked request if it is still pending */
if (resp->status == NLM_LCK_BLOCKED) if (resp->status == NLM_LCK_BLOCKED)
nlmclnt_cancel(host, req->a_args.block, fl); nlmclnt_cancel(host, req->a_args.block, fl);
out: out:
nlmclnt_release_lockargs(req); nlm_release_call(req);
return status; return status;
} }
...@@ -658,10 +599,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) ...@@ -658,10 +599,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
struct nlm_res *resp = &req->a_res; struct nlm_res *resp = &req->a_res;
int status; int status;
/* Clean the GRANTED flag now so the lock doesn't get
* reclaimed while we're stuck in the unlock call. */
fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED;
/* /*
* Note: the server is supposed to either grant us the unlock * Note: the server is supposed to either grant us the unlock
* request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
...@@ -669,32 +606,24 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) ...@@ -669,32 +606,24 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
*/ */
do_vfs_lock(fl); do_vfs_lock(fl);
if (req->a_flags & RPC_TASK_ASYNC) { if (req->a_flags & RPC_TASK_ASYNC)
status = nlmclnt_async_call(req, NLMPROC_UNLOCK, return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
&nlmclnt_unlock_ops);
/* Hrmf... Do the unlock early since locks_remove_posix()
* really expects us to free the lock synchronously */
if (status < 0) {
nlmclnt_release_lockargs(req);
kfree(req);
}
return status;
}
status = nlmclnt_call(req, NLMPROC_UNLOCK); status = nlmclnt_call(req, NLMPROC_UNLOCK);
nlmclnt_release_lockargs(req);
if (status < 0) if (status < 0)
return status; goto out;
status = 0;
if (resp->status == NLM_LCK_GRANTED) if (resp->status == NLM_LCK_GRANTED)
return 0; goto out;
if (resp->status != NLM_LCK_DENIED_NOLOCKS) if (resp->status != NLM_LCK_DENIED_NOLOCKS)
printk("lockd: unexpected unlock status: %d\n", resp->status); printk("lockd: unexpected unlock status: %d\n", resp->status);
/* What to do now? I'm out of my depth... */ /* What to do now? I'm out of my depth... */
status = -ENOLCK;
return -ENOLCK; out:
nlm_release_call(req);
return status;
} }
static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
...@@ -716,9 +645,6 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) ...@@ -716,9 +645,6 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
if (status != NLM_LCK_GRANTED) if (status != NLM_LCK_GRANTED)
printk(KERN_WARNING "lockd: unexpected unlock status: %d\n", status); printk(KERN_WARNING "lockd: unexpected unlock status: %d\n", status);
die: die:
nlm_release_host(req->a_host);
nlmclnt_release_lockargs(req);
kfree(req);
return; return;
retry_rebind: retry_rebind:
nlm_rebind_host(req->a_host); nlm_rebind_host(req->a_host);
...@@ -728,6 +654,7 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) ...@@ -728,6 +654,7 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
static const struct rpc_call_ops nlmclnt_unlock_ops = { static const struct rpc_call_ops nlmclnt_unlock_ops = {
.rpc_call_done = nlmclnt_unlock_callback, .rpc_call_done = nlmclnt_unlock_callback,
.rpc_release = nlmclnt_rpc_release,
}; };
/* /*
...@@ -749,20 +676,15 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl ...@@ -749,20 +676,15 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl
recalc_sigpending(); recalc_sigpending();
spin_unlock_irqrestore(&current->sighand->siglock, flags); spin_unlock_irqrestore(&current->sighand->siglock, flags);
req = nlmclnt_alloc_call(); req = nlm_alloc_call(nlm_get_host(host));
if (!req) if (!req)
return -ENOMEM; return -ENOMEM;
req->a_host = host;
req->a_flags = RPC_TASK_ASYNC; req->a_flags = RPC_TASK_ASYNC;
nlmclnt_setlockargs(req, fl); nlmclnt_setlockargs(req, fl);
req->a_args.block = block; req->a_args.block = block;
status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops); status = nlm_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
if (status < 0) {
nlmclnt_release_lockargs(req);
kfree(req);
}
spin_lock_irqsave(&current->sighand->siglock, flags); spin_lock_irqsave(&current->sighand->siglock, flags);
current->blocked = oldset; current->blocked = oldset;
...@@ -791,6 +713,7 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) ...@@ -791,6 +713,7 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
switch (req->a_res.status) { switch (req->a_res.status) {
case NLM_LCK_GRANTED: case NLM_LCK_GRANTED:
case NLM_LCK_DENIED_GRACE_PERIOD: case NLM_LCK_DENIED_GRACE_PERIOD:
case NLM_LCK_DENIED:
/* Everything's good */ /* Everything's good */
break; break;
case NLM_LCK_DENIED_NOLOCKS: case NLM_LCK_DENIED_NOLOCKS:
...@@ -802,9 +725,6 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) ...@@ -802,9 +725,6 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
} }
die: die:
nlm_release_host(req->a_host);
nlmclnt_release_lockargs(req);
kfree(req);
return; return;
retry_cancel: retry_cancel:
...@@ -818,6 +738,7 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) ...@@ -818,6 +738,7 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
static const struct rpc_call_ops nlmclnt_cancel_ops = { static const struct rpc_call_ops nlmclnt_cancel_ops = {
.rpc_call_done = nlmclnt_cancel_callback, .rpc_call_done = nlmclnt_cancel_callback,
.rpc_release = nlmclnt_rpc_release,
}; };
/* /*
......
...@@ -123,6 +123,8 @@ nlm_lookup_host(int server, struct sockaddr_in *sin, ...@@ -123,6 +123,8 @@ nlm_lookup_host(int server, struct sockaddr_in *sin,
nlm_hosts[hash] = host; nlm_hosts[hash] = host;
INIT_LIST_HEAD(&host->h_lockowners); INIT_LIST_HEAD(&host->h_lockowners);
spin_lock_init(&host->h_lock); spin_lock_init(&host->h_lock);
INIT_LIST_HEAD(&host->h_granted);
INIT_LIST_HEAD(&host->h_reclaim);
if (++nrhosts > NLM_HOST_MAX) if (++nrhosts > NLM_HOST_MAX)
next_gc = 0; next_gc = 0;
...@@ -191,11 +193,12 @@ nlm_bind_host(struct nlm_host *host) ...@@ -191,11 +193,12 @@ nlm_bind_host(struct nlm_host *host)
xprt->resvport = 1; /* NLM requires a reserved port */ xprt->resvport = 1; /* NLM requires a reserved port */
/* Existing NLM servers accept AUTH_UNIX only */ /* Existing NLM servers accept AUTH_UNIX only */
clnt = rpc_create_client(xprt, host->h_name, &nlm_program, clnt = rpc_new_client(xprt, host->h_name, &nlm_program,
host->h_version, RPC_AUTH_UNIX); host->h_version, RPC_AUTH_UNIX);
if (IS_ERR(clnt)) if (IS_ERR(clnt))
goto forgetit; goto forgetit;
clnt->cl_autobind = 1; /* turn on pmap queries */ clnt->cl_autobind = 1; /* turn on pmap queries */
clnt->cl_softrtry = 1; /* All queries are soft */
host->h_rpcclnt = clnt; host->h_rpcclnt = clnt;
} }
...@@ -242,8 +245,12 @@ void nlm_release_host(struct nlm_host *host) ...@@ -242,8 +245,12 @@ void nlm_release_host(struct nlm_host *host)
{ {
if (host != NULL) { if (host != NULL) {
dprintk("lockd: release host %s\n", host->h_name); dprintk("lockd: release host %s\n", host->h_name);
atomic_dec(&host->h_count);
BUG_ON(atomic_read(&host->h_count) < 0); BUG_ON(atomic_read(&host->h_count) < 0);
if (atomic_dec_and_test(&host->h_count)) {
BUG_ON(!list_empty(&host->h_lockowners));
BUG_ON(!list_empty(&host->h_granted));
BUG_ON(!list_empty(&host->h_reclaim));
}
} }
} }
...@@ -331,7 +338,6 @@ nlm_gc_hosts(void) ...@@ -331,7 +338,6 @@ nlm_gc_hosts(void)
rpc_destroy_client(host->h_rpcclnt); rpc_destroy_client(host->h_rpcclnt);
} }
} }
BUG_ON(!list_empty(&host->h_lockowners));
kfree(host); kfree(host);
nrhosts--; nrhosts--;
} }
......
...@@ -35,6 +35,10 @@ nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res) ...@@ -35,6 +35,10 @@ nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
struct rpc_clnt *clnt; struct rpc_clnt *clnt;
int status; int status;
struct nsm_args args; struct nsm_args args;
struct rpc_message msg = {
.rpc_argp = &args,
.rpc_resp = res,
};
clnt = nsm_create(); clnt = nsm_create();
if (IS_ERR(clnt)) { if (IS_ERR(clnt)) {
...@@ -49,7 +53,8 @@ nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res) ...@@ -49,7 +53,8 @@ nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
args.proc = NLMPROC_NSM_NOTIFY; args.proc = NLMPROC_NSM_NOTIFY;
memset(res, 0, sizeof(*res)); memset(res, 0, sizeof(*res));
status = rpc_call(clnt, proc, &args, res, 0); msg.rpc_proc = &clnt->cl_procinfo[proc];
status = rpc_call_sync(clnt, &msg, 0);
if (status < 0) if (status < 0)
printk(KERN_DEBUG "nsm_mon_unmon: rpc failed, status=%d\n", printk(KERN_DEBUG "nsm_mon_unmon: rpc failed, status=%d\n",
status); status);
...@@ -214,12 +219,16 @@ static struct rpc_procinfo nsm_procedures[] = { ...@@ -214,12 +219,16 @@ static struct rpc_procinfo nsm_procedures[] = {
.p_encode = (kxdrproc_t) xdr_encode_mon, .p_encode = (kxdrproc_t) xdr_encode_mon,
.p_decode = (kxdrproc_t) xdr_decode_stat_res, .p_decode = (kxdrproc_t) xdr_decode_stat_res,
.p_bufsiz = MAX(SM_mon_sz, SM_monres_sz) << 2, .p_bufsiz = MAX(SM_mon_sz, SM_monres_sz) << 2,
.p_statidx = SM_MON,
.p_name = "MONITOR",
}, },
[SM_UNMON] = { [SM_UNMON] = {
.p_proc = SM_UNMON, .p_proc = SM_UNMON,
.p_encode = (kxdrproc_t) xdr_encode_unmon, .p_encode = (kxdrproc_t) xdr_encode_unmon,
.p_decode = (kxdrproc_t) xdr_decode_stat, .p_decode = (kxdrproc_t) xdr_decode_stat,
.p_bufsiz = MAX(SM_mon_id_sz, SM_unmonres_sz) << 2, .p_bufsiz = MAX(SM_mon_id_sz, SM_unmonres_sz) << 2,
.p_statidx = SM_UNMON,
.p_name = "UNMONITOR",
}, },
}; };
......
...@@ -21,10 +21,6 @@ ...@@ -21,10 +21,6 @@
#define NLMDBG_FACILITY NLMDBG_CLIENT #define NLMDBG_FACILITY NLMDBG_CLIENT
static u32 nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *);
static const struct rpc_call_ops nlm4svc_callback_ops;
/* /*
* Obtain client and file from arguments * Obtain client and file from arguments
*/ */
...@@ -233,84 +229,90 @@ nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -233,84 +229,90 @@ nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
return rpc_success; return rpc_success;
} }
/*
* This is the generic lockd callback for async RPC calls
*/
static void nlm4svc_callback_exit(struct rpc_task *task, void *data)
{
dprintk("lockd: %4d callback returned %d\n", task->tk_pid,
-task->tk_status);
}
static void nlm4svc_callback_release(void *data)
{
nlm_release_call(data);
}
static const struct rpc_call_ops nlm4svc_callback_ops = {
.rpc_call_done = nlm4svc_callback_exit,
.rpc_release = nlm4svc_callback_release,
};
/* /*
* `Async' versions of the above service routines. They aren't really, * `Async' versions of the above service routines. They aren't really,
* because we send the callback before the reply proper. I hope this * because we send the callback before the reply proper. I hope this
* doesn't break any clients. * doesn't break any clients.
*/ */
static int static int nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp,
nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp, int (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *))
void *resp)
{ {
struct nlm_res res; struct nlm_host *host;
u32 stat; struct nlm_rqst *call;
int stat;
dprintk("lockd: TEST_MSG called\n"); host = nlmsvc_lookup_host(rqstp);
memset(&res, 0, sizeof(res)); if (host == NULL)
return rpc_system_err;
if ((stat = nlm4svc_proc_test(rqstp, argp, &res)) == 0) call = nlm_alloc_call(host);
stat = nlm4svc_callback(rqstp, NLMPROC_TEST_RES, &res); if (call == NULL)
return rpc_system_err;
stat = func(rqstp, argp, &call->a_res);
if (stat != 0) {
nlm_release_call(call);
return stat; return stat;
}
call->a_flags = RPC_TASK_ASYNC;
if (nlm_async_reply(call, proc, &nlm4svc_callback_ops) < 0)
return rpc_system_err;
return rpc_success;
} }
static int static int nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp) void *resp)
{ {
struct nlm_res res; dprintk("lockd: TEST_MSG called\n");
u32 stat; return nlm4svc_callback(rqstp, NLMPROC_TEST_RES, argp, nlm4svc_proc_test);
}
static int nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp)
{
dprintk("lockd: LOCK_MSG called\n"); dprintk("lockd: LOCK_MSG called\n");
memset(&res, 0, sizeof(res)); return nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, argp, nlm4svc_proc_lock);
if ((stat = nlm4svc_proc_lock(rqstp, argp, &res)) == 0)
stat = nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, &res);
return stat;
} }
static int static int nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp) void *resp)
{ {
struct nlm_res res;
u32 stat;
dprintk("lockd: CANCEL_MSG called\n"); dprintk("lockd: CANCEL_MSG called\n");
memset(&res, 0, sizeof(res)); return nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, argp, nlm4svc_proc_cancel);
if ((stat = nlm4svc_proc_cancel(rqstp, argp, &res)) == 0)
stat = nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, &res);
return stat;
} }
static int static int nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp) void *resp)
{ {
struct nlm_res res;
u32 stat;
dprintk("lockd: UNLOCK_MSG called\n"); dprintk("lockd: UNLOCK_MSG called\n");
memset(&res, 0, sizeof(res)); return nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, argp, nlm4svc_proc_unlock);
if ((stat = nlm4svc_proc_unlock(rqstp, argp, &res)) == 0)
stat = nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, &res);
return stat;
} }
static int static int nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp) void *resp)
{ {
struct nlm_res res;
u32 stat;
dprintk("lockd: GRANTED_MSG called\n"); dprintk("lockd: GRANTED_MSG called\n");
memset(&res, 0, sizeof(res)); return nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, argp, nlm4svc_proc_granted);
if ((stat = nlm4svc_proc_granted(rqstp, argp, &res)) == 0)
stat = nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, &res);
return stat;
} }
/* /*
...@@ -471,55 +473,6 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, ...@@ -471,55 +473,6 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp,
} }
/*
* This is the generic lockd callback for async RPC calls
*/
static u32
nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
{
struct nlm_host *host;
struct nlm_rqst *call;
if (!(call = nlmclnt_alloc_call()))
return rpc_system_err;
host = nlmclnt_lookup_host(&rqstp->rq_addr,
rqstp->rq_prot, rqstp->rq_vers);
if (!host) {
kfree(call);
return rpc_system_err;
}
call->a_flags = RPC_TASK_ASYNC;
call->a_host = host;
memcpy(&call->a_args, resp, sizeof(*resp));
if (nlmsvc_async_call(call, proc, &nlm4svc_callback_ops) < 0)
goto error;
return rpc_success;
error:
kfree(call);
nlm_release_host(host);
return rpc_system_err;
}
static void nlm4svc_callback_exit(struct rpc_task *task, void *data)
{
struct nlm_rqst *call = data;
if (task->tk_status < 0) {
dprintk("lockd: %4d callback failed (errno = %d)\n",
task->tk_pid, -task->tk_status);
}
nlm_release_host(call->a_host);
kfree(call);
}
static const struct rpc_call_ops nlm4svc_callback_ops = {
.rpc_call_done = nlm4svc_callback_exit,
};
/* /*
* NLM Server procedures. * NLM Server procedures.
*/ */
......
...@@ -39,9 +39,12 @@ ...@@ -39,9 +39,12 @@
#define nlm_deadlock nlm_lck_denied #define nlm_deadlock nlm_lck_denied
#endif #endif
static void nlmsvc_release_block(struct nlm_block *block);
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 int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
static void nlmsvc_freegrantargs(struct nlm_rqst *call);
static const struct rpc_call_ops nlmsvc_grant_ops; static const struct rpc_call_ops nlmsvc_grant_ops;
/* /*
...@@ -58,6 +61,7 @@ nlmsvc_insert_block(struct nlm_block *block, unsigned long when) ...@@ -58,6 +61,7 @@ nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
struct nlm_block **bp, *b; struct nlm_block **bp, *b;
dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when); dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
kref_get(&block->b_count);
if (block->b_queued) if (block->b_queued)
nlmsvc_remove_block(block); nlmsvc_remove_block(block);
bp = &nlm_blocked; bp = &nlm_blocked;
...@@ -90,6 +94,7 @@ nlmsvc_remove_block(struct nlm_block *block) ...@@ -90,6 +94,7 @@ nlmsvc_remove_block(struct nlm_block *block)
if (b == block) { if (b == block) {
*bp = block->b_next; *bp = block->b_next;
block->b_queued = 0; block->b_queued = 0;
nlmsvc_release_block(block);
return 1; return 1;
} }
} }
...@@ -98,11 +103,10 @@ nlmsvc_remove_block(struct nlm_block *block) ...@@ -98,11 +103,10 @@ nlmsvc_remove_block(struct nlm_block *block)
} }
/* /*
* Find a block for a given lock and optionally remove it from * Find a block for a given lock
* the list.
*/ */
static struct nlm_block * static struct nlm_block *
nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock, int remove) nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock)
{ {
struct nlm_block **head, *block; struct nlm_block **head, *block;
struct file_lock *fl; struct file_lock *fl;
...@@ -112,17 +116,14 @@ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock, int remove) ...@@ -112,17 +116,14 @@ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock, int remove)
(long long)lock->fl.fl_start, (long long)lock->fl.fl_start,
(long long)lock->fl.fl_end, lock->fl.fl_type); (long long)lock->fl.fl_end, lock->fl.fl_type);
for (head = &nlm_blocked; (block = *head) != 0; head = &block->b_next) { for (head = &nlm_blocked; (block = *head) != 0; head = &block->b_next) {
fl = &block->b_call.a_args.lock.fl; fl = &block->b_call->a_args.lock.fl;
dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n", dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
block->b_file, fl->fl_pid, block->b_file, fl->fl_pid,
(long long)fl->fl_start, (long long)fl->fl_start,
(long long)fl->fl_end, fl->fl_type, (long long)fl->fl_end, fl->fl_type,
nlmdbg_cookie2a(&block->b_call.a_args.cookie)); nlmdbg_cookie2a(&block->b_call->a_args.cookie));
if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) { if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
if (remove) { kref_get(&block->b_count);
*head = block->b_next;
block->b_queued = 0;
}
return block; return block;
} }
} }
...@@ -150,11 +151,13 @@ nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin) ...@@ -150,11 +151,13 @@ nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin)
for (block = nlm_blocked; block; block = block->b_next) { for (block = nlm_blocked; block; block = block->b_next) {
dprintk("cookie: head of blocked queue %p, block %p\n", dprintk("cookie: head of blocked queue %p, block %p\n",
nlm_blocked, block); nlm_blocked, block);
if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie) if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie)
&& nlm_cmp_addr(sin, &block->b_host->h_addr)) && nlm_cmp_addr(sin, &block->b_host->h_addr))
break; break;
} }
if (block != NULL)
kref_get(&block->b_count);
return block; return block;
} }
...@@ -174,27 +177,30 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, ...@@ -174,27 +177,30 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
{ {
struct nlm_block *block; struct nlm_block *block;
struct nlm_host *host; struct nlm_host *host;
struct nlm_rqst *call; struct nlm_rqst *call = NULL;
/* Create host handle for callback */ /* Create host handle for callback */
host = nlmclnt_lookup_host(&rqstp->rq_addr, host = nlmsvc_lookup_host(rqstp);
rqstp->rq_prot, rqstp->rq_vers);
if (host == NULL) if (host == NULL)
return NULL; return NULL;
call = nlm_alloc_call(host);
if (call == NULL)
return NULL;
/* Allocate memory for block, and initialize arguments */ /* Allocate memory for block, and initialize arguments */
if (!(block = (struct nlm_block *) kmalloc(sizeof(*block), GFP_KERNEL))) block = kzalloc(sizeof(*block), GFP_KERNEL);
if (block == NULL)
goto failed; goto failed;
memset(block, 0, sizeof(*block)); kref_init(&block->b_count);
locks_init_lock(&block->b_call.a_args.lock.fl);
locks_init_lock(&block->b_call.a_res.lock.fl);
if (!nlmclnt_setgrantargs(&block->b_call, lock)) if (!nlmsvc_setgrantargs(call, lock))
goto failed_free; goto failed_free;
/* Set notifier function for VFS, and init args */ /* Set notifier function for VFS, and init args */
block->b_call.a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations; call->a_args.lock.fl.fl_flags |= FL_SLEEP;
block->b_call.a_args.cookie = *cookie; /* see above */ call->a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations;
call->a_args.cookie = *cookie; /* see above */
dprintk("lockd: created block %p...\n", block); dprintk("lockd: created block %p...\n", block);
...@@ -202,22 +208,23 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, ...@@ -202,22 +208,23 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
block->b_daemon = rqstp->rq_server; block->b_daemon = rqstp->rq_server;
block->b_host = host; block->b_host = host;
block->b_file = file; block->b_file = file;
file->f_count++;
/* Add to file's list of blocks */ /* Add to file's list of blocks */
block->b_fnext = file->f_blocks; block->b_fnext = file->f_blocks;
file->f_blocks = block; file->f_blocks = block;
/* Set up RPC arguments for callback */ /* Set up RPC arguments for callback */
call = &block->b_call; block->b_call = call;
call->a_host = host;
call->a_flags = RPC_TASK_ASYNC; call->a_flags = RPC_TASK_ASYNC;
call->a_block = block;
return block; return block;
failed_free: failed_free:
kfree(block); kfree(block);
failed: failed:
nlm_release_host(host); nlm_release_call(call);
return NULL; return NULL;
} }
...@@ -227,29 +234,26 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, ...@@ -227,29 +234,26 @@ 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 int static int nlmsvc_unlink_block(struct nlm_block *block)
nlmsvc_delete_block(struct nlm_block *block, int unlock)
{ {
struct file_lock *fl = &block->b_call.a_args.lock.fl; int status;
struct nlm_file *file = block->b_file; dprintk("lockd: unlinking block %p...\n", block);
struct nlm_block **bp;
int status = 0;
dprintk("lockd: deleting block %p...\n", block);
/* Remove block from list */ /* Remove block from list */
status = posix_unblock_lock(block->b_file->f_file, &block->b_call->a_args.lock.fl);
nlmsvc_remove_block(block); nlmsvc_remove_block(block);
if (unlock)
status = posix_unblock_lock(file->f_file, fl);
/* If the block is in the middle of a GRANT callback,
* don't kill it yet. */
if (block->b_incall) {
nlmsvc_insert_block(block, NLM_NEVER);
block->b_done = 1;
return status; return status;
} }
static void nlmsvc_free_block(struct kref *kref)
{
struct nlm_block *block = container_of(kref, struct nlm_block, b_count);
struct nlm_file *file = block->b_file;
struct nlm_block **bp;
dprintk("lockd: freeing block %p...\n", block);
down(&file->f_sema);
/* Remove block from file's list of blocks */ /* Remove block from file's list of blocks */
for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) { for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) {
if (*bp == block) { if (*bp == block) {
...@@ -257,36 +261,93 @@ nlmsvc_delete_block(struct nlm_block *block, int unlock) ...@@ -257,36 +261,93 @@ nlmsvc_delete_block(struct nlm_block *block, int unlock)
break; break;
} }
} }
up(&file->f_sema);
if (block->b_host) nlmsvc_freegrantargs(block->b_call);
nlm_release_host(block->b_host); nlm_release_call(block->b_call);
nlmclnt_freegrantargs(&block->b_call); nlm_release_file(block->b_file);
kfree(block); kfree(block);
return status; }
static void nlmsvc_release_block(struct nlm_block *block)
{
if (block != NULL)
kref_put(&block->b_count, nlmsvc_free_block);
}
static void nlmsvc_act_mark(struct nlm_host *host, struct nlm_file *file)
{
struct nlm_block *block;
down(&file->f_sema);
for (block = file->f_blocks; block != NULL; block = block->b_fnext)
block->b_host->h_inuse = 1;
up(&file->f_sema);
}
static void nlmsvc_act_unlock(struct nlm_host *host, struct nlm_file *file)
{
struct nlm_block *block;
restart:
down(&file->f_sema);
for (block = file->f_blocks; block != NULL; block = block->b_fnext) {
if (host != NULL && host != block->b_host)
continue;
if (!block->b_queued)
continue;
kref_get(&block->b_count);
up(&file->f_sema);
nlmsvc_unlink_block(block);
nlmsvc_release_block(block);
goto restart;
}
up(&file->f_sema);
} }
/* /*
* Loop over all blocks and perform the action specified. * Loop over all blocks and perform the action specified.
* (NLM_ACT_CHECK handled by nlmsvc_inspect_file). * (NLM_ACT_CHECK handled by nlmsvc_inspect_file).
*/ */
int void
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;
/* XXX: Will everything get cleaned up if we don't unlock here? */
down(&file->f_sema);
for (block = file->f_blocks; block; block = next) {
next = block->b_fnext;
if (action == NLM_ACT_MARK) if (action == NLM_ACT_MARK)
block->b_host->h_inuse = 1; nlmsvc_act_mark(host, file);
else if (action == NLM_ACT_UNLOCK) { else
if (host == NULL || host == block->b_host) nlmsvc_act_unlock(host, file);
nlmsvc_delete_block(block, 1); }
}
} /*
up(&file->f_sema); * Initialize arguments for GRANTED call. The nlm_rqst structure
* has been cleared already.
*/
static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
{
locks_copy_lock(&call->a_args.lock.fl, &lock->fl);
memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh));
call->a_args.lock.caller = system_utsname.nodename;
call->a_args.lock.oh.len = lock->oh.len;
/* set default data area */
call->a_args.lock.oh.data = call->a_owner;
call->a_args.lock.svid = lock->fl.fl_pid;
if (lock->oh.len > NLMCLNT_OHSIZE) {
void *data = kmalloc(lock->oh.len, GFP_KERNEL);
if (!data)
return 0; return 0;
call->a_args.lock.oh.data = (u8 *) data;
}
memcpy(call->a_args.lock.oh.data, lock->oh.data, lock->oh.len);
return 1;
}
static void nlmsvc_freegrantargs(struct nlm_rqst *call)
{
if (call->a_args.lock.oh.data != call->a_owner)
kfree(call->a_args.lock.oh.data);
} }
/* /*
...@@ -297,9 +358,9 @@ u32 ...@@ -297,9 +358,9 @@ u32
nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
struct nlm_lock *lock, int wait, struct nlm_cookie *cookie) struct nlm_lock *lock, int wait, struct nlm_cookie *cookie)
{ {
struct file_lock *conflock; struct nlm_block *block, *newblock = NULL;
struct nlm_block *block;
int error; int error;
u32 ret;
dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n", dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
file->f_file->f_dentry->d_inode->i_sb->s_id, file->f_file->f_dentry->d_inode->i_sb->s_id,
...@@ -310,69 +371,65 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, ...@@ -310,69 +371,65 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
wait); wait);
/* Get existing block (in case client is busy-waiting) */ lock->fl.fl_flags &= ~FL_SLEEP;
block = nlmsvc_lookup_block(file, lock, 0);
lock->fl.fl_flags |= FL_LOCKD;
again: again:
/* Lock file against concurrent access */ /* Lock file against concurrent access */
down(&file->f_sema); down(&file->f_sema);
/* Get existing block (in case client is busy-waiting) */
block = nlmsvc_lookup_block(file, lock);
if (block == NULL) {
if (newblock != NULL)
lock = &newblock->b_call->a_args.lock;
} else
lock = &block->b_call->a_args.lock;
if (!(conflock = posix_test_lock(file->f_file, &lock->fl))) {
error = posix_lock_file(file->f_file, &lock->fl); error = posix_lock_file(file->f_file, &lock->fl);
lock->fl.fl_flags &= ~FL_SLEEP;
if (block) dprintk("lockd: posix_lock_file returned %d\n", error);
nlmsvc_delete_block(block, 0);
up(&file->f_sema);
dprintk("lockd: posix_lock_file returned %d\n", -error); switch(error) {
switch(-error) {
case 0: case 0:
return nlm_granted; ret = nlm_granted;
case EDEADLK: goto out;
return nlm_deadlock; case -EAGAIN:
case EAGAIN: break;
return nlm_lck_denied; case -EDEADLK:
ret = nlm_deadlock;
goto out;
default: /* includes ENOLCK */ default: /* includes ENOLCK */
return nlm_lck_denied_nolocks; ret = nlm_lck_denied_nolocks;
} goto out;
} }
if (!wait) { ret = nlm_lck_denied;
up(&file->f_sema); if (!wait)
return nlm_lck_denied; goto out;
}
if (posix_locks_deadlock(&lock->fl, conflock)) { ret = nlm_lck_blocked;
up(&file->f_sema); if (block != NULL)
return nlm_deadlock; goto out;
}
/* If we don't have a block, create and initialize it. Then /* If we don't have a block, create and initialize it. Then
* retry because we may have slept in kmalloc. */ * retry because we may have slept in kmalloc. */
/* We have to release f_sema as nlmsvc_create_block may try to /* We have to release f_sema as nlmsvc_create_block may try to
* to claim it while doing host garbage collection */ * to claim it while doing host garbage collection */
if (block == NULL) { if (newblock == NULL) {
up(&file->f_sema); up(&file->f_sema);
dprintk("lockd: blocking on this lock (allocating).\n"); dprintk("lockd: blocking on this lock (allocating).\n");
if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie))) if (!(newblock = nlmsvc_create_block(rqstp, file, lock, cookie)))
return nlm_lck_denied_nolocks; return nlm_lck_denied_nolocks;
goto again; goto again;
} }
/* Append to list of blocked */ /* Append to list of blocked */
nlmsvc_insert_block(block, NLM_NEVER); nlmsvc_insert_block(newblock, NLM_NEVER);
out:
if (list_empty(&block->b_call.a_args.lock.fl.fl_block)) {
/* Now add block to block list of the conflicting lock
if we haven't done so. */
dprintk("lockd: blocking on this lock.\n");
posix_block_lock(conflock, &block->b_call.a_args.lock.fl);
}
up(&file->f_sema); up(&file->f_sema);
return nlm_lck_blocked; nlmsvc_release_block(newblock);
nlmsvc_release_block(block);
dprintk("lockd: nlmsvc_lock returned %u\n", ret);
return ret;
} }
/* /*
...@@ -382,8 +439,6 @@ u32 ...@@ -382,8 +439,6 @@ u32
nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock, nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
struct nlm_lock *conflock) struct nlm_lock *conflock)
{ {
struct file_lock *fl;
dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n", dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%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,
file->f_file->f_dentry->d_inode->i_ino, file->f_file->f_dentry->d_inode->i_ino,
...@@ -391,13 +446,14 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock, ...@@ -391,13 +446,14 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
(long long)lock->fl.fl_start, (long long)lock->fl.fl_start,
(long long)lock->fl.fl_end); (long long)lock->fl.fl_end);
if ((fl = posix_test_lock(file->f_file, &lock->fl)) != NULL) { if (posix_test_lock(file->f_file, &lock->fl, &conflock->fl)) {
dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n", dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
fl->fl_type, (long long)fl->fl_start, conflock->fl.fl_type,
(long long)fl->fl_end); (long long)conflock->fl.fl_start,
(long long)conflock->fl.fl_end);
conflock->caller = "somehost"; /* FIXME */ conflock->caller = "somehost"; /* FIXME */
conflock->oh.len = 0; /* don't return OH info */ conflock->oh.len = 0; /* don't return OH info */
conflock->fl = *fl; conflock->svid = conflock->fl.fl_pid;
return nlm_lck_denied; return nlm_lck_denied;
} }
...@@ -453,9 +509,12 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) ...@@ -453,9 +509,12 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
(long long)lock->fl.fl_end); (long long)lock->fl.fl_end);
down(&file->f_sema); down(&file->f_sema);
if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) block = nlmsvc_lookup_block(file, lock);
status = nlmsvc_delete_block(block, 1);
up(&file->f_sema); up(&file->f_sema);
if (block != NULL) {
status = nlmsvc_unlink_block(block);
nlmsvc_release_block(block);
}
return status ? nlm_lck_denied : nlm_granted; return status ? nlm_lck_denied : nlm_granted;
} }
...@@ -473,7 +532,7 @@ nlmsvc_notify_blocked(struct file_lock *fl) ...@@ -473,7 +532,7 @@ nlmsvc_notify_blocked(struct file_lock *fl)
dprintk("lockd: VFS unblock notification for block %p\n", fl); dprintk("lockd: VFS unblock notification for block %p\n", fl);
for (bp = &nlm_blocked; (block = *bp) != 0; bp = &block->b_next) { for (bp = &nlm_blocked; (block = *bp) != 0; bp = &block->b_next) {
if (nlm_compare_locks(&block->b_call.a_args.lock.fl, fl)) { if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
nlmsvc_insert_block(block, 0); nlmsvc_insert_block(block, 0);
svc_wake_up(block->b_daemon); svc_wake_up(block->b_daemon);
return; return;
...@@ -508,17 +567,13 @@ static void ...@@ -508,17 +567,13 @@ static void
nlmsvc_grant_blocked(struct nlm_block *block) nlmsvc_grant_blocked(struct nlm_block *block)
{ {
struct nlm_file *file = block->b_file; struct nlm_file *file = block->b_file;
struct nlm_lock *lock = &block->b_call.a_args.lock; struct nlm_lock *lock = &block->b_call->a_args.lock;
struct file_lock *conflock;
int error; int error;
dprintk("lockd: grant blocked lock %p\n", block); dprintk("lockd: grant blocked lock %p\n", block);
/* First thing is lock the file */
down(&file->f_sema);
/* Unlink block request from list */ /* Unlink block request from list */
nlmsvc_remove_block(block); nlmsvc_unlink_block(block);
/* If b_granted is true this means we've been here before. /* If b_granted is true this means we've been here before.
* Just retry the grant callback, possibly refreshing the RPC * Just retry the grant callback, possibly refreshing the RPC
...@@ -529,24 +584,21 @@ nlmsvc_grant_blocked(struct nlm_block *block) ...@@ -529,24 +584,21 @@ nlmsvc_grant_blocked(struct nlm_block *block)
} }
/* Try the lock operation again */ /* Try the lock operation again */
if ((conflock = posix_test_lock(file->f_file, &lock->fl)) != NULL) { lock->fl.fl_flags |= FL_SLEEP;
/* Bummer, we blocked again */ error = posix_lock_file(file->f_file, &lock->fl);
lock->fl.fl_flags &= ~FL_SLEEP;
switch (error) {
case 0:
break;
case -EAGAIN:
dprintk("lockd: lock still blocked\n"); dprintk("lockd: lock still blocked\n");
nlmsvc_insert_block(block, NLM_NEVER); nlmsvc_insert_block(block, NLM_NEVER);
posix_block_lock(conflock, &lock->fl);
up(&file->f_sema);
return; return;
} default:
/* Alright, no conflicting lock. Now lock it for real. If the
* following yields an error, this is most probably due to low
* memory. Retry the lock in a few seconds.
*/
if ((error = posix_lock_file(file->f_file, &lock->fl)) < 0) {
printk(KERN_WARNING "lockd: unexpected error %d in %s!\n", printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
-error, __FUNCTION__); -error, __FUNCTION__);
nlmsvc_insert_block(block, 10 * HZ); nlmsvc_insert_block(block, 10 * HZ);
up(&file->f_sema);
return; return;
} }
...@@ -554,17 +606,15 @@ nlmsvc_grant_blocked(struct nlm_block *block) ...@@ -554,17 +606,15 @@ nlmsvc_grant_blocked(struct nlm_block *block)
/* Lock was granted by VFS. */ /* Lock was granted by VFS. */
dprintk("lockd: GRANTing blocked lock.\n"); dprintk("lockd: GRANTing blocked lock.\n");
block->b_granted = 1; block->b_granted = 1;
block->b_incall = 1;
/* Schedule next grant callback in 30 seconds */ /* Schedule next grant callback in 30 seconds */
nlmsvc_insert_block(block, 30 * HZ); nlmsvc_insert_block(block, 30 * HZ);
/* Call the client */ /* Call the client */
nlm_get_host(block->b_call.a_host); kref_get(&block->b_count);
if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG, if (nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG,
&nlmsvc_grant_ops) < 0) &nlmsvc_grant_ops) < 0)
nlm_release_host(block->b_call.a_host); nlmsvc_release_block(block);
up(&file->f_sema);
} }
/* /*
...@@ -578,20 +628,10 @@ nlmsvc_grant_blocked(struct nlm_block *block) ...@@ -578,20 +628,10 @@ nlmsvc_grant_blocked(struct nlm_block *block)
static void nlmsvc_grant_callback(struct rpc_task *task, void *data) static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
{ {
struct nlm_rqst *call = data; struct nlm_rqst *call = data;
struct nlm_block *block; struct nlm_block *block = call->a_block;
unsigned long timeout; unsigned long timeout;
struct sockaddr_in *peer_addr = RPC_PEERADDR(task->tk_client);
dprintk("lockd: GRANT_MSG RPC callback\n"); dprintk("lockd: GRANT_MSG RPC callback\n");
dprintk("callback: looking for cookie %s, host (%u.%u.%u.%u)\n",
nlmdbg_cookie2a(&call->a_args.cookie),
NIPQUAD(peer_addr->sin_addr.s_addr));
if (!(block = nlmsvc_find_block(&call->a_args.cookie, peer_addr))) {
dprintk("lockd: no block for cookie %s, host (%u.%u.%u.%u)\n",
nlmdbg_cookie2a(&call->a_args.cookie),
NIPQUAD(peer_addr->sin_addr.s_addr));
return;
}
/* Technically, we should down the file semaphore here. Since we /* Technically, we should down the file semaphore here. Since we
* move the block towards the head of the queue only, no harm * move the block towards the head of the queue only, no harm
...@@ -608,13 +648,18 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data) ...@@ -608,13 +648,18 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
} }
nlmsvc_insert_block(block, timeout); nlmsvc_insert_block(block, timeout);
svc_wake_up(block->b_daemon); svc_wake_up(block->b_daemon);
block->b_incall = 0; }
void nlmsvc_grant_release(void *data)
{
struct nlm_rqst *call = data;
nlm_release_host(call->a_host); nlmsvc_release_block(call->a_block);
} }
static const struct rpc_call_ops nlmsvc_grant_ops = { static const struct rpc_call_ops nlmsvc_grant_ops = {
.rpc_call_done = nlmsvc_grant_callback, .rpc_call_done = nlmsvc_grant_callback,
.rpc_release = nlmsvc_grant_release,
}; };
/* /*
...@@ -634,25 +679,17 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status ...@@ -634,25 +679,17 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status
return; return;
file = block->b_file; file = block->b_file;
file->f_count++;
down(&file->f_sema);
block = nlmsvc_find_block(cookie, &rqstp->rq_addr);
if (block) { 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);
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. */
up(&file->f_sema); nlmsvc_unlink_block(block);
if (status == NLM_LCK_GRANTED)
nlmsvc_delete_block(block, 0);
else
nlmsvc_delete_block(block, 1);
} }
} }
nlm_release_file(file); nlmsvc_release_block(block);
} }
/* /*
...@@ -675,10 +712,12 @@ nlmsvc_retry_blocked(void) ...@@ -675,10 +712,12 @@ nlmsvc_retry_blocked(void)
break; break;
dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n", dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",
block, block->b_when, block->b_done); block, block->b_when, block->b_done);
kref_get(&block->b_count);
if (block->b_done) if (block->b_done)
nlmsvc_delete_block(block, 0); nlmsvc_unlink_block(block);
else else
nlmsvc_grant_blocked(block); nlmsvc_grant_blocked(block);
nlmsvc_release_block(block);
} }
if ((block = nlm_blocked) && block->b_when != NLM_NEVER) if ((block = nlm_blocked) && block->b_when != NLM_NEVER)
......
...@@ -22,10 +22,6 @@ ...@@ -22,10 +22,6 @@
#define NLMDBG_FACILITY NLMDBG_CLIENT #define NLMDBG_FACILITY NLMDBG_CLIENT
static u32 nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *);
static const struct rpc_call_ops nlmsvc_callback_ops;
#ifdef CONFIG_LOCKD_V4 #ifdef CONFIG_LOCKD_V4
static u32 static u32
cast_to_nlm(u32 status, u32 vers) cast_to_nlm(u32 status, u32 vers)
...@@ -261,84 +257,92 @@ nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -261,84 +257,92 @@ nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
return rpc_success; return rpc_success;
} }
/*
* This is the generic lockd callback for async RPC calls
*/
static void nlmsvc_callback_exit(struct rpc_task *task, void *data)
{
dprintk("lockd: %4d callback returned %d\n", task->tk_pid,
-task->tk_status);
}
static void nlmsvc_callback_release(void *data)
{
nlm_release_call(data);
}
static const struct rpc_call_ops nlmsvc_callback_ops = {
.rpc_call_done = nlmsvc_callback_exit,
.rpc_release = nlmsvc_callback_release,
};
/* /*
* `Async' versions of the above service routines. They aren't really, * `Async' versions of the above service routines. They aren't really,
* because we send the callback before the reply proper. I hope this * because we send the callback before the reply proper. I hope this
* doesn't break any clients. * doesn't break any clients.
*/ */
static int static int nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp,
nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp, int (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *))
void *resp)
{ {
struct nlm_res res; struct nlm_host *host;
u32 stat; struct nlm_rqst *call;
int stat;
dprintk("lockd: TEST_MSG called\n"); host = nlmsvc_lookup_host(rqstp);
memset(&res, 0, sizeof(res)); if (host == NULL)
return rpc_system_err;
if ((stat = nlmsvc_proc_test(rqstp, argp, &res)) == 0) call = nlm_alloc_call(host);
stat = nlmsvc_callback(rqstp, NLMPROC_TEST_RES, &res); if (call == NULL)
return rpc_system_err;
stat = func(rqstp, argp, &call->a_res);
if (stat != 0) {
nlm_release_call(call);
return stat; return stat;
}
call->a_flags = RPC_TASK_ASYNC;
if (nlm_async_reply(call, proc, &nlmsvc_callback_ops) < 0)
return rpc_system_err;
return rpc_success;
} }
static int static int nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp) void *resp)
{ {
struct nlm_res res; dprintk("lockd: TEST_MSG called\n");
u32 stat; return nlmsvc_callback(rqstp, NLMPROC_TEST_RES, argp, nlmsvc_proc_test);
}
static int nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp)
{
dprintk("lockd: LOCK_MSG called\n"); dprintk("lockd: LOCK_MSG called\n");
memset(&res, 0, sizeof(res)); return nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, argp, nlmsvc_proc_lock);
if ((stat = nlmsvc_proc_lock(rqstp, argp, &res)) == 0)
stat = nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, &res);
return stat;
} }
static int static int nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp) void *resp)
{ {
struct nlm_res res;
u32 stat;
dprintk("lockd: CANCEL_MSG called\n"); dprintk("lockd: CANCEL_MSG called\n");
memset(&res, 0, sizeof(res)); return nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, argp, nlmsvc_proc_cancel);
if ((stat = nlmsvc_proc_cancel(rqstp, argp, &res)) == 0)
stat = nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, &res);
return stat;
} }
static int static int
nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp) void *resp)
{ {
struct nlm_res res;
u32 stat;
dprintk("lockd: UNLOCK_MSG called\n"); dprintk("lockd: UNLOCK_MSG called\n");
memset(&res, 0, sizeof(res)); return nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, argp, nlmsvc_proc_unlock);
if ((stat = nlmsvc_proc_unlock(rqstp, argp, &res)) == 0)
stat = nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, &res);
return stat;
} }
static int static int
nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp, nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp) void *resp)
{ {
struct nlm_res res;
u32 stat;
dprintk("lockd: GRANTED_MSG called\n"); dprintk("lockd: GRANTED_MSG called\n");
memset(&res, 0, sizeof(res)); return nlmsvc_callback(rqstp, NLMPROC_GRANTED_RES, argp, nlmsvc_proc_granted);
if ((stat = nlmsvc_proc_granted(rqstp, argp, &res)) == 0)
stat = nlmsvc_callback(rqstp, NLMPROC_GRANTED_RES, &res);
return stat;
} }
/* /*
...@@ -496,55 +500,6 @@ nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, ...@@ -496,55 +500,6 @@ nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp,
return rpc_success; return rpc_success;
} }
/*
* This is the generic lockd callback for async RPC calls
*/
static u32
nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
{
struct nlm_host *host;
struct nlm_rqst *call;
if (!(call = nlmclnt_alloc_call()))
return rpc_system_err;
host = nlmclnt_lookup_host(&rqstp->rq_addr,
rqstp->rq_prot, rqstp->rq_vers);
if (!host) {
kfree(call);
return rpc_system_err;
}
call->a_flags = RPC_TASK_ASYNC;
call->a_host = host;
memcpy(&call->a_args, resp, sizeof(*resp));
if (nlmsvc_async_call(call, proc, &nlmsvc_callback_ops) < 0)
goto error;
return rpc_success;
error:
nlm_release_host(host);
kfree(call);
return rpc_system_err;
}
static void nlmsvc_callback_exit(struct rpc_task *task, void *data)
{
struct nlm_rqst *call = data;
if (task->tk_status < 0) {
dprintk("lockd: %4d callback failed (errno = %d)\n",
task->tk_pid, -task->tk_status);
}
nlm_release_host(call->a_host);
kfree(call);
}
static const struct rpc_call_ops nlmsvc_callback_ops = {
.rpc_call_done = nlmsvc_callback_exit,
};
/* /*
* NLM Server procedures. * NLM Server procedures.
*/ */
......
...@@ -88,7 +88,7 @@ nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, ...@@ -88,7 +88,7 @@ nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
* Traverse all shares for a given file (and host). * Traverse all shares for a given file (and host).
* NLM_ACT_CHECK is handled by nlmsvc_inspect_file. * NLM_ACT_CHECK is handled by nlmsvc_inspect_file.
*/ */
int void
nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, int action) nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, int action)
{ {
struct nlm_share *share, **shpp; struct nlm_share *share, **shpp;
...@@ -106,6 +106,4 @@ nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, int action) ...@@ -106,6 +106,4 @@ nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, int action)
} }
shpp = &share->s_next; shpp = &share->s_next;
} }
return 0;
} }
...@@ -182,7 +182,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, int action) ...@@ -182,7 +182,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, int action)
again: again:
file->f_locks = 0; file->f_locks = 0;
for (fl = inode->i_flock; fl; fl = fl->fl_next) { for (fl = inode->i_flock; fl; fl = fl->fl_next) {
if (!(fl->fl_flags & FL_LOCKD)) if (fl->fl_lmops != &nlmsvc_lock_operations)
continue; continue;
/* update current lock count */ /* update current lock count */
...@@ -224,9 +224,8 @@ nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, int action) ...@@ -224,9 +224,8 @@ nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, int action)
if (file->f_count || file->f_blocks || file->f_shares) if (file->f_count || file->f_blocks || file->f_shares)
return 1; return 1;
} else { } else {
if (nlmsvc_traverse_blocks(host, file, action) nlmsvc_traverse_blocks(host, file, action);
|| nlmsvc_traverse_shares(host, file, action)) nlmsvc_traverse_shares(host, file, action);
return 1;
} }
return nlm_traverse_locks(host, file, action); return nlm_traverse_locks(host, file, action);
} }
......
...@@ -131,10 +131,11 @@ nlm_decode_lock(u32 *p, struct nlm_lock *lock) ...@@ -131,10 +131,11 @@ nlm_decode_lock(u32 *p, struct nlm_lock *lock)
|| !(p = nlm_decode_fh(p, &lock->fh)) || !(p = nlm_decode_fh(p, &lock->fh))
|| !(p = nlm_decode_oh(p, &lock->oh))) || !(p = nlm_decode_oh(p, &lock->oh)))
return NULL; return NULL;
lock->svid = ntohl(*p++);
locks_init_lock(fl); locks_init_lock(fl);
fl->fl_owner = current->files; fl->fl_owner = current->files;
fl->fl_pid = ntohl(*p++); fl->fl_pid = (pid_t)lock->svid;
fl->fl_flags = FL_POSIX; fl->fl_flags = FL_POSIX;
fl->fl_type = F_RDLCK; /* as good as anything else */ fl->fl_type = F_RDLCK; /* as good as anything else */
start = ntohl(*p++); start = ntohl(*p++);
...@@ -174,7 +175,7 @@ nlm_encode_lock(u32 *p, struct nlm_lock *lock) ...@@ -174,7 +175,7 @@ nlm_encode_lock(u32 *p, struct nlm_lock *lock)
else else
len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
*p++ = htonl(fl->fl_pid); *p++ = htonl(lock->svid);
*p++ = htonl(start); *p++ = htonl(start);
*p++ = htonl(len); *p++ = htonl(len);
...@@ -197,7 +198,7 @@ nlm_encode_testres(u32 *p, struct nlm_res *resp) ...@@ -197,7 +198,7 @@ nlm_encode_testres(u32 *p, struct nlm_res *resp)
struct file_lock *fl = &resp->lock.fl; struct file_lock *fl = &resp->lock.fl;
*p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one; *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
*p++ = htonl(fl->fl_pid); *p++ = htonl(resp->lock.svid);
/* Encode owner handle. */ /* Encode owner handle. */
if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
...@@ -298,7 +299,8 @@ nlmsvc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) ...@@ -298,7 +299,8 @@ nlmsvc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
memset(lock, 0, sizeof(*lock)); memset(lock, 0, sizeof(*lock));
locks_init_lock(&lock->fl); locks_init_lock(&lock->fl);
lock->fl.fl_pid = ~(u32) 0; lock->svid = ~(u32) 0;
lock->fl.fl_pid = (pid_t)lock->svid;
if (!(p = nlm_decode_cookie(p, &argp->cookie)) if (!(p = nlm_decode_cookie(p, &argp->cookie))
|| !(p = xdr_decode_string_inplace(p, &lock->caller, || !(p = xdr_decode_string_inplace(p, &lock->caller,
...@@ -415,7 +417,8 @@ nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) ...@@ -415,7 +417,8 @@ nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
memset(&resp->lock, 0, sizeof(resp->lock)); memset(&resp->lock, 0, sizeof(resp->lock));
locks_init_lock(fl); locks_init_lock(fl);
excl = ntohl(*p++); excl = ntohl(*p++);
fl->fl_pid = ntohl(*p++); resp->lock.svid = ntohl(*p++);
fl->fl_pid = (pid_t)resp->lock.svid;
if (!(p = nlm_decode_oh(p, &resp->lock.oh))) if (!(p = nlm_decode_oh(p, &resp->lock.oh)))
return -EIO; return -EIO;
...@@ -543,7 +546,9 @@ nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) ...@@ -543,7 +546,9 @@ nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
.p_proc = NLMPROC_##proc, \ .p_proc = NLMPROC_##proc, \
.p_encode = (kxdrproc_t) nlmclt_encode_##argtype, \ .p_encode = (kxdrproc_t) nlmclt_encode_##argtype, \
.p_decode = (kxdrproc_t) nlmclt_decode_##restype, \ .p_decode = (kxdrproc_t) nlmclt_decode_##restype, \
.p_bufsiz = MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2 \ .p_bufsiz = MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2, \
.p_statidx = NLMPROC_##proc, \
.p_name = #proc, \
} }
static struct rpc_procinfo nlm_procedures[] = { static struct rpc_procinfo nlm_procedures[] = {
......
...@@ -130,10 +130,11 @@ nlm4_decode_lock(u32 *p, struct nlm_lock *lock) ...@@ -130,10 +130,11 @@ nlm4_decode_lock(u32 *p, struct nlm_lock *lock)
|| !(p = nlm4_decode_fh(p, &lock->fh)) || !(p = nlm4_decode_fh(p, &lock->fh))
|| !(p = nlm4_decode_oh(p, &lock->oh))) || !(p = nlm4_decode_oh(p, &lock->oh)))
return NULL; return NULL;
lock->svid = ntohl(*p++);
locks_init_lock(fl); locks_init_lock(fl);
fl->fl_owner = current->files; fl->fl_owner = current->files;
fl->fl_pid = ntohl(*p++); fl->fl_pid = (pid_t)lock->svid;
fl->fl_flags = FL_POSIX; fl->fl_flags = FL_POSIX;
fl->fl_type = F_RDLCK; /* as good as anything else */ fl->fl_type = F_RDLCK; /* as good as anything else */
p = xdr_decode_hyper(p, &start); p = xdr_decode_hyper(p, &start);
...@@ -167,7 +168,7 @@ nlm4_encode_lock(u32 *p, struct nlm_lock *lock) ...@@ -167,7 +168,7 @@ nlm4_encode_lock(u32 *p, struct nlm_lock *lock)
|| (fl->fl_end > NLM4_OFFSET_MAX && fl->fl_end != OFFSET_MAX)) || (fl->fl_end > NLM4_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
return NULL; return NULL;
*p++ = htonl(fl->fl_pid); *p++ = htonl(lock->svid);
start = loff_t_to_s64(fl->fl_start); start = loff_t_to_s64(fl->fl_start);
if (fl->fl_end == OFFSET_MAX) if (fl->fl_end == OFFSET_MAX)
...@@ -198,7 +199,7 @@ nlm4_encode_testres(u32 *p, struct nlm_res *resp) ...@@ -198,7 +199,7 @@ nlm4_encode_testres(u32 *p, struct nlm_res *resp)
struct file_lock *fl = &resp->lock.fl; struct file_lock *fl = &resp->lock.fl;
*p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one; *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
*p++ = htonl(fl->fl_pid); *p++ = htonl(resp->lock.svid);
/* Encode owner handle. */ /* Encode owner handle. */
if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
...@@ -212,8 +213,8 @@ nlm4_encode_testres(u32 *p, struct nlm_res *resp) ...@@ -212,8 +213,8 @@ nlm4_encode_testres(u32 *p, struct nlm_res *resp)
p = xdr_encode_hyper(p, start); p = xdr_encode_hyper(p, start);
p = xdr_encode_hyper(p, len); p = xdr_encode_hyper(p, len);
dprintk("xdr: encode_testres (status %d pid %d type %d start %Ld end %Ld)\n", dprintk("xdr: encode_testres (status %u pid %d type %d start %Ld end %Ld)\n",
resp->status, fl->fl_pid, fl->fl_type, resp->status, (int)resp->lock.svid, fl->fl_type,
(long long)fl->fl_start, (long long)fl->fl_end); (long long)fl->fl_start, (long long)fl->fl_end);
} }
...@@ -303,7 +304,8 @@ nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) ...@@ -303,7 +304,8 @@ nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
memset(lock, 0, sizeof(*lock)); memset(lock, 0, sizeof(*lock));
locks_init_lock(&lock->fl); locks_init_lock(&lock->fl);
lock->fl.fl_pid = ~(u32) 0; lock->svid = ~(u32) 0;
lock->fl.fl_pid = (pid_t)lock->svid;
if (!(p = nlm4_decode_cookie(p, &argp->cookie)) if (!(p = nlm4_decode_cookie(p, &argp->cookie))
|| !(p = xdr_decode_string_inplace(p, &lock->caller, || !(p = xdr_decode_string_inplace(p, &lock->caller,
...@@ -420,7 +422,8 @@ nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) ...@@ -420,7 +422,8 @@ nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
memset(&resp->lock, 0, sizeof(resp->lock)); memset(&resp->lock, 0, sizeof(resp->lock));
locks_init_lock(fl); locks_init_lock(fl);
excl = ntohl(*p++); excl = ntohl(*p++);
fl->fl_pid = ntohl(*p++); resp->lock.svid = ntohl(*p++);
fl->fl_pid = (pid_t)resp->lock.svid;
if (!(p = nlm4_decode_oh(p, &resp->lock.oh))) if (!(p = nlm4_decode_oh(p, &resp->lock.oh)))
return -EIO; return -EIO;
...@@ -548,7 +551,9 @@ nlm4clt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) ...@@ -548,7 +551,9 @@ nlm4clt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
.p_proc = NLMPROC_##proc, \ .p_proc = NLMPROC_##proc, \
.p_encode = (kxdrproc_t) nlm4clt_encode_##argtype, \ .p_encode = (kxdrproc_t) nlm4clt_encode_##argtype, \
.p_decode = (kxdrproc_t) nlm4clt_decode_##restype, \ .p_decode = (kxdrproc_t) nlm4clt_decode_##restype, \
.p_bufsiz = MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2 \ .p_bufsiz = MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2, \
.p_statidx = NLMPROC_##proc, \
.p_name = #proc, \
} }
static struct rpc_procinfo nlm4_procedures[] = { static struct rpc_procinfo nlm4_procedures[] = {
......
...@@ -139,10 +139,7 @@ int lease_break_time = 45; ...@@ -139,10 +139,7 @@ int lease_break_time = 45;
#define for_each_lock(inode, lockp) \ #define for_each_lock(inode, lockp) \
for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next) for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next)
LIST_HEAD(file_lock_list); static LIST_HEAD(file_lock_list);
EXPORT_SYMBOL(file_lock_list);
static LIST_HEAD(blocked_list); static LIST_HEAD(blocked_list);
static kmem_cache_t *filelock_cache; static kmem_cache_t *filelock_cache;
...@@ -153,6 +150,21 @@ static struct file_lock *locks_alloc_lock(void) ...@@ -153,6 +150,21 @@ static struct file_lock *locks_alloc_lock(void)
return kmem_cache_alloc(filelock_cache, SLAB_KERNEL); return kmem_cache_alloc(filelock_cache, SLAB_KERNEL);
} }
static void locks_release_private(struct file_lock *fl)
{
if (fl->fl_ops) {
if (fl->fl_ops->fl_release_private)
fl->fl_ops->fl_release_private(fl);
fl->fl_ops = NULL;
}
if (fl->fl_lmops) {
if (fl->fl_lmops->fl_release_private)
fl->fl_lmops->fl_release_private(fl);
fl->fl_lmops = NULL;
}
}
/* Free a lock which is not in use. */ /* Free a lock which is not in use. */
static void locks_free_lock(struct file_lock *fl) static void locks_free_lock(struct file_lock *fl)
{ {
...@@ -169,18 +181,7 @@ static void locks_free_lock(struct file_lock *fl) ...@@ -169,18 +181,7 @@ static void locks_free_lock(struct file_lock *fl)
if (!list_empty(&fl->fl_link)) if (!list_empty(&fl->fl_link))
panic("Attempting to free lock on active lock list"); panic("Attempting to free lock on active lock list");
if (fl->fl_ops) { locks_release_private(fl);
if (fl->fl_ops->fl_release_private)
fl->fl_ops->fl_release_private(fl);
fl->fl_ops = NULL;
}
if (fl->fl_lmops) {
if (fl->fl_lmops->fl_release_private)
fl->fl_lmops->fl_release_private(fl);
fl->fl_lmops = NULL;
}
kmem_cache_free(filelock_cache, fl); kmem_cache_free(filelock_cache, fl);
} }
...@@ -218,24 +219,46 @@ static void init_once(void *foo, kmem_cache_t *cache, unsigned long flags) ...@@ -218,24 +219,46 @@ static void init_once(void *foo, kmem_cache_t *cache, unsigned long flags)
locks_init_lock(lock); locks_init_lock(lock);
} }
static void locks_copy_private(struct file_lock *new, struct file_lock *fl)
{
if (fl->fl_ops) {
if (fl->fl_ops->fl_copy_lock)
fl->fl_ops->fl_copy_lock(new, fl);
new->fl_ops = fl->fl_ops;
}
if (fl->fl_lmops) {
if (fl->fl_lmops->fl_copy_lock)
fl->fl_lmops->fl_copy_lock(new, fl);
new->fl_lmops = fl->fl_lmops;
}
}
/* /*
* Initialize a new lock from an existing file_lock structure. * Initialize a new lock from an existing file_lock structure.
*/ */
void locks_copy_lock(struct file_lock *new, struct file_lock *fl) static void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl)
{ {
new->fl_owner = fl->fl_owner; new->fl_owner = fl->fl_owner;
new->fl_pid = fl->fl_pid; new->fl_pid = fl->fl_pid;
new->fl_file = fl->fl_file; new->fl_file = NULL;
new->fl_flags = fl->fl_flags; new->fl_flags = fl->fl_flags;
new->fl_type = fl->fl_type; new->fl_type = fl->fl_type;
new->fl_start = fl->fl_start; new->fl_start = fl->fl_start;
new->fl_end = fl->fl_end; new->fl_end = fl->fl_end;
new->fl_ops = NULL;
new->fl_lmops = NULL;
}
void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
{
locks_release_private(new);
__locks_copy_lock(new, fl);
new->fl_file = fl->fl_file;
new->fl_ops = fl->fl_ops; new->fl_ops = fl->fl_ops;
new->fl_lmops = fl->fl_lmops; new->fl_lmops = fl->fl_lmops;
if (fl->fl_ops && fl->fl_ops->fl_copy_lock)
fl->fl_ops->fl_copy_lock(new, fl); locks_copy_private(new, fl);
if (fl->fl_lmops && fl->fl_lmops->fl_copy_lock)
fl->fl_lmops->fl_copy_lock(new, fl);
} }
EXPORT_SYMBOL(locks_copy_lock); EXPORT_SYMBOL(locks_copy_lock);
...@@ -654,8 +677,9 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w ...@@ -654,8 +677,9 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w
return result; return result;
} }
struct file_lock * int
posix_test_lock(struct file *filp, struct file_lock *fl) posix_test_lock(struct file *filp, struct file_lock *fl,
struct file_lock *conflock)
{ {
struct file_lock *cfl; struct file_lock *cfl;
...@@ -666,9 +690,13 @@ posix_test_lock(struct file *filp, struct file_lock *fl) ...@@ -666,9 +690,13 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
if (posix_locks_conflict(cfl, fl)) if (posix_locks_conflict(cfl, fl))
break; break;
} }
if (cfl) {
__locks_copy_lock(conflock, cfl);
unlock_kernel(); unlock_kernel();
return 1;
return (cfl); }
unlock_kernel();
return 0;
} }
EXPORT_SYMBOL(posix_test_lock); EXPORT_SYMBOL(posix_test_lock);
...@@ -904,7 +932,8 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request) ...@@ -904,7 +932,8 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request)
fl->fl_start = request->fl_start; fl->fl_start = request->fl_start;
fl->fl_end = request->fl_end; fl->fl_end = request->fl_end;
fl->fl_type = request->fl_type; fl->fl_type = request->fl_type;
fl->fl_u = request->fl_u; locks_release_private(fl);
locks_copy_private(fl, request);
request = fl; request = fl;
added = 1; added = 1;
} }
...@@ -1544,7 +1573,7 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd) ...@@ -1544,7 +1573,7 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
*/ */
int fcntl_getlk(struct file *filp, struct flock __user *l) int fcntl_getlk(struct file *filp, struct flock __user *l)
{ {
struct file_lock *fl, file_lock; struct file_lock *fl, cfl, file_lock;
struct flock flock; struct flock flock;
int error; int error;
...@@ -1568,7 +1597,7 @@ int fcntl_getlk(struct file *filp, struct flock __user *l) ...@@ -1568,7 +1597,7 @@ int fcntl_getlk(struct file *filp, struct flock __user *l)
else else
fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock); fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
} else { } else {
fl = posix_test_lock(filp, &file_lock); fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL);
} }
flock.l_type = F_UNLCK; flock.l_type = F_UNLCK;
...@@ -1698,7 +1727,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -1698,7 +1727,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
*/ */
int fcntl_getlk64(struct file *filp, struct flock64 __user *l) int fcntl_getlk64(struct file *filp, struct flock64 __user *l)
{ {
struct file_lock *fl, file_lock; struct file_lock *fl, cfl, file_lock;
struct flock64 flock; struct flock64 flock;
int error; int error;
...@@ -1722,7 +1751,7 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l) ...@@ -1722,7 +1751,7 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l)
else else
fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock); fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
} else { } else {
fl = posix_test_lock(filp, &file_lock); fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL);
} }
flock.l_type = F_UNLCK; flock.l_type = F_UNLCK;
...@@ -1935,21 +1964,6 @@ void locks_remove_flock(struct file *filp) ...@@ -1935,21 +1964,6 @@ void locks_remove_flock(struct file *filp)
unlock_kernel(); unlock_kernel();
} }
/**
* posix_block_lock - blocks waiting for a file lock
* @blocker: the lock which is blocking
* @waiter: the lock which conflicts and has to wait
*
* lockd needs to block waiting for locks.
*/
void
posix_block_lock(struct file_lock *blocker, struct file_lock *waiter)
{
locks_insert_block(blocker, waiter);
}
EXPORT_SYMBOL(posix_block_lock);
/** /**
* posix_unblock_lock - stop waiting for a file lock * posix_unblock_lock - stop waiting for a file lock
* @filp: how the file was opened * @filp: how the file was opened
......
...@@ -399,6 +399,44 @@ struct seq_operations mounts_op = { ...@@ -399,6 +399,44 @@ struct seq_operations mounts_op = {
.show = show_vfsmnt .show = show_vfsmnt
}; };
static int show_vfsstat(struct seq_file *m, void *v)
{
struct vfsmount *mnt = v;
int err = 0;
/* device */
if (mnt->mnt_devname) {
seq_puts(m, "device ");
mangle(m, mnt->mnt_devname);
} else
seq_puts(m, "no device");
/* mount point */
seq_puts(m, " mounted on ");
seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
seq_putc(m, ' ');
/* file system type */
seq_puts(m, "with fstype ");
mangle(m, mnt->mnt_sb->s_type->name);
/* optional statistics */
if (mnt->mnt_sb->s_op->show_stats) {
seq_putc(m, ' ');
err = mnt->mnt_sb->s_op->show_stats(m, mnt);
}
seq_putc(m, '\n');
return err;
}
struct seq_operations mountstats_op = {
.start = m_start,
.next = m_next,
.stop = m_stop,
.show = show_vfsstat,
};
/** /**
* may_umount_tree - check if a mount tree is busy * may_umount_tree - check if a mount tree is busy
* @mnt: root of mount tree * @mnt: root of mount tree
......
...@@ -55,7 +55,12 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) ...@@ -55,7 +55,12 @@ static void nfs_callback_svc(struct svc_rqst *rqstp)
complete(&nfs_callback_info.started); complete(&nfs_callback_info.started);
while (nfs_callback_info.users != 0 || !signalled()) { for(;;) {
if (signalled()) {
if (nfs_callback_info.users == 0)
break;
flush_signals(current);
}
/* /*
* Listen for a request on the socket * Listen for a request on the socket
*/ */
...@@ -73,6 +78,7 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) ...@@ -73,6 +78,7 @@ static void nfs_callback_svc(struct svc_rqst *rqstp)
svc_process(serv, rqstp); svc_process(serv, rqstp);
} }
svc_exit_thread(rqstp);
nfs_callback_info.pid = 0; nfs_callback_info.pid = 0;
complete(&nfs_callback_info.stopped); complete(&nfs_callback_info.stopped);
unlock_kernel(); unlock_kernel();
...@@ -134,11 +140,13 @@ int nfs_callback_down(void) ...@@ -134,11 +140,13 @@ int nfs_callback_down(void)
lock_kernel(); lock_kernel();
down(&nfs_callback_sema); down(&nfs_callback_sema);
if (--nfs_callback_info.users || nfs_callback_info.pid == 0) nfs_callback_info.users--;
goto out; do {
kill_proc(nfs_callback_info.pid, SIGKILL, 1); if (nfs_callback_info.users != 0 || nfs_callback_info.pid == 0)
wait_for_completion(&nfs_callback_info.stopped); break;
out: if (kill_proc(nfs_callback_info.pid, SIGKILL, 1) < 0)
break;
} while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0);
up(&nfs_callback_sema); up(&nfs_callback_sema);
unlock_kernel(); unlock_kernel();
return ret; return ret;
......
...@@ -330,7 +330,7 @@ static unsigned encode_op_hdr(struct xdr_stream *xdr, uint32_t op, uint32_t res) ...@@ -330,7 +330,7 @@ static unsigned encode_op_hdr(struct xdr_stream *xdr, uint32_t op, uint32_t res)
static unsigned encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res) static unsigned encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res)
{ {
uint32_t *savep; uint32_t *savep = NULL;
unsigned status = res->status; unsigned status = res->status;
if (unlikely(status != 0)) if (unlikely(status != 0))
...@@ -358,23 +358,26 @@ static unsigned process_op(struct svc_rqst *rqstp, ...@@ -358,23 +358,26 @@ static unsigned process_op(struct svc_rqst *rqstp,
struct xdr_stream *xdr_in, void *argp, struct xdr_stream *xdr_in, void *argp,
struct xdr_stream *xdr_out, void *resp) struct xdr_stream *xdr_out, void *resp)
{ {
struct callback_op *op; struct callback_op *op = &callback_ops[0];
unsigned int op_nr; unsigned int op_nr = OP_CB_ILLEGAL;
unsigned int status = 0; unsigned int status = 0;
long maxlen; long maxlen;
unsigned res; unsigned res;
dprintk("%s: start\n", __FUNCTION__); dprintk("%s: start\n", __FUNCTION__);
status = decode_op_hdr(xdr_in, &op_nr); status = decode_op_hdr(xdr_in, &op_nr);
if (unlikely(status != 0)) { if (likely(status == 0)) {
op_nr = OP_CB_ILLEGAL; switch (op_nr) {
op = &callback_ops[0]; case OP_CB_GETATTR:
} else if (unlikely(op_nr != OP_CB_GETATTR && op_nr != OP_CB_RECALL)) { case OP_CB_RECALL:
op = &callback_ops[op_nr];
break;
default:
op_nr = OP_CB_ILLEGAL; op_nr = OP_CB_ILLEGAL;
op = &callback_ops[0]; op = &callback_ops[0];
status = htonl(NFS4ERR_OP_ILLEGAL); status = htonl(NFS4ERR_OP_ILLEGAL);
} else }
op = &callback_ops[op_nr]; }
maxlen = xdr_out->end - xdr_out->p; maxlen = xdr_out->end - xdr_out->p;
if (maxlen > 0 && maxlen < PAGE_SIZE) { if (maxlen > 0 && maxlen < PAGE_SIZE) {
...@@ -416,6 +419,7 @@ static int nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp ...@@ -416,6 +419,7 @@ static int nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp
decode_compound_hdr_arg(&xdr_in, &hdr_arg); decode_compound_hdr_arg(&xdr_in, &hdr_arg);
hdr_res.taglen = hdr_arg.taglen; hdr_res.taglen = hdr_arg.taglen;
hdr_res.tag = hdr_arg.tag; hdr_res.tag = hdr_arg.tag;
hdr_res.nops = NULL;
encode_compound_hdr_res(&xdr_out, &hdr_res); encode_compound_hdr_res(&xdr_out, &hdr_res);
for (;;) { for (;;) {
......
...@@ -421,3 +421,22 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp) ...@@ -421,3 +421,22 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp)
nfs_free_delegation(delegation); nfs_free_delegation(delegation);
} }
} }
int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
{
struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state;
struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_delegation *delegation;
int res = 0;
if (nfsi->delegation_state == 0)
return 0;
spin_lock(&clp->cl_lock);
delegation = nfsi->delegation;
if (delegation != NULL) {
memcpy(dst->data, delegation->stateid.data, sizeof(dst->data));
res = 1;
}
spin_unlock(&clp->cl_lock);
return res;
}
...@@ -41,6 +41,7 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp); ...@@ -41,6 +41,7 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp);
int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid);
int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state); int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state);
int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl);
int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
static inline int nfs_have_delegation(struct inode *inode, int flags) static inline int nfs_have_delegation(struct inode *inode, int flags)
{ {
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "nfs4_fs.h" #include "nfs4_fs.h"
#include "delegation.h" #include "delegation.h"
#include "iostat.h"
#define NFS_PARANOIA 1 #define NFS_PARANOIA 1
/* #define NFS_DEBUG_VERBOSE 1 */ /* #define NFS_DEBUG_VERBOSE 1 */
...@@ -129,6 +130,9 @@ nfs_opendir(struct inode *inode, struct file *filp) ...@@ -129,6 +130,9 @@ nfs_opendir(struct inode *inode, struct file *filp)
{ {
int res = 0; int res = 0;
dfprintk(VFS, "NFS: opendir(%s/%ld)\n",
inode->i_sb->s_id, inode->i_ino);
lock_kernel(); lock_kernel();
/* Call generic open code in order to cache credentials */ /* Call generic open code in order to cache credentials */
if (!res) if (!res)
...@@ -172,7 +176,9 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) ...@@ -172,7 +176,9 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
unsigned long timestamp; unsigned long timestamp;
int error; int error;
dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index); dfprintk(DIRCACHE, "NFS: %s: reading cookie %Lu into page %lu\n",
__FUNCTION__, (long long)desc->entry->cookie,
page->index);
again: again:
timestamp = jiffies; timestamp = jiffies;
...@@ -244,7 +250,8 @@ int find_dirent(nfs_readdir_descriptor_t *desc) ...@@ -244,7 +250,8 @@ int find_dirent(nfs_readdir_descriptor_t *desc)
status; status;
while((status = dir_decode(desc)) == 0) { while((status = dir_decode(desc)) == 0) {
dfprintk(VFS, "NFS: found cookie %Lu\n", (unsigned long long)entry->cookie); dfprintk(DIRCACHE, "NFS: %s: examining cookie %Lu\n",
__FUNCTION__, (unsigned long long)entry->cookie);
if (entry->prev_cookie == *desc->dir_cookie) if (entry->prev_cookie == *desc->dir_cookie)
break; break;
if (loop_count++ > 200) { if (loop_count++ > 200) {
...@@ -252,7 +259,6 @@ int find_dirent(nfs_readdir_descriptor_t *desc) ...@@ -252,7 +259,6 @@ int find_dirent(nfs_readdir_descriptor_t *desc)
schedule(); schedule();
} }
} }
dfprintk(VFS, "NFS: find_dirent() returns %d\n", status);
return status; return status;
} }
...@@ -276,7 +282,8 @@ int find_dirent_index(nfs_readdir_descriptor_t *desc) ...@@ -276,7 +282,8 @@ int find_dirent_index(nfs_readdir_descriptor_t *desc)
if (status) if (status)
break; break;
dfprintk(VFS, "NFS: found cookie %Lu at index %Ld\n", (unsigned long long)entry->cookie, desc->current_index); dfprintk(DIRCACHE, "NFS: found cookie %Lu at index %Ld\n",
(unsigned long long)entry->cookie, desc->current_index);
if (desc->file->f_pos == desc->current_index) { if (desc->file->f_pos == desc->current_index) {
*desc->dir_cookie = entry->cookie; *desc->dir_cookie = entry->cookie;
...@@ -288,7 +295,6 @@ int find_dirent_index(nfs_readdir_descriptor_t *desc) ...@@ -288,7 +295,6 @@ int find_dirent_index(nfs_readdir_descriptor_t *desc)
schedule(); schedule();
} }
} }
dfprintk(VFS, "NFS: find_dirent_index() returns %d\n", status);
return status; return status;
} }
...@@ -303,7 +309,9 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) ...@@ -303,7 +309,9 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc)
struct page *page; struct page *page;
int status; int status;
dfprintk(VFS, "NFS: find_dirent_page() searching directory page %ld\n", desc->page_index); dfprintk(DIRCACHE, "NFS: %s: searching page %ld for target %Lu\n",
__FUNCTION__, desc->page_index,
(long long) *desc->dir_cookie);
page = read_cache_page(inode->i_mapping, desc->page_index, page = read_cache_page(inode->i_mapping, desc->page_index,
(filler_t *)nfs_readdir_filler, desc); (filler_t *)nfs_readdir_filler, desc);
...@@ -324,7 +332,7 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) ...@@ -324,7 +332,7 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc)
if (status < 0) if (status < 0)
dir_page_release(desc); dir_page_release(desc);
out: out:
dfprintk(VFS, "NFS: find_dirent_page() returns %d\n", status); dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __FUNCTION__, status);
return status; return status;
read_error: read_error:
page_cache_release(page); page_cache_release(page);
...@@ -346,13 +354,15 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) ...@@ -346,13 +354,15 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
/* Always search-by-index from the beginning of the cache */ /* Always search-by-index from the beginning of the cache */
if (*desc->dir_cookie == 0) { if (*desc->dir_cookie == 0) {
dfprintk(VFS, "NFS: readdir_search_pagecache() searching for offset %Ld\n", (long long)desc->file->f_pos); dfprintk(DIRCACHE, "NFS: readdir_search_pagecache() searching for offset %Ld\n",
(long long)desc->file->f_pos);
desc->page_index = 0; desc->page_index = 0;
desc->entry->cookie = desc->entry->prev_cookie = 0; desc->entry->cookie = desc->entry->prev_cookie = 0;
desc->entry->eof = 0; desc->entry->eof = 0;
desc->current_index = 0; desc->current_index = 0;
} else } else
dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); dfprintk(DIRCACHE, "NFS: readdir_search_pagecache() searching for cookie %Lu\n",
(unsigned long long)*desc->dir_cookie);
for (;;) { for (;;) {
res = find_dirent_page(desc); res = find_dirent_page(desc);
...@@ -365,7 +375,8 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) ...@@ -365,7 +375,8 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
schedule(); schedule();
} }
} }
dfprintk(VFS, "NFS: readdir_search_pagecache() returned %d\n", res);
dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __FUNCTION__, res);
return res; return res;
} }
...@@ -390,7 +401,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, ...@@ -390,7 +401,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
int loop_count = 0, int loop_count = 0,
res; res;
dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)entry->cookie); dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n",
(unsigned long long)entry->cookie);
for(;;) { for(;;) {
unsigned d_type = DT_UNKNOWN; unsigned d_type = DT_UNKNOWN;
...@@ -427,7 +439,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, ...@@ -427,7 +439,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
dir_page_release(desc); dir_page_release(desc);
if (dentry != NULL) if (dentry != NULL)
dput(dentry); dput(dentry);
dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (unsigned long long)*desc->dir_cookie, res); dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n",
(unsigned long long)*desc->dir_cookie, res);
return res; return res;
} }
...@@ -453,7 +466,8 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, ...@@ -453,7 +466,8 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
struct page *page = NULL; struct page *page = NULL;
int status; int status;
dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
(unsigned long long)*desc->dir_cookie);
page = alloc_page(GFP_HIGHUSER); page = alloc_page(GFP_HIGHUSER);
if (!page) { if (!page) {
...@@ -485,7 +499,8 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, ...@@ -485,7 +499,8 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
desc->entry->cookie = desc->entry->prev_cookie = 0; desc->entry->cookie = desc->entry->prev_cookie = 0;
desc->entry->eof = 0; desc->entry->eof = 0;
out: out:
dfprintk(VFS, "NFS: uncached_readdir() returns %d\n", status); dfprintk(DIRCACHE, "NFS: %s: returns %d\n",
__FUNCTION__, status);
return status; return status;
out_release: out_release:
dir_page_release(desc); dir_page_release(desc);
...@@ -507,6 +522,11 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -507,6 +522,11 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct nfs_fattr fattr; struct nfs_fattr fattr;
long res; long res;
dfprintk(VFS, "NFS: readdir(%s/%s) starting at cookie %Lu\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
(long long)filp->f_pos);
nfs_inc_stats(inode, NFSIOS_VFSGETDENTS);
lock_kernel(); lock_kernel();
res = nfs_revalidate_inode(NFS_SERVER(inode), inode); res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
...@@ -566,9 +586,12 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -566,9 +586,12 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
} }
} }
unlock_kernel(); unlock_kernel();
if (res < 0) if (res > 0)
res = 0;
dfprintk(VFS, "NFS: readdir(%s/%s) returns %ld\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
res);
return res; return res;
return 0;
} }
loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
...@@ -599,6 +622,10 @@ loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) ...@@ -599,6 +622,10 @@ loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
*/ */
int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync) int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync)
{ {
dfprintk(VFS, "NFS: fsync_dir(%s/%s) datasync %d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
datasync);
return 0; return 0;
} }
...@@ -713,6 +740,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) ...@@ -713,6 +740,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
parent = dget_parent(dentry); parent = dget_parent(dentry);
lock_kernel(); lock_kernel();
dir = parent->d_inode; dir = parent->d_inode;
nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
inode = dentry->d_inode; inode = dentry->d_inode;
if (!inode) { if (!inode) {
...@@ -722,8 +750,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) ...@@ -722,8 +750,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
} }
if (is_bad_inode(inode)) { if (is_bad_inode(inode)) {
dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n", dfprintk(LOOKUPCACHE, "%s: %s/%s has dud inode\n",
dentry->d_parent->d_name.name, dentry->d_name.name); __FUNCTION__, dentry->d_parent->d_name.name,
dentry->d_name.name);
goto out_bad; goto out_bad;
} }
...@@ -755,6 +784,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) ...@@ -755,6 +784,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
out_valid: out_valid:
unlock_kernel(); unlock_kernel();
dput(parent); dput(parent);
dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is valid\n",
__FUNCTION__, dentry->d_parent->d_name.name,
dentry->d_name.name);
return 1; return 1;
out_zap_parent: out_zap_parent:
nfs_zap_caches(dir); nfs_zap_caches(dir);
...@@ -771,6 +803,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) ...@@ -771,6 +803,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
d_drop(dentry); d_drop(dentry);
unlock_kernel(); unlock_kernel();
dput(parent); dput(parent);
dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n",
__FUNCTION__, dentry->d_parent->d_name.name,
dentry->d_name.name);
return 0; return 0;
} }
...@@ -844,6 +879,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru ...@@ -844,6 +879,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
dfprintk(VFS, "NFS: lookup(%s/%s)\n", dfprintk(VFS, "NFS: lookup(%s/%s)\n",
dentry->d_parent->d_name.name, dentry->d_name.name); dentry->d_parent->d_name.name, dentry->d_name.name);
nfs_inc_stats(dir, NFSIOS_VFSLOOKUP);
res = ERR_PTR(-ENAMETOOLONG); res = ERR_PTR(-ENAMETOOLONG);
if (dentry->d_name.len > NFS_SERVER(dir)->namelen) if (dentry->d_name.len > NFS_SERVER(dir)->namelen)
...@@ -865,9 +901,9 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru ...@@ -865,9 +901,9 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
res = ERR_PTR(error); res = ERR_PTR(error);
goto out_unlock; goto out_unlock;
} }
res = ERR_PTR(-EACCES);
inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr); inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);
if (!inode) res = (struct dentry *)inode;
if (IS_ERR(res))
goto out_unlock; goto out_unlock;
no_entry: no_entry:
res = d_add_unique(dentry, inode); res = d_add_unique(dentry, inode);
...@@ -912,6 +948,9 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry ...@@ -912,6 +948,9 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
struct dentry *res = NULL; struct dentry *res = NULL;
int error; int error;
dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n",
dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
/* Check that we are indeed trying to open this file */ /* Check that we are indeed trying to open this file */
if (!is_atomic_open(dir, nd)) if (!is_atomic_open(dir, nd))
goto no_open; goto no_open;
...@@ -1057,7 +1096,7 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc) ...@@ -1057,7 +1096,7 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
return NULL; return NULL;
dentry->d_op = NFS_PROTO(dir)->dentry_ops; dentry->d_op = NFS_PROTO(dir)->dentry_ops;
inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr);
if (!inode) { if (IS_ERR(inode)) {
dput(dentry); dput(dentry);
return NULL; return NULL;
} }
...@@ -1095,9 +1134,9 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, ...@@ -1095,9 +1134,9 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
if (error < 0) if (error < 0)
goto out_err; goto out_err;
} }
error = -ENOMEM;
inode = nfs_fhget(dentry->d_sb, fhandle, fattr); inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
if (inode == NULL) error = PTR_ERR(inode);
if (IS_ERR(inode))
goto out_err; goto out_err;
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
return 0; return 0;
...@@ -1119,8 +1158,8 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, ...@@ -1119,8 +1158,8 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
int error; int error;
int open_flags = 0; int open_flags = 0;
dfprintk(VFS, "NFS: create(%s/%ld, %s\n", dir->i_sb->s_id, dfprintk(VFS, "NFS: create(%s/%ld), %s\n",
dir->i_ino, dentry->d_name.name); dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
attr.ia_mode = mode; attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE; attr.ia_valid = ATTR_MODE;
...@@ -1153,8 +1192,8 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) ...@@ -1153,8 +1192,8 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
struct iattr attr; struct iattr attr;
int status; int status;
dfprintk(VFS, "NFS: mknod(%s/%ld, %s\n", dir->i_sb->s_id, dfprintk(VFS, "NFS: mknod(%s/%ld), %s\n",
dir->i_ino, dentry->d_name.name); dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
if (!new_valid_dev(rdev)) if (!new_valid_dev(rdev))
return -EINVAL; return -EINVAL;
...@@ -1186,8 +1225,8 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -1186,8 +1225,8 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
struct iattr attr; struct iattr attr;
int error; int error;
dfprintk(VFS, "NFS: mkdir(%s/%ld, %s\n", dir->i_sb->s_id, dfprintk(VFS, "NFS: mkdir(%s/%ld), %s\n",
dir->i_ino, dentry->d_name.name); dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
attr.ia_valid = ATTR_MODE; attr.ia_valid = ATTR_MODE;
attr.ia_mode = mode | S_IFDIR; attr.ia_mode = mode | S_IFDIR;
...@@ -1212,8 +1251,8 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -1212,8 +1251,8 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
{ {
int error; int error;
dfprintk(VFS, "NFS: rmdir(%s/%ld, %s\n", dir->i_sb->s_id, dfprintk(VFS, "NFS: rmdir(%s/%ld), %s\n",
dir->i_ino, dentry->d_name.name); dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
lock_kernel(); lock_kernel();
nfs_begin_data_update(dir); nfs_begin_data_update(dir);
...@@ -1241,6 +1280,7 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry) ...@@ -1241,6 +1280,7 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_parent->d_name.name, dentry->d_name.name,
atomic_read(&dentry->d_count)); atomic_read(&dentry->d_count));
nfs_inc_stats(dir, NFSIOS_SILLYRENAME);
#ifdef NFS_PARANOIA #ifdef NFS_PARANOIA
if (!dentry->d_inode) if (!dentry->d_inode)
...@@ -1268,7 +1308,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name); ...@@ -1268,7 +1308,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
sillycounter++; sillycounter++;
sprintf(suffix, "%*.*x", countersize, countersize, sillycounter); sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);
dfprintk(VFS, "trying to rename %s to %s\n", dfprintk(VFS, "NFS: trying to rename %s to %s\n",
dentry->d_name.name, silly); dentry->d_name.name, silly);
sdentry = lookup_one_len(silly, dentry->d_parent, slen); sdentry = lookup_one_len(silly, dentry->d_parent, slen);
...@@ -1640,6 +1680,8 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) ...@@ -1640,6 +1680,8 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
struct rpc_cred *cred; struct rpc_cred *cred;
int res = 0; int res = 0;
nfs_inc_stats(inode, NFSIOS_VFSACCESS);
if (mask == 0) if (mask == 0)
goto out; goto out;
/* Is this sys_access() ? */ /* Is this sys_access() ? */
...@@ -1679,13 +1721,15 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) ...@@ -1679,13 +1721,15 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
res = PTR_ERR(cred); res = PTR_ERR(cred);
unlock_kernel(); unlock_kernel();
out: out:
dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n",
inode->i_sb->s_id, inode->i_ino, mask, res);
return res; return res;
out_notsup: out_notsup:
res = nfs_revalidate_inode(NFS_SERVER(inode), inode); res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
if (res == 0) if (res == 0)
res = generic_permission(inode, mask, NULL); res = generic_permission(inode, mask, NULL);
unlock_kernel(); unlock_kernel();
return res; goto out;
} }
/* /*
......
此差异已折叠。
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <asm/system.h> #include <asm/system.h>
#include "delegation.h" #include "delegation.h"
#include "iostat.h"
#define NFSDBG_FACILITY NFSDBG_FILE #define NFSDBG_FACILITY NFSDBG_FILE
...@@ -102,18 +103,15 @@ static int nfs_check_flags(int flags) ...@@ -102,18 +103,15 @@ static int nfs_check_flags(int flags)
static int static int
nfs_file_open(struct inode *inode, struct file *filp) nfs_file_open(struct inode *inode, struct file *filp)
{ {
struct nfs_server *server = NFS_SERVER(inode);
int (*open)(struct inode *, struct file *);
int res; int res;
res = nfs_check_flags(filp->f_flags); res = nfs_check_flags(filp->f_flags);
if (res) if (res)
return res; return res;
nfs_inc_stats(inode, NFSIOS_VFSOPEN);
lock_kernel(); lock_kernel();
/* Do NFSv4 open() call */ res = NFS_SERVER(inode)->rpc_ops->file_open(inode, filp);
if ((open = server->rpc_ops->file_open) != NULL)
res = open(inode, filp);
unlock_kernel(); unlock_kernel();
return res; return res;
} }
...@@ -124,6 +122,7 @@ nfs_file_release(struct inode *inode, struct file *filp) ...@@ -124,6 +122,7 @@ nfs_file_release(struct inode *inode, struct file *filp)
/* Ensure that dirty pages are flushed out with the right creds */ /* Ensure that dirty pages are flushed out with the right creds */
if (filp->f_mode & FMODE_WRITE) if (filp->f_mode & FMODE_WRITE)
filemap_fdatawrite(filp->f_mapping); filemap_fdatawrite(filp->f_mapping);
nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
return NFS_PROTO(inode)->file_release(inode, filp); return NFS_PROTO(inode)->file_release(inode, filp);
} }
...@@ -199,6 +198,7 @@ nfs_file_flush(struct file *file) ...@@ -199,6 +198,7 @@ nfs_file_flush(struct file *file)
if ((file->f_mode & FMODE_WRITE) == 0) if ((file->f_mode & FMODE_WRITE) == 0)
return 0; return 0;
nfs_inc_stats(inode, NFSIOS_VFSFLUSH);
lock_kernel(); lock_kernel();
/* Ensure that data+attribute caches are up to date after close() */ /* Ensure that data+attribute caches are up to date after close() */
status = nfs_wb_all(inode); status = nfs_wb_all(inode);
...@@ -229,6 +229,7 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos) ...@@ -229,6 +229,7 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos)
(unsigned long) count, (unsigned long) pos); (unsigned long) count, (unsigned long) pos);
result = nfs_revalidate_file(inode, iocb->ki_filp); result = nfs_revalidate_file(inode, iocb->ki_filp);
nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, count);
if (!result) if (!result)
result = generic_file_aio_read(iocb, buf, count, pos); result = generic_file_aio_read(iocb, buf, count, pos);
return result; return result;
...@@ -282,6 +283,7 @@ nfs_fsync(struct file *file, struct dentry *dentry, int datasync) ...@@ -282,6 +283,7 @@ nfs_fsync(struct file *file, struct dentry *dentry, int datasync)
dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
lock_kernel(); lock_kernel();
status = nfs_wb_all(inode); status = nfs_wb_all(inode);
if (!status) { if (!status) {
...@@ -316,6 +318,17 @@ static int nfs_commit_write(struct file *file, struct page *page, unsigned offse ...@@ -316,6 +318,17 @@ static int nfs_commit_write(struct file *file, struct page *page, unsigned offse
return status; return status;
} }
static int nfs_invalidate_page(struct page *page, unsigned long offset)
{
/* FIXME: we really should cancel any unstarted writes on this page */
return 1;
}
static int nfs_release_page(struct page *page, gfp_t gfp)
{
return !nfs_wb_page(page->mapping->host, page);
}
struct address_space_operations nfs_file_aops = { struct address_space_operations nfs_file_aops = {
.readpage = nfs_readpage, .readpage = nfs_readpage,
.readpages = nfs_readpages, .readpages = nfs_readpages,
...@@ -324,6 +337,8 @@ struct address_space_operations nfs_file_aops = { ...@@ -324,6 +337,8 @@ struct address_space_operations nfs_file_aops = {
.writepages = nfs_writepages, .writepages = nfs_writepages,
.prepare_write = nfs_prepare_write, .prepare_write = nfs_prepare_write,
.commit_write = nfs_commit_write, .commit_write = nfs_commit_write,
.invalidatepage = nfs_invalidate_page,
.releasepage = nfs_release_page,
#ifdef CONFIG_NFS_DIRECTIO #ifdef CONFIG_NFS_DIRECTIO
.direct_IO = nfs_direct_IO, .direct_IO = nfs_direct_IO,
#endif #endif
...@@ -365,6 +380,7 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t ...@@ -365,6 +380,7 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t
if (!count) if (!count)
goto out; goto out;
nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count);
result = generic_file_aio_write(iocb, buf, count, pos); result = generic_file_aio_write(iocb, buf, count, pos);
out: out:
return result; return result;
...@@ -376,15 +392,17 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t ...@@ -376,15 +392,17 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t
static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
{ {
struct file_lock *cfl; struct file_lock cfl;
struct inode *inode = filp->f_mapping->host; struct inode *inode = filp->f_mapping->host;
int status = 0; int status = 0;
lock_kernel(); lock_kernel();
/* Try local locking first */ /* Try local locking first */
cfl = posix_test_lock(filp, fl); if (posix_test_lock(filp, fl, &cfl)) {
if (cfl != NULL) { fl->fl_start = cfl.fl_start;
locks_copy_lock(fl, cfl); fl->fl_end = cfl.fl_end;
fl->fl_type = cfl.fl_type;
fl->fl_pid = cfl.fl_pid;
goto out; goto out;
} }
...@@ -425,10 +443,8 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl) ...@@ -425,10 +443,8 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl)
static int do_unlk(struct file *filp, int cmd, struct file_lock *fl) static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
{ {
struct inode *inode = filp->f_mapping->host; struct inode *inode = filp->f_mapping->host;
sigset_t oldset;
int status; int status;
rpc_clnt_sigmask(NFS_CLIENT(inode), &oldset);
/* /*
* Flush all pending writes before doing anything * Flush all pending writes before doing anything
* with locks.. * with locks..
...@@ -446,17 +462,14 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl) ...@@ -446,17 +462,14 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
else else
status = do_vfs_lock(filp, fl); status = do_vfs_lock(filp, fl);
unlock_kernel(); unlock_kernel();
rpc_clnt_sigunmask(NFS_CLIENT(inode), &oldset);
return status; return status;
} }
static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
{ {
struct inode *inode = filp->f_mapping->host; struct inode *inode = filp->f_mapping->host;
sigset_t oldset;
int status; int status;
rpc_clnt_sigmask(NFS_CLIENT(inode), &oldset);
/* /*
* Flush all pending writes before doing anything * Flush all pending writes before doing anything
* with locks.. * with locks..
...@@ -489,7 +502,6 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) ...@@ -489,7 +502,6 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
nfs_sync_mapping(filp->f_mapping); nfs_sync_mapping(filp->f_mapping);
nfs_zap_caches(inode); nfs_zap_caches(inode);
out: out:
rpc_clnt_sigunmask(NFS_CLIENT(inode), &oldset);
return status; return status;
} }
...@@ -504,9 +516,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -504,9 +516,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
inode->i_sb->s_id, inode->i_ino, inode->i_sb->s_id, inode->i_ino,
fl->fl_type, fl->fl_flags, fl->fl_type, fl->fl_flags,
(long long)fl->fl_start, (long long)fl->fl_end); (long long)fl->fl_start, (long long)fl->fl_end);
nfs_inc_stats(inode, NFSIOS_VFSLOCK);
if (!inode)
return -EINVAL;
/* No mandatory locks over NFS */ /* No mandatory locks over NFS */
if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
...@@ -531,9 +541,6 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -531,9 +541,6 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
inode->i_sb->s_id, inode->i_ino, inode->i_sb->s_id, inode->i_ino,
fl->fl_type, fl->fl_flags); fl->fl_type, fl->fl_flags);
if (!inode)
return -EINVAL;
/* /*
* No BSD flocks over NFS allowed. * No BSD flocks over NFS allowed.
* Note: we could try to fake a POSIX lock request here by * Note: we could try to fake a POSIX lock request here by
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -74,8 +75,8 @@ struct idmap { ...@@ -74,8 +75,8 @@ struct idmap {
struct dentry *idmap_dentry; struct dentry *idmap_dentry;
wait_queue_head_t idmap_wq; wait_queue_head_t idmap_wq;
struct idmap_msg idmap_im; struct idmap_msg idmap_im;
struct semaphore idmap_lock; /* Serializes upcalls */ struct mutex idmap_lock; /* Serializes upcalls */
struct semaphore idmap_im_lock; /* Protects the hashtable */ struct mutex idmap_im_lock; /* Protects the hashtable */
struct idmap_hashtable idmap_user_hash; struct idmap_hashtable idmap_user_hash;
struct idmap_hashtable idmap_group_hash; struct idmap_hashtable idmap_group_hash;
}; };
...@@ -101,11 +102,9 @@ nfs_idmap_new(struct nfs4_client *clp) ...@@ -101,11 +102,9 @@ nfs_idmap_new(struct nfs4_client *clp)
if (clp->cl_idmap != NULL) if (clp->cl_idmap != NULL)
return; return;
if ((idmap = kmalloc(sizeof(*idmap), GFP_KERNEL)) == NULL) if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL)
return; return;
memset(idmap, 0, sizeof(*idmap));
snprintf(idmap->idmap_path, sizeof(idmap->idmap_path), snprintf(idmap->idmap_path, sizeof(idmap->idmap_path),
"%s/idmap", clp->cl_rpcclient->cl_pathname); "%s/idmap", clp->cl_rpcclient->cl_pathname);
...@@ -116,8 +115,8 @@ nfs_idmap_new(struct nfs4_client *clp) ...@@ -116,8 +115,8 @@ nfs_idmap_new(struct nfs4_client *clp)
return; return;
} }
init_MUTEX(&idmap->idmap_lock); mutex_init(&idmap->idmap_lock);
init_MUTEX(&idmap->idmap_im_lock); mutex_init(&idmap->idmap_im_lock);
init_waitqueue_head(&idmap->idmap_wq); init_waitqueue_head(&idmap->idmap_wq);
idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER; idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER;
idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP;
...@@ -132,6 +131,8 @@ nfs_idmap_delete(struct nfs4_client *clp) ...@@ -132,6 +131,8 @@ nfs_idmap_delete(struct nfs4_client *clp)
if (!idmap) if (!idmap)
return; return;
dput(idmap->idmap_dentry);
idmap->idmap_dentry = NULL;
rpc_unlink(idmap->idmap_path); rpc_unlink(idmap->idmap_path);
clp->cl_idmap = NULL; clp->cl_idmap = NULL;
kfree(idmap); kfree(idmap);
...@@ -232,8 +233,8 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, ...@@ -232,8 +233,8 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h,
if (namelen >= IDMAP_NAMESZ) if (namelen >= IDMAP_NAMESZ)
return -EINVAL; return -EINVAL;
down(&idmap->idmap_lock); mutex_lock(&idmap->idmap_lock);
down(&idmap->idmap_im_lock); mutex_lock(&idmap->idmap_im_lock);
he = idmap_lookup_name(h, name, namelen); he = idmap_lookup_name(h, name, namelen);
if (he != NULL) { if (he != NULL) {
...@@ -259,11 +260,11 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, ...@@ -259,11 +260,11 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h,
} }
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
up(&idmap->idmap_im_lock); mutex_unlock(&idmap->idmap_im_lock);
schedule(); schedule();
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
remove_wait_queue(&idmap->idmap_wq, &wq); remove_wait_queue(&idmap->idmap_wq, &wq);
down(&idmap->idmap_im_lock); mutex_lock(&idmap->idmap_im_lock);
if (im->im_status & IDMAP_STATUS_SUCCESS) { if (im->im_status & IDMAP_STATUS_SUCCESS) {
*id = im->im_id; *id = im->im_id;
...@@ -272,8 +273,8 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, ...@@ -272,8 +273,8 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h,
out: out:
memset(im, 0, sizeof(*im)); memset(im, 0, sizeof(*im));
up(&idmap->idmap_im_lock); mutex_unlock(&idmap->idmap_im_lock);
up(&idmap->idmap_lock); mutex_unlock(&idmap->idmap_lock);
return (ret); return (ret);
} }
...@@ -293,8 +294,8 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, ...@@ -293,8 +294,8 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h,
im = &idmap->idmap_im; im = &idmap->idmap_im;
down(&idmap->idmap_lock); mutex_lock(&idmap->idmap_lock);
down(&idmap->idmap_im_lock); mutex_lock(&idmap->idmap_im_lock);
he = idmap_lookup_id(h, id); he = idmap_lookup_id(h, id);
if (he != 0) { if (he != 0) {
...@@ -320,11 +321,11 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, ...@@ -320,11 +321,11 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h,
} }
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
up(&idmap->idmap_im_lock); mutex_unlock(&idmap->idmap_im_lock);
schedule(); schedule();
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
remove_wait_queue(&idmap->idmap_wq, &wq); remove_wait_queue(&idmap->idmap_wq, &wq);
down(&idmap->idmap_im_lock); mutex_lock(&idmap->idmap_im_lock);
if (im->im_status & IDMAP_STATUS_SUCCESS) { if (im->im_status & IDMAP_STATUS_SUCCESS) {
if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0) if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0)
...@@ -335,8 +336,8 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, ...@@ -335,8 +336,8 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h,
out: out:
memset(im, 0, sizeof(*im)); memset(im, 0, sizeof(*im));
up(&idmap->idmap_im_lock); mutex_unlock(&idmap->idmap_im_lock);
up(&idmap->idmap_lock); mutex_unlock(&idmap->idmap_lock);
return ret; return ret;
} }
...@@ -380,7 +381,7 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) ...@@ -380,7 +381,7 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
if (copy_from_user(&im_in, src, mlen) != 0) if (copy_from_user(&im_in, src, mlen) != 0)
return (-EFAULT); return (-EFAULT);
down(&idmap->idmap_im_lock); mutex_lock(&idmap->idmap_im_lock);
ret = mlen; ret = mlen;
im->im_status = im_in.im_status; im->im_status = im_in.im_status;
...@@ -440,7 +441,7 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) ...@@ -440,7 +441,7 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id); idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id);
ret = mlen; ret = mlen;
out: out:
up(&idmap->idmap_im_lock); mutex_unlock(&idmap->idmap_im_lock);
return ret; return ret;
} }
...@@ -452,10 +453,10 @@ idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) ...@@ -452,10 +453,10 @@ idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
if (msg->errno >= 0) if (msg->errno >= 0)
return; return;
down(&idmap->idmap_im_lock); mutex_lock(&idmap->idmap_im_lock);
im->im_status = IDMAP_STATUS_LOOKUPFAIL; im->im_status = IDMAP_STATUS_LOOKUPFAIL;
wake_up(&idmap->idmap_wq); wake_up(&idmap->idmap_wq);
up(&idmap->idmap_im_lock); mutex_unlock(&idmap->idmap_im_lock);
} }
/* /*
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/unistd.h> #include <linux/unistd.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/stats.h> #include <linux/sunrpc/stats.h>
#include <linux/sunrpc/metrics.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfs_mount.h> #include <linux/nfs_mount.h>
#include <linux/nfs4_mount.h> #include <linux/nfs4_mount.h>
...@@ -42,6 +43,7 @@ ...@@ -42,6 +43,7 @@
#include "nfs4_fs.h" #include "nfs4_fs.h"
#include "callback.h" #include "callback.h"
#include "delegation.h" #include "delegation.h"
#include "iostat.h"
#define NFSDBG_FACILITY NFSDBG_VFS #define NFSDBG_FACILITY NFSDBG_VFS
#define NFS_PARANOIA 1 #define NFS_PARANOIA 1
...@@ -65,6 +67,7 @@ static void nfs_clear_inode(struct inode *); ...@@ -65,6 +67,7 @@ static void nfs_clear_inode(struct inode *);
static void nfs_umount_begin(struct super_block *); static void nfs_umount_begin(struct super_block *);
static int nfs_statfs(struct super_block *, struct kstatfs *); static int nfs_statfs(struct super_block *, struct kstatfs *);
static int nfs_show_options(struct seq_file *, struct vfsmount *); static int nfs_show_options(struct seq_file *, struct vfsmount *);
static int nfs_show_stats(struct seq_file *, struct vfsmount *);
static void nfs_zap_acl_cache(struct inode *); static void nfs_zap_acl_cache(struct inode *);
static struct rpc_program nfs_program; static struct rpc_program nfs_program;
...@@ -78,6 +81,7 @@ static struct super_operations nfs_sops = { ...@@ -78,6 +81,7 @@ static struct super_operations nfs_sops = {
.clear_inode = nfs_clear_inode, .clear_inode = nfs_clear_inode,
.umount_begin = nfs_umount_begin, .umount_begin = nfs_umount_begin,
.show_options = nfs_show_options, .show_options = nfs_show_options,
.show_stats = nfs_show_stats,
}; };
/* /*
...@@ -133,7 +137,7 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr) ...@@ -133,7 +137,7 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
static int static int
nfs_write_inode(struct inode *inode, int sync) nfs_write_inode(struct inode *inode, int sync)
{ {
int flags = sync ? FLUSH_WAIT : 0; int flags = sync ? FLUSH_SYNC : 0;
int ret; int ret;
ret = nfs_commit_inode(inode, flags); ret = nfs_commit_inode(inode, flags);
...@@ -237,7 +241,6 @@ static struct inode * ...@@ -237,7 +241,6 @@ static struct inode *
nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo) nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo)
{ {
struct nfs_server *server = NFS_SB(sb); struct nfs_server *server = NFS_SB(sb);
struct inode *rooti;
int error; int error;
error = server->rpc_ops->getroot(server, rootfh, fsinfo); error = server->rpc_ops->getroot(server, rootfh, fsinfo);
...@@ -246,10 +249,7 @@ nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *f ...@@ -246,10 +249,7 @@ nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *f
return ERR_PTR(error); return ERR_PTR(error);
} }
rooti = nfs_fhget(sb, rootfh, fsinfo->fattr); return nfs_fhget(sb, rootfh, fsinfo->fattr);
if (!rooti)
return ERR_PTR(-ENOMEM);
return rooti;
} }
/* /*
...@@ -277,6 +277,10 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) ...@@ -277,6 +277,10 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
sb->s_magic = NFS_SUPER_MAGIC; sb->s_magic = NFS_SUPER_MAGIC;
server->io_stats = nfs_alloc_iostats();
if (server->io_stats == NULL)
return -ENOMEM;
root_inode = nfs_get_root(sb, &server->fh, &fsinfo); root_inode = nfs_get_root(sb, &server->fh, &fsinfo);
/* Did getting the root inode fail? */ /* Did getting the root inode fail? */
if (IS_ERR(root_inode)) { if (IS_ERR(root_inode)) {
...@@ -290,6 +294,9 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) ...@@ -290,6 +294,9 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
} }
sb->s_root->d_op = server->rpc_ops->dentry_ops; sb->s_root->d_op = server->rpc_ops->dentry_ops;
/* mount time stamp, in seconds */
server->mount_time = jiffies;
/* Get some general file system info */ /* Get some general file system info */
if (server->namelen == 0 && if (server->namelen == 0 &&
server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0) server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
...@@ -396,6 +403,9 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) ...@@ -396,6 +403,9 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data)
nfs_init_timeout_values(&timeparms, proto, data->timeo, data->retrans); nfs_init_timeout_values(&timeparms, proto, data->timeo, data->retrans);
server->retrans_timeo = timeparms.to_initval;
server->retrans_count = timeparms.to_retries;
/* create transport and client */ /* create transport and client */
xprt = xprt_create_proto(proto, &server->addr, &timeparms); xprt = xprt_create_proto(proto, &server->addr, &timeparms);
if (IS_ERR(xprt)) { if (IS_ERR(xprt)) {
...@@ -579,7 +589,7 @@ nfs_statfs(struct super_block *sb, struct kstatfs *buf) ...@@ -579,7 +589,7 @@ nfs_statfs(struct super_block *sb, struct kstatfs *buf)
} }
static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults)
{ {
static struct proc_nfs_info { static struct proc_nfs_info {
int flag; int flag;
...@@ -588,28 +598,26 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) ...@@ -588,28 +598,26 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
} nfs_info[] = { } nfs_info[] = {
{ NFS_MOUNT_SOFT, ",soft", ",hard" }, { NFS_MOUNT_SOFT, ",soft", ",hard" },
{ NFS_MOUNT_INTR, ",intr", "" }, { NFS_MOUNT_INTR, ",intr", "" },
{ NFS_MOUNT_POSIX, ",posix", "" },
{ NFS_MOUNT_NOCTO, ",nocto", "" }, { NFS_MOUNT_NOCTO, ",nocto", "" },
{ NFS_MOUNT_NOAC, ",noac", "" }, { NFS_MOUNT_NOAC, ",noac", "" },
{ NFS_MOUNT_NONLM, ",nolock", ",lock" }, { NFS_MOUNT_NONLM, ",nolock", "" },
{ NFS_MOUNT_NOACL, ",noacl", "" }, { NFS_MOUNT_NOACL, ",noacl", "" },
{ 0, NULL, NULL } { 0, NULL, NULL }
}; };
struct proc_nfs_info *nfs_infop; struct proc_nfs_info *nfs_infop;
struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
char buf[12]; char buf[12];
char *proto; char *proto;
seq_printf(m, ",v%d", nfss->rpc_ops->version); seq_printf(m, ",vers=%d", nfss->rpc_ops->version);
seq_printf(m, ",rsize=%d", nfss->rsize); seq_printf(m, ",rsize=%d", nfss->rsize);
seq_printf(m, ",wsize=%d", nfss->wsize); seq_printf(m, ",wsize=%d", nfss->wsize);
if (nfss->acregmin != 3*HZ) if (nfss->acregmin != 3*HZ || showdefaults)
seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ); seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ);
if (nfss->acregmax != 60*HZ) if (nfss->acregmax != 60*HZ || showdefaults)
seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ); seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ);
if (nfss->acdirmin != 30*HZ) if (nfss->acdirmin != 30*HZ || showdefaults)
seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ); seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ);
if (nfss->acdirmax != 60*HZ) if (nfss->acdirmax != 60*HZ || showdefaults)
seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ); seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ);
for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
if (nfss->flags & nfs_infop->flag) if (nfss->flags & nfs_infop->flag)
...@@ -629,8 +637,96 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) ...@@ -629,8 +637,96 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
proto = buf; proto = buf;
} }
seq_printf(m, ",proto=%s", proto); seq_printf(m, ",proto=%s", proto);
seq_printf(m, ",timeo=%lu", 10U * nfss->retrans_timeo / HZ);
seq_printf(m, ",retrans=%u", nfss->retrans_count);
}
static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
{
struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
nfs_show_mount_options(m, nfss, 0);
seq_puts(m, ",addr="); seq_puts(m, ",addr=");
seq_escape(m, nfss->hostname, " \t\n\\"); seq_escape(m, nfss->hostname, " \t\n\\");
return 0;
}
static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
{
int i, cpu;
struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
struct rpc_auth *auth = nfss->client->cl_auth;
struct nfs_iostats totals = { };
seq_printf(m, "statvers=%s", NFS_IOSTAT_VERS);
/*
* Display all mount option settings
*/
seq_printf(m, "\n\topts:\t");
seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw");
seq_puts(m, mnt->mnt_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : "");
seq_puts(m, mnt->mnt_sb->s_flags & MS_NOATIME ? ",noatime" : "");
seq_puts(m, mnt->mnt_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : "");
nfs_show_mount_options(m, nfss, 1);
seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ);
seq_printf(m, "\n\tcaps:\t");
seq_printf(m, "caps=0x%x", nfss->caps);
seq_printf(m, ",wtmult=%d", nfss->wtmult);
seq_printf(m, ",dtsize=%d", nfss->dtsize);
seq_printf(m, ",bsize=%d", nfss->bsize);
seq_printf(m, ",namelen=%d", nfss->namelen);
#ifdef CONFIG_NFS_V4
if (nfss->rpc_ops->version == 4) {
seq_printf(m, "\n\tnfsv4:\t");
seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
}
#endif
/*
* Display security flavor in effect for this mount
*/
seq_printf(m, "\n\tsec:\tflavor=%d", auth->au_ops->au_flavor);
if (auth->au_flavor)
seq_printf(m, ",pseudoflavor=%d", auth->au_flavor);
/*
* Display superblock I/O counters
*/
for (cpu = 0; cpu < NR_CPUS; cpu++) {
struct nfs_iostats *stats;
if (!cpu_possible(cpu))
continue;
preempt_disable();
stats = per_cpu_ptr(nfss->io_stats, cpu);
for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
totals.events[i] += stats->events[i];
for (i = 0; i < __NFSIOS_BYTESMAX; i++)
totals.bytes[i] += stats->bytes[i];
preempt_enable();
}
seq_printf(m, "\n\tevents:\t");
for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
seq_printf(m, "%lu ", totals.events[i]);
seq_printf(m, "\n\tbytes:\t");
for (i = 0; i < __NFSIOS_BYTESMAX; i++)
seq_printf(m, "%Lu ", totals.bytes[i]);
seq_printf(m, "\n");
rpc_print_iostats(m, nfss->client);
return 0; return 0;
} }
...@@ -660,6 +756,8 @@ static void nfs_zap_caches_locked(struct inode *inode) ...@@ -660,6 +756,8 @@ static void nfs_zap_caches_locked(struct inode *inode)
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
int mode = inode->i_mode; int mode = inode->i_mode;
nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
NFS_ATTRTIMEO_UPDATE(inode) = jiffies; NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
...@@ -751,7 +849,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) ...@@ -751,7 +849,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
.fh = fh, .fh = fh,
.fattr = fattr .fattr = fattr
}; };
struct inode *inode = NULL; struct inode *inode = ERR_PTR(-ENOENT);
unsigned long hash; unsigned long hash;
if ((fattr->valid & NFS_ATTR_FATTR) == 0) if ((fattr->valid & NFS_ATTR_FATTR) == 0)
...@@ -764,8 +862,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) ...@@ -764,8 +862,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
hash = nfs_fattr_to_ino_t(fattr); hash = nfs_fattr_to_ino_t(fattr);
if (!(inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc))) inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc);
if (inode == NULL) {
inode = ERR_PTR(-ENOMEM);
goto out_no_inode; goto out_no_inode;
}
if (inode->i_state & I_NEW) { if (inode->i_state & I_NEW) {
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
...@@ -834,7 +935,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) ...@@ -834,7 +935,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
return inode; return inode;
out_no_inode: out_no_inode:
printk("nfs_fhget: iget failed\n"); dprintk("nfs_fhget: iget failed with error %ld\n", PTR_ERR(inode));
goto out; goto out;
} }
...@@ -847,6 +948,8 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -847,6 +948,8 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
struct nfs_fattr fattr; struct nfs_fattr fattr;
int error; int error;
nfs_inc_stats(inode, NFSIOS_VFSSETATTR);
if (attr->ia_valid & ATTR_SIZE) { if (attr->ia_valid & ATTR_SIZE) {
if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode)) if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode))
attr->ia_valid &= ~ATTR_SIZE; attr->ia_valid &= ~ATTR_SIZE;
...@@ -859,11 +962,9 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -859,11 +962,9 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
lock_kernel(); lock_kernel();
nfs_begin_data_update(inode); nfs_begin_data_update(inode);
/* Write all dirty data if we're changing file permissions or size */ /* Write all dirty data */
if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE)) != 0) {
filemap_write_and_wait(inode->i_mapping); filemap_write_and_wait(inode->i_mapping);
nfs_wb_all(inode); nfs_wb_all(inode);
}
/* /*
* Return any delegations if we're going to change ACLs * Return any delegations if we're going to change ACLs
*/ */
...@@ -902,6 +1003,7 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr) ...@@ -902,6 +1003,7 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
if ((attr->ia_valid & ATTR_SIZE) != 0) { if ((attr->ia_valid & ATTR_SIZE) != 0) {
nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
inode->i_size = attr->ia_size; inode->i_size = attr->ia_size;
vmtruncate(inode, attr->ia_size); vmtruncate(inode, attr->ia_size);
} }
...@@ -949,7 +1051,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) ...@@ -949,7 +1051,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
int err; int err;
/* Flush out writes to the server in order to update c/mtime */ /* Flush out writes to the server in order to update c/mtime */
nfs_sync_inode(inode, 0, 0, FLUSH_WAIT|FLUSH_NOCOMMIT); nfs_sync_inode_wait(inode, 0, 0, FLUSH_NOCOMMIT);
/* /*
* We may force a getattr if the user cares about atime. * We may force a getattr if the user cares about atime.
...@@ -973,7 +1075,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) ...@@ -973,7 +1075,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
return err; return err;
} }
struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred) static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, struct dentry *dentry, struct rpc_cred *cred)
{ {
struct nfs_open_context *ctx; struct nfs_open_context *ctx;
...@@ -981,6 +1083,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rp ...@@ -981,6 +1083,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rp
if (ctx != NULL) { if (ctx != NULL) {
atomic_set(&ctx->count, 1); atomic_set(&ctx->count, 1);
ctx->dentry = dget(dentry); ctx->dentry = dget(dentry);
ctx->vfsmnt = mntget(mnt);
ctx->cred = get_rpccred(cred); ctx->cred = get_rpccred(cred);
ctx->state = NULL; ctx->state = NULL;
ctx->lockowner = current->files; ctx->lockowner = current->files;
...@@ -1011,6 +1114,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx) ...@@ -1011,6 +1114,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx)
if (ctx->cred != NULL) if (ctx->cred != NULL)
put_rpccred(ctx->cred); put_rpccred(ctx->cred);
dput(ctx->dentry); dput(ctx->dentry);
mntput(ctx->vfsmnt);
kfree(ctx); kfree(ctx);
} }
} }
...@@ -1019,7 +1123,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx) ...@@ -1019,7 +1123,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx)
* Ensure that mmap has a recent RPC credential for use when writing out * Ensure that mmap has a recent RPC credential for use when writing out
* shared pages * shared pages
*/ */
void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx) static void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
{ {
struct inode *inode = filp->f_dentry->d_inode; struct inode *inode = filp->f_dentry->d_inode;
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
...@@ -1051,7 +1155,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c ...@@ -1051,7 +1155,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c
return ctx; return ctx;
} }
void nfs_file_clear_open_context(struct file *filp) static void nfs_file_clear_open_context(struct file *filp)
{ {
struct inode *inode = filp->f_dentry->d_inode; struct inode *inode = filp->f_dentry->d_inode;
struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data; struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data;
...@@ -1076,7 +1180,7 @@ int nfs_open(struct inode *inode, struct file *filp) ...@@ -1076,7 +1180,7 @@ int nfs_open(struct inode *inode, struct file *filp)
cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
if (IS_ERR(cred)) if (IS_ERR(cred))
return PTR_ERR(cred); return PTR_ERR(cred);
ctx = alloc_nfs_open_context(filp->f_dentry, cred); ctx = alloc_nfs_open_context(filp->f_vfsmnt, filp->f_dentry, cred);
put_rpccred(cred); put_rpccred(cred);
if (ctx == NULL) if (ctx == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -1185,6 +1289,7 @@ int nfs_attribute_timeout(struct inode *inode) ...@@ -1185,6 +1289,7 @@ int nfs_attribute_timeout(struct inode *inode)
*/ */
int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{ {
nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
if (!(NFS_I(inode)->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) if (!(NFS_I(inode)->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))
&& !nfs_attribute_timeout(inode)) && !nfs_attribute_timeout(inode))
return NFS_STALE(inode) ? -ESTALE : 0; return NFS_STALE(inode) ? -ESTALE : 0;
...@@ -1201,6 +1306,7 @@ void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) ...@@ -1201,6 +1306,7 @@ void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
if (nfsi->cache_validity & NFS_INO_INVALID_DATA) { if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
if (S_ISREG(inode->i_mode)) if (S_ISREG(inode->i_mode))
nfs_sync_mapping(mapping); nfs_sync_mapping(mapping);
invalidate_inode_pages2(mapping); invalidate_inode_pages2(mapping);
...@@ -1299,39 +1405,37 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat ...@@ -1299,39 +1405,37 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
if ((fattr->valid & NFS_ATTR_FATTR) == 0) if ((fattr->valid & NFS_ATTR_FATTR) == 0)
return 0; return 0;
/* Has the inode gone and changed behind our back? */
if (nfsi->fileid != fattr->fileid
|| (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) {
return -EIO;
}
/* 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);
/* Do atomic weak cache consistency updates */ /* Do atomic weak cache consistency updates */
nfs_wcc_update_inode(inode, fattr); nfs_wcc_update_inode(inode, fattr);
if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 && if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0) {
nfsi->change_attr != fattr->change_attr) { if (nfsi->change_attr == fattr->change_attr)
goto out;
nfsi->cache_validity |= NFS_INO_INVALID_ATTR; nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
if (!data_unstable) if (!data_unstable)
nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE;
} }
/* Has the inode gone and changed behind our back? */
if (nfsi->fileid != fattr->fileid
|| (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) {
return -EIO;
}
cur_size = i_size_read(inode);
new_isize = nfs_size_to_loff_t(fattr->size);
/* 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;
if (!data_unstable) if (!data_unstable)
nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE;
} }
if (cur_size != new_isize) {
nfsi->cache_validity |= NFS_INO_INVALID_ATTR; cur_size = i_size_read(inode);
if (nfsi->npages == 0) new_isize = nfs_size_to_loff_t(fattr->size);
nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; if (cur_size != new_isize && nfsi->npages == 0)
} nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
/* Have any file permissions changed? */ /* Have any file permissions changed? */
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
...@@ -1343,6 +1447,7 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat ...@@ -1343,6 +1447,7 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
if (inode->i_nlink != fattr->nlink) if (inode->i_nlink != fattr->nlink)
nfsi->cache_validity |= NFS_INO_INVALID_ATTR; nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
out:
if (!timespec_equal(&inode->i_atime, &fattr->atime)) if (!timespec_equal(&inode->i_atime, &fattr->atime))
nfsi->cache_validity |= NFS_INO_INVALID_ATIME; nfsi->cache_validity |= NFS_INO_INVALID_ATIME;
...@@ -1481,15 +1586,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1481,15 +1586,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
nfsi->cache_change_attribute = jiffies; nfsi->cache_change_attribute = jiffies;
} }
if ((fattr->valid & NFS_ATTR_FATTR_V4)
&& nfsi->change_attr != fattr->change_attr) {
dprintk("NFS: change_attr change on server for file %s/%ld\n",
inode->i_sb->s_id, inode->i_ino);
nfsi->change_attr = fattr->change_attr;
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
nfsi->cache_change_attribute = jiffies;
}
/* If ctime has changed we should definitely clear access+acl caches */ /* If ctime has changed we should definitely clear access+acl caches */
if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) {
invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
...@@ -1519,8 +1615,20 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1519,8 +1615,20 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
inode->i_blksize = fattr->du.nfs2.blocksize; inode->i_blksize = fattr->du.nfs2.blocksize;
} }
if ((fattr->valid & NFS_ATTR_FATTR_V4)) {
if (nfsi->change_attr != fattr->change_attr) {
dprintk("NFS: change_attr change on server for file %s/%ld\n",
inode->i_sb->s_id, inode->i_ino);
nfsi->change_attr = fattr->change_attr;
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
nfsi->cache_change_attribute = jiffies;
} else
invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA);
}
/* Update attrtimeo value if we're out of the unstable period */ /* Update attrtimeo value if we're out of the unstable period */
if (invalid & NFS_INO_INVALID_ATTR) { if (invalid & NFS_INO_INVALID_ATTR) {
nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
nfsi->attrtimeo_timestamp = jiffies; nfsi->attrtimeo_timestamp = jiffies;
} else if (time_after(jiffies, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) { } else if (time_after(jiffies, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) {
...@@ -1637,10 +1745,9 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, ...@@ -1637,10 +1745,9 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
#endif /* CONFIG_NFS_V3 */ #endif /* CONFIG_NFS_V3 */
s = ERR_PTR(-ENOMEM); s = ERR_PTR(-ENOMEM);
server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
if (!server) if (!server)
goto out_err; goto out_err;
memset(server, 0, sizeof(struct nfs_server));
/* Zero out the NFS state stuff */ /* Zero out the NFS state stuff */
init_nfsv4_state(server); init_nfsv4_state(server);
server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
...@@ -1712,6 +1819,7 @@ static void nfs_kill_super(struct super_block *s) ...@@ -1712,6 +1819,7 @@ static void nfs_kill_super(struct super_block *s)
rpciod_down(); /* release rpciod */ rpciod_down(); /* release rpciod */
nfs_free_iostats(server->io_stats);
kfree(server->hostname); kfree(server->hostname);
kfree(server); kfree(server);
} }
...@@ -1738,6 +1846,7 @@ static struct super_operations nfs4_sops = { ...@@ -1738,6 +1846,7 @@ static struct super_operations nfs4_sops = {
.clear_inode = nfs4_clear_inode, .clear_inode = nfs4_clear_inode,
.umount_begin = nfs_umount_begin, .umount_begin = nfs_umount_begin,
.show_options = nfs_show_options, .show_options = nfs_show_options,
.show_stats = nfs_show_stats,
}; };
/* /*
...@@ -1800,6 +1909,9 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, ...@@ -1800,6 +1909,9 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
nfs_init_timeout_values(&timeparms, data->proto, data->timeo, data->retrans); nfs_init_timeout_values(&timeparms, data->proto, data->timeo, data->retrans);
server->retrans_timeo = timeparms.to_initval;
server->retrans_count = timeparms.to_retries;
clp = nfs4_get_client(&server->addr.sin_addr); clp = nfs4_get_client(&server->addr.sin_addr);
if (!clp) { if (!clp) {
dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__); dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__);
...@@ -1941,10 +2053,9 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, ...@@ -1941,10 +2053,9 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
if (!server) if (!server)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
memset(server, 0, sizeof(struct nfs_server));
/* Zero out the NFS state stuff */ /* Zero out the NFS state stuff */
init_nfsv4_state(server); init_nfsv4_state(server);
server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
...@@ -2024,10 +2135,12 @@ static void nfs4_kill_super(struct super_block *sb) ...@@ -2024,10 +2135,12 @@ static void nfs4_kill_super(struct super_block *sb)
if (server->client != NULL && !IS_ERR(server->client)) if (server->client != NULL && !IS_ERR(server->client))
rpc_shutdown_client(server->client); rpc_shutdown_client(server->client);
rpciod_down(); /* release rpciod */
destroy_nfsv4_state(server); destroy_nfsv4_state(server);
rpciod_down();
nfs_free_iostats(server->io_stats);
kfree(server->hostname); kfree(server->hostname);
kfree(server); kfree(server);
} }
......
/*
* linux/fs/nfs/iostat.h
*
* Declarations for NFS client per-mount statistics
*
* Copyright (C) 2005, 2006 Chuck Lever <cel@netapp.com>
*
* NFS client per-mount statistics provide information about the health of
* the NFS client and the health of each NFS mount point. Generally these
* are not for detailed problem diagnosis, but simply to indicate that there
* is a problem.
*
* These counters are not meant to be human-readable, but are meant to be
* integrated into system monitoring tools such as "sar" and "iostat". As
* such, the counters are sampled by the tools over time, and are never
* zeroed after a file system is mounted. Moving averages can be computed
* by the tools by taking the difference between two instantaneous samples
* and dividing that by the time between the samples.
*/
#ifndef _NFS_IOSTAT
#define _NFS_IOSTAT
#define NFS_IOSTAT_VERS "1.0"
/*
* NFS byte counters
*
* 1. SERVER - the number of payload bytes read from or written to the
* server by the NFS client via an NFS READ or WRITE request.
*
* 2. NORMAL - the number of bytes read or written by applications via
* the read(2) and write(2) system call interfaces.
*
* 3. DIRECT - the number of bytes read or written from files opened
* with the O_DIRECT flag.
*
* These counters give a view of the data throughput into and out of the NFS
* client. Comparing the number of bytes requested by an application with the
* number of bytes the client requests from the server can provide an
* indication of client efficiency (per-op, cache hits, etc).
*
* These counters can also help characterize which access methods are in
* use. DIRECT by itself shows whether there is any O_DIRECT traffic.
* NORMAL + DIRECT shows how much data is going through the system call
* interface. A large amount of SERVER traffic without much NORMAL or
* DIRECT traffic shows that applications are using mapped files.
*
* NFS page counters
*
* These count the number of pages read or written via nfs_readpage(),
* nfs_readpages(), or their write equivalents.
*/
enum nfs_stat_bytecounters {
NFSIOS_NORMALREADBYTES = 0,
NFSIOS_NORMALWRITTENBYTES,
NFSIOS_DIRECTREADBYTES,
NFSIOS_DIRECTWRITTENBYTES,
NFSIOS_SERVERREADBYTES,
NFSIOS_SERVERWRITTENBYTES,
NFSIOS_READPAGES,
NFSIOS_WRITEPAGES,
__NFSIOS_BYTESMAX,
};
/*
* NFS event counters
*
* These counters provide a low-overhead way of monitoring client activity
* without enabling NFS trace debugging. The counters show the rate at
* which VFS requests are made, and how often the client invalidates its
* data and attribute caches. This allows system administrators to monitor
* such things as how close-to-open is working, and answer questions such
* as "why are there so many GETATTR requests on the wire?"
*
* They also count anamolous events such as short reads and writes, silly
* renames due to close-after-delete, and operations that change the size
* of a file (such operations can often be the source of data corruption
* if applications aren't using file locking properly).
*/
enum nfs_stat_eventcounters {
NFSIOS_INODEREVALIDATE = 0,
NFSIOS_DENTRYREVALIDATE,
NFSIOS_DATAINVALIDATE,
NFSIOS_ATTRINVALIDATE,
NFSIOS_VFSOPEN,
NFSIOS_VFSLOOKUP,
NFSIOS_VFSACCESS,
NFSIOS_VFSUPDATEPAGE,
NFSIOS_VFSREADPAGE,
NFSIOS_VFSREADPAGES,
NFSIOS_VFSWRITEPAGE,
NFSIOS_VFSWRITEPAGES,
NFSIOS_VFSGETDENTS,
NFSIOS_VFSSETATTR,
NFSIOS_VFSFLUSH,
NFSIOS_VFSFSYNC,
NFSIOS_VFSLOCK,
NFSIOS_VFSRELEASE,
NFSIOS_CONGESTIONWAIT,
NFSIOS_SETATTRTRUNC,
NFSIOS_EXTENDWRITE,
NFSIOS_SILLYRENAME,
NFSIOS_SHORTREAD,
NFSIOS_SHORTWRITE,
NFSIOS_DELAY,
__NFSIOS_COUNTSMAX,
};
#ifdef __KERNEL__
#include <linux/percpu.h>
#include <linux/cache.h>
struct nfs_iostats {
unsigned long long bytes[__NFSIOS_BYTESMAX];
unsigned long events[__NFSIOS_COUNTSMAX];
} ____cacheline_aligned;
static inline void nfs_inc_server_stats(struct nfs_server *server, enum nfs_stat_eventcounters stat)
{
struct nfs_iostats *iostats;
int cpu;
cpu = get_cpu();
iostats = per_cpu_ptr(server->io_stats, cpu);
iostats->events[stat] ++;
put_cpu_no_resched();
}
static inline void nfs_inc_stats(struct inode *inode, enum nfs_stat_eventcounters stat)
{
nfs_inc_server_stats(NFS_SERVER(inode), stat);
}
static inline void nfs_add_server_stats(struct nfs_server *server, enum nfs_stat_bytecounters stat, unsigned long addend)
{
struct nfs_iostats *iostats;
int cpu;
cpu = get_cpu();
iostats = per_cpu_ptr(server->io_stats, cpu);
iostats->bytes[stat] += addend;
put_cpu_no_resched();
}
static inline void nfs_add_stats(struct inode *inode, enum nfs_stat_bytecounters stat, unsigned long addend)
{
nfs_add_server_stats(NFS_SERVER(inode), stat, addend);
}
static inline struct nfs_iostats *nfs_alloc_iostats(void)
{
return alloc_percpu(struct nfs_iostats);
}
static inline void nfs_free_iostats(struct nfs_iostats *stats)
{
if (stats != NULL)
free_percpu(stats);
}
#endif
#endif
...@@ -49,9 +49,12 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, ...@@ -49,9 +49,12 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh,
struct mnt_fhstatus result = { struct mnt_fhstatus result = {
.fh = fh .fh = fh
}; };
struct rpc_message msg = {
.rpc_argp = path,
.rpc_resp = &result,
};
char hostname[32]; char hostname[32];
int status; int status;
int call;
dprintk("NFS: nfs_mount(%08x:%s)\n", dprintk("NFS: nfs_mount(%08x:%s)\n",
(unsigned)ntohl(addr->sin_addr.s_addr), path); (unsigned)ntohl(addr->sin_addr.s_addr), path);
...@@ -61,8 +64,12 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, ...@@ -61,8 +64,12 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh,
if (IS_ERR(mnt_clnt)) if (IS_ERR(mnt_clnt))
return PTR_ERR(mnt_clnt); return PTR_ERR(mnt_clnt);
call = (version == NFS_MNT3_VERSION) ? MOUNTPROC3_MNT : MNTPROC_MNT; if (version == NFS_MNT3_VERSION)
status = rpc_call(mnt_clnt, call, path, &result, 0); msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT];
else
msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT];
status = rpc_call_sync(mnt_clnt, &msg, 0);
return status < 0? status : (result.status? -EACCES : 0); return status < 0? status : (result.status? -EACCES : 0);
} }
...@@ -137,6 +144,8 @@ static struct rpc_procinfo mnt_procedures[] = { ...@@ -137,6 +144,8 @@ static struct rpc_procinfo mnt_procedures[] = {
.p_encode = (kxdrproc_t) xdr_encode_dirpath, .p_encode = (kxdrproc_t) xdr_encode_dirpath,
.p_decode = (kxdrproc_t) xdr_decode_fhstatus, .p_decode = (kxdrproc_t) xdr_decode_fhstatus,
.p_bufsiz = MNT_dirpath_sz << 2, .p_bufsiz = MNT_dirpath_sz << 2,
.p_statidx = MNTPROC_MNT,
.p_name = "MOUNT",
}, },
}; };
...@@ -146,6 +155,8 @@ static struct rpc_procinfo mnt3_procedures[] = { ...@@ -146,6 +155,8 @@ static struct rpc_procinfo mnt3_procedures[] = {
.p_encode = (kxdrproc_t) xdr_encode_dirpath, .p_encode = (kxdrproc_t) xdr_encode_dirpath,
.p_decode = (kxdrproc_t) xdr_decode_fhstatus3, .p_decode = (kxdrproc_t) xdr_decode_fhstatus3,
.p_bufsiz = MNT_dirpath_sz << 2, .p_bufsiz = MNT_dirpath_sz << 2,
.p_statidx = MOUNTPROC3_MNT,
.p_name = "MOUNT",
}, },
}; };
......
...@@ -682,7 +682,9 @@ nfs_stat_to_errno(int stat) ...@@ -682,7 +682,9 @@ nfs_stat_to_errno(int stat)
.p_encode = (kxdrproc_t) nfs_xdr_##argtype, \ .p_encode = (kxdrproc_t) nfs_xdr_##argtype, \
.p_decode = (kxdrproc_t) nfs_xdr_##restype, \ .p_decode = (kxdrproc_t) nfs_xdr_##restype, \
.p_bufsiz = MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \ .p_bufsiz = MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \
.p_timer = timer \ .p_timer = timer, \
.p_statidx = NFSPROC_##proc, \
.p_name = #proc, \
} }
struct rpc_procinfo nfs_procedures[] = { struct rpc_procinfo nfs_procedures[] = {
PROC(GETATTR, fhandle, attrstat, 1), PROC(GETATTR, fhandle, attrstat, 1),
......
...@@ -190,6 +190,10 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) ...@@ -190,6 +190,10 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
struct nfs3_getaclres res = { struct nfs3_getaclres res = {
.fattr = &fattr, .fattr = &fattr,
}; };
struct rpc_message msg = {
.rpc_argp = &args,
.rpc_resp = &res,
};
struct posix_acl *acl; struct posix_acl *acl;
int status, count; int status, count;
...@@ -218,8 +222,8 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) ...@@ -218,8 +222,8 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
return NULL; return NULL;
dprintk("NFS call getacl\n"); dprintk("NFS call getacl\n");
status = rpc_call(server->client_acl, ACLPROC3_GETACL, msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL];
&args, &res, 0); status = rpc_call_sync(server->client_acl, &msg, 0);
dprintk("NFS reply getacl: %d\n", status); dprintk("NFS reply getacl: %d\n", status);
/* pages may have been allocated at the xdr layer. */ /* pages may have been allocated at the xdr layer. */
...@@ -286,6 +290,10 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, ...@@ -286,6 +290,10 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
.acl_access = acl, .acl_access = acl,
.pages = pages, .pages = pages,
}; };
struct rpc_message msg = {
.rpc_argp = &args,
.rpc_resp = &fattr,
};
int status, count; int status, count;
status = -EOPNOTSUPP; status = -EOPNOTSUPP;
...@@ -306,8 +314,8 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, ...@@ -306,8 +314,8 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
dprintk("NFS call setacl\n"); dprintk("NFS call setacl\n");
nfs_begin_data_update(inode); nfs_begin_data_update(inode);
status = rpc_call(server->client_acl, ACLPROC3_SETACL, msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL];
&args, &fattr, 0); status = rpc_call_sync(server->client_acl, &msg, 0);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS; NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS;
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
......
此差异已折叠。
...@@ -1109,7 +1109,9 @@ nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) ...@@ -1109,7 +1109,9 @@ nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
.p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \ .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
.p_decode = (kxdrproc_t) nfs3_xdr_##restype, \ .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
.p_bufsiz = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \ .p_bufsiz = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \
.p_timer = timer \ .p_timer = timer, \
.p_statidx = NFS3PROC_##proc, \
.p_name = #proc, \
} }
struct rpc_procinfo nfs3_procedures[] = { struct rpc_procinfo nfs3_procedures[] = {
...@@ -1150,6 +1152,7 @@ static struct rpc_procinfo nfs3_acl_procedures[] = { ...@@ -1150,6 +1152,7 @@ static struct rpc_procinfo nfs3_acl_procedures[] = {
.p_decode = (kxdrproc_t) nfs3_xdr_getaclres, .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
.p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2, .p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2,
.p_timer = 1, .p_timer = 1,
.p_name = "GETACL",
}, },
[ACLPROC3_SETACL] = { [ACLPROC3_SETACL] = {
.p_proc = ACLPROC3_SETACL, .p_proc = ACLPROC3_SETACL,
...@@ -1157,6 +1160,7 @@ static struct rpc_procinfo nfs3_acl_procedures[] = { ...@@ -1157,6 +1160,7 @@ static struct rpc_procinfo nfs3_acl_procedures[] = {
.p_decode = (kxdrproc_t) nfs3_xdr_setaclres, .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
.p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2, .p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2,
.p_timer = 0, .p_timer = 0,
.p_name = "SETACL",
}, },
}; };
......
此差异已折叠。
...@@ -977,6 +977,7 @@ static int reclaimer(void *ptr) ...@@ -977,6 +977,7 @@ static int reclaimer(void *ptr)
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",
NIPQUAD(clp->cl_addr.s_addr), -status); NIPQUAD(clp->cl_addr.s_addr), -status);
set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
goto out; goto out;
} }
......
...@@ -4344,6 +4344,8 @@ nfs_stat_to_errno(int stat) ...@@ -4344,6 +4344,8 @@ nfs_stat_to_errno(int stat)
.p_encode = (kxdrproc_t) nfs4_xdr_##argtype, \ .p_encode = (kxdrproc_t) nfs4_xdr_##argtype, \
.p_decode = (kxdrproc_t) nfs4_xdr_##restype, \ .p_decode = (kxdrproc_t) nfs4_xdr_##restype, \
.p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2, \ .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2, \
.p_statidx = NFSPROC4_CLNT_##proc, \
.p_name = #proc, \
} }
struct rpc_procinfo nfs4_procedures[] = { struct rpc_procinfo nfs4_procedures[] = {
......
...@@ -85,6 +85,9 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, ...@@ -85,6 +85,9 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
atomic_set(&req->wb_complete, 0); atomic_set(&req->wb_complete, 0);
req->wb_index = page->index; req->wb_index = page->index;
page_cache_get(page); page_cache_get(page);
BUG_ON(PagePrivate(page));
BUG_ON(!PageLocked(page));
BUG_ON(page->mapping->host != inode);
req->wb_offset = offset; req->wb_offset = offset;
req->wb_pgbase = offset; req->wb_pgbase = offset;
req->wb_bytes = count; req->wb_bytes = count;
...@@ -132,9 +135,11 @@ void nfs_clear_page_writeback(struct nfs_page *req) ...@@ -132,9 +135,11 @@ void nfs_clear_page_writeback(struct nfs_page *req)
{ {
struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode);
if (req->wb_page != NULL) {
spin_lock(&nfsi->req_lock); spin_lock(&nfsi->req_lock);
radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK);
spin_unlock(&nfsi->req_lock); spin_unlock(&nfsi->req_lock);
}
nfs_unlock_request(req); nfs_unlock_request(req);
} }
...@@ -147,8 +152,9 @@ void nfs_clear_page_writeback(struct nfs_page *req) ...@@ -147,8 +152,9 @@ void nfs_clear_page_writeback(struct nfs_page *req)
*/ */
void nfs_clear_request(struct nfs_page *req) void nfs_clear_request(struct nfs_page *req)
{ {
if (req->wb_page) { struct page *page = req->wb_page;
page_cache_release(req->wb_page); if (page != NULL) {
page_cache_release(page);
req->wb_page = NULL; req->wb_page = NULL;
} }
} }
......
此差异已折叠。
此差异已折叠。
...@@ -163,10 +163,9 @@ nfs_async_unlink(struct dentry *dentry) ...@@ -163,10 +163,9 @@ nfs_async_unlink(struct dentry *dentry)
struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode); struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode);
int status = -ENOMEM; int status = -ENOMEM;
data = kmalloc(sizeof(*data), GFP_KERNEL); data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) if (!data)
goto out; goto out;
memset(data, 0, sizeof(*data));
data->cred = rpcauth_lookupcred(clnt->cl_auth, 0); data->cred = rpcauth_lookupcred(clnt->cl_auth, 0);
if (IS_ERR(data->cred)) { if (IS_ERR(data->cred)) {
......
此差异已折叠。
...@@ -326,6 +326,8 @@ nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, u32 *p) ...@@ -326,6 +326,8 @@ nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, u32 *p)
.p_encode = (kxdrproc_t) nfs4_xdr_##argtype, \ .p_encode = (kxdrproc_t) nfs4_xdr_##argtype, \
.p_decode = (kxdrproc_t) nfs4_xdr_##restype, \ .p_decode = (kxdrproc_t) nfs4_xdr_##restype, \
.p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2, \ .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2, \
.p_statidx = NFSPROC4_CB_##call, \
.p_name = #proc, \
} }
static struct rpc_procinfo nfs4_cb_procedures[] = { static struct rpc_procinfo nfs4_cb_procedures[] = {
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册