mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
This commit is contained in:
commit
47853e7fa5
@ -910,6 +910,14 @@ running once the system is up.
|
||||
nfsroot= [NFS] nfs root filesystem for disk-less boxes.
|
||||
See Documentation/nfsroot.txt.
|
||||
|
||||
nfs.callback_tcpport=
|
||||
[NFS] set the TCP port on which the NFSv4 callback
|
||||
channel should listen.
|
||||
|
||||
nfs.idmap_cache_timeout=
|
||||
[NFS] set the maximum lifetime for idmapper cache
|
||||
entries.
|
||||
|
||||
nmi_watchdog= [KNL,BUGS=IA-32] Debugging features for SMP kernels
|
||||
|
||||
no387 [BUGS=IA-32] Tells the kernel to use the 387 maths
|
||||
|
@ -26,11 +26,12 @@
|
||||
static int nlmclnt_test(struct nlm_rqst *, struct file_lock *);
|
||||
static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *);
|
||||
static int nlmclnt_unlock(struct nlm_rqst *, struct file_lock *);
|
||||
static void nlmclnt_unlock_callback(struct rpc_task *);
|
||||
static void nlmclnt_cancel_callback(struct rpc_task *);
|
||||
static int nlm_stat_to_errno(u32 stat);
|
||||
static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host);
|
||||
|
||||
static const struct rpc_call_ops nlmclnt_unlock_ops;
|
||||
static const struct rpc_call_ops nlmclnt_cancel_ops;
|
||||
|
||||
/*
|
||||
* Cookie counter for NLM requests
|
||||
*/
|
||||
@ -221,8 +222,7 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
|
||||
goto done;
|
||||
}
|
||||
clnt->cl_softrtry = nfssrv->client->cl_softrtry;
|
||||
clnt->cl_intr = nfssrv->client->cl_intr;
|
||||
clnt->cl_chatty = nfssrv->client->cl_chatty;
|
||||
clnt->cl_intr = nfssrv->client->cl_intr;
|
||||
}
|
||||
|
||||
/* Keep the old signal mask */
|
||||
@ -399,8 +399,7 @@ in_grace_period:
|
||||
/*
|
||||
* Generic NLM call, async version.
|
||||
*/
|
||||
int
|
||||
nlmsvc_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
|
||||
int nlmsvc_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;
|
||||
@ -419,13 +418,12 @@ nlmsvc_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
|
||||
msg.rpc_proc = &clnt->cl_procinfo[proc];
|
||||
|
||||
/* bootstrap and kick off the async RPC call */
|
||||
status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req);
|
||||
status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
|
||||
static int nlmclnt_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;
|
||||
@ -448,7 +446,7 @@ nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
|
||||
/* Increment host refcount */
|
||||
nlm_get_host(host);
|
||||
/* bootstrap and kick off the async RPC call */
|
||||
status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req);
|
||||
status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req);
|
||||
if (status < 0)
|
||||
nlm_release_host(host);
|
||||
return status;
|
||||
@ -664,7 +662,7 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
|
||||
|
||||
if (req->a_flags & RPC_TASK_ASYNC) {
|
||||
status = nlmclnt_async_call(req, NLMPROC_UNLOCK,
|
||||
nlmclnt_unlock_callback);
|
||||
&nlmclnt_unlock_ops);
|
||||
/* Hrmf... Do the unlock early since locks_remove_posix()
|
||||
* really expects us to free the lock synchronously */
|
||||
do_vfs_lock(fl);
|
||||
@ -692,10 +690,9 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
|
||||
return -ENOLCK;
|
||||
}
|
||||
|
||||
static void
|
||||
nlmclnt_unlock_callback(struct rpc_task *task)
|
||||
static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
|
||||
{
|
||||
struct nlm_rqst *req = (struct nlm_rqst *) task->tk_calldata;
|
||||
struct nlm_rqst *req = data;
|
||||
int status = req->a_res.status;
|
||||
|
||||
if (RPC_ASSASSINATED(task))
|
||||
@ -722,6 +719,10 @@ die:
|
||||
rpc_restart_call(task);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nlmclnt_unlock_ops = {
|
||||
.rpc_call_done = nlmclnt_unlock_callback,
|
||||
};
|
||||
|
||||
/*
|
||||
* Cancel a blocked lock request.
|
||||
* We always use an async RPC call for this in order not to hang a
|
||||
@ -750,8 +751,7 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
|
||||
|
||||
nlmclnt_setlockargs(req, fl);
|
||||
|
||||
status = nlmclnt_async_call(req, NLMPROC_CANCEL,
|
||||
nlmclnt_cancel_callback);
|
||||
status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
|
||||
if (status < 0) {
|
||||
nlmclnt_release_lockargs(req);
|
||||
kfree(req);
|
||||
@ -765,10 +765,9 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
nlmclnt_cancel_callback(struct rpc_task *task)
|
||||
static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
|
||||
{
|
||||
struct nlm_rqst *req = (struct nlm_rqst *) task->tk_calldata;
|
||||
struct nlm_rqst *req = data;
|
||||
|
||||
if (RPC_ASSASSINATED(task))
|
||||
goto die;
|
||||
@ -807,6 +806,10 @@ retry_cancel:
|
||||
rpc_delay(task, 30 * HZ);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nlmclnt_cancel_ops = {
|
||||
.rpc_call_done = nlmclnt_cancel_callback,
|
||||
};
|
||||
|
||||
/*
|
||||
* Convert an NLM status code to a generic kernel errno
|
||||
*/
|
||||
|
@ -177,7 +177,7 @@ nlm_bind_host(struct nlm_host *host)
|
||||
if ((clnt = host->h_rpcclnt) != NULL) {
|
||||
xprt = clnt->cl_xprt;
|
||||
if (time_after_eq(jiffies, host->h_nextrebind)) {
|
||||
clnt->cl_port = 0;
|
||||
rpc_force_rebind(clnt);
|
||||
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
|
||||
dprintk("lockd: next rebind in %ld jiffies\n",
|
||||
host->h_nextrebind - jiffies);
|
||||
@ -217,7 +217,7 @@ nlm_rebind_host(struct nlm_host *host)
|
||||
{
|
||||
dprintk("lockd: rebind host %s\n", host->h_name);
|
||||
if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) {
|
||||
host->h_rpcclnt->cl_port = 0;
|
||||
rpc_force_rebind(host->h_rpcclnt);
|
||||
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +123,6 @@ nsm_create(void)
|
||||
if (IS_ERR(clnt))
|
||||
goto out_err;
|
||||
clnt->cl_softrtry = 1;
|
||||
clnt->cl_chatty = 1;
|
||||
clnt->cl_oneshot = 1;
|
||||
return clnt;
|
||||
|
||||
|
@ -178,6 +178,8 @@ lockd(struct svc_rqst *rqstp)
|
||||
|
||||
}
|
||||
|
||||
flush_signals(current);
|
||||
|
||||
/*
|
||||
* Check whether there's a new lockd process before
|
||||
* shutting down the hosts and clearing the slot.
|
||||
@ -192,8 +194,6 @@ lockd(struct svc_rqst *rqstp)
|
||||
"lockd: new process, skipping host shutdown\n");
|
||||
wake_up(&lockd_exit);
|
||||
|
||||
flush_signals(current);
|
||||
|
||||
/* Exit the RPC thread */
|
||||
svc_exit_thread(rqstp);
|
||||
|
||||
|
@ -22,7 +22,8 @@
|
||||
#define NLMDBG_FACILITY NLMDBG_CLIENT
|
||||
|
||||
static u32 nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *);
|
||||
static void nlm4svc_callback_exit(struct rpc_task *);
|
||||
|
||||
static const struct rpc_call_ops nlm4svc_callback_ops;
|
||||
|
||||
/*
|
||||
* Obtain client and file from arguments
|
||||
@ -470,7 +471,6 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp,
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This is the generic lockd callback for async RPC calls
|
||||
*/
|
||||
@ -494,7 +494,7 @@ nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
|
||||
call->a_host = host;
|
||||
memcpy(&call->a_args, resp, sizeof(*resp));
|
||||
|
||||
if (nlmsvc_async_call(call, proc, nlm4svc_callback_exit) < 0)
|
||||
if (nlmsvc_async_call(call, proc, &nlm4svc_callback_ops) < 0)
|
||||
goto error;
|
||||
|
||||
return rpc_success;
|
||||
@ -504,10 +504,9 @@ nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
|
||||
return rpc_system_err;
|
||||
}
|
||||
|
||||
static void
|
||||
nlm4svc_callback_exit(struct rpc_task *task)
|
||||
static void nlm4svc_callback_exit(struct rpc_task *task, void *data)
|
||||
{
|
||||
struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata;
|
||||
struct nlm_rqst *call = data;
|
||||
|
||||
if (task->tk_status < 0) {
|
||||
dprintk("lockd: %4d callback failed (errno = %d)\n",
|
||||
@ -517,6 +516,10 @@ nlm4svc_callback_exit(struct rpc_task *task)
|
||||
kfree(call);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nlm4svc_callback_ops = {
|
||||
.rpc_call_done = nlm4svc_callback_exit,
|
||||
};
|
||||
|
||||
/*
|
||||
* NLM Server procedures.
|
||||
*/
|
||||
|
@ -41,7 +41,8 @@
|
||||
|
||||
static void nlmsvc_insert_block(struct nlm_block *block, unsigned long);
|
||||
static int nlmsvc_remove_block(struct nlm_block *block);
|
||||
static void nlmsvc_grant_callback(struct rpc_task *task);
|
||||
|
||||
static const struct rpc_call_ops nlmsvc_grant_ops;
|
||||
|
||||
/*
|
||||
* The list of blocked locks to retry
|
||||
@ -226,31 +227,27 @@ failed:
|
||||
* It is the caller's responsibility to check whether the file
|
||||
* can be closed hereafter.
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
nlmsvc_delete_block(struct nlm_block *block, int unlock)
|
||||
{
|
||||
struct file_lock *fl = &block->b_call.a_args.lock.fl;
|
||||
struct nlm_file *file = block->b_file;
|
||||
struct nlm_block **bp;
|
||||
int status = 0;
|
||||
|
||||
dprintk("lockd: deleting block %p...\n", block);
|
||||
|
||||
/* Remove block from list */
|
||||
nlmsvc_remove_block(block);
|
||||
if (fl->fl_next)
|
||||
posix_unblock_lock(file->f_file, fl);
|
||||
if (unlock) {
|
||||
fl->fl_type = F_UNLCK;
|
||||
posix_lock_file(file->f_file, fl);
|
||||
block->b_granted = 0;
|
||||
}
|
||||
if (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;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Remove block from file's list of blocks */
|
||||
@ -265,6 +262,7 @@ nlmsvc_delete_block(struct nlm_block *block, int unlock)
|
||||
nlm_release_host(block->b_host);
|
||||
nlmclnt_freegrantargs(&block->b_call);
|
||||
kfree(block);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -275,6 +273,7 @@ int
|
||||
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) {
|
||||
@ -444,6 +443,7 @@ u32
|
||||
nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
|
||||
{
|
||||
struct nlm_block *block;
|
||||
int status = 0;
|
||||
|
||||
dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n",
|
||||
file->f_file->f_dentry->d_inode->i_sb->s_id,
|
||||
@ -454,9 +454,9 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
|
||||
|
||||
down(&file->f_sema);
|
||||
if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL)
|
||||
nlmsvc_delete_block(block, 1);
|
||||
status = nlmsvc_delete_block(block, 1);
|
||||
up(&file->f_sema);
|
||||
return nlm_granted;
|
||||
return status ? nlm_lck_denied : nlm_granted;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -562,7 +562,7 @@ callback:
|
||||
/* Call the client */
|
||||
nlm_get_host(block->b_call.a_host);
|
||||
if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG,
|
||||
nlmsvc_grant_callback) < 0)
|
||||
&nlmsvc_grant_ops) < 0)
|
||||
nlm_release_host(block->b_call.a_host);
|
||||
up(&file->f_sema);
|
||||
}
|
||||
@ -575,10 +575,9 @@ callback:
|
||||
* chain once more in order to have it removed by lockd itself (which can
|
||||
* then sleep on the file semaphore without disrupting e.g. the nfs client).
|
||||
*/
|
||||
static void
|
||||
nlmsvc_grant_callback(struct rpc_task *task)
|
||||
static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
|
||||
{
|
||||
struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata;
|
||||
struct nlm_rqst *call = data;
|
||||
struct nlm_block *block;
|
||||
unsigned long timeout;
|
||||
struct sockaddr_in *peer_addr = RPC_PEERADDR(task->tk_client);
|
||||
@ -614,6 +613,10 @@ nlmsvc_grant_callback(struct rpc_task *task)
|
||||
nlm_release_host(call->a_host);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nlmsvc_grant_ops = {
|
||||
.rpc_call_done = nlmsvc_grant_callback,
|
||||
};
|
||||
|
||||
/*
|
||||
* We received a GRANT_RES callback. Try to find the corresponding
|
||||
* block.
|
||||
@ -633,11 +636,12 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status
|
||||
|
||||
file->f_count++;
|
||||
down(&file->f_sema);
|
||||
if ((block = nlmsvc_find_block(cookie,&rqstp->rq_addr)) != NULL) {
|
||||
block = nlmsvc_find_block(cookie, &rqstp->rq_addr);
|
||||
if (block) {
|
||||
if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
|
||||
/* Try again in a couple of seconds */
|
||||
nlmsvc_insert_block(block, 10 * HZ);
|
||||
block = NULL;
|
||||
up(&file->f_sema);
|
||||
} else {
|
||||
/* Lock is now held by client, or has been rejected.
|
||||
* In both cases, the block should be removed. */
|
||||
@ -648,8 +652,6 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status
|
||||
nlmsvc_delete_block(block, 1);
|
||||
}
|
||||
}
|
||||
if (!block)
|
||||
up(&file->f_sema);
|
||||
nlm_release_file(file);
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,8 @@
|
||||
#define NLMDBG_FACILITY NLMDBG_CLIENT
|
||||
|
||||
static u32 nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *);
|
||||
static void nlmsvc_callback_exit(struct rpc_task *);
|
||||
|
||||
static const struct rpc_call_ops nlmsvc_callback_ops;
|
||||
|
||||
#ifdef CONFIG_LOCKD_V4
|
||||
static u32
|
||||
@ -518,7 +519,7 @@ nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
|
||||
call->a_host = host;
|
||||
memcpy(&call->a_args, resp, sizeof(*resp));
|
||||
|
||||
if (nlmsvc_async_call(call, proc, nlmsvc_callback_exit) < 0)
|
||||
if (nlmsvc_async_call(call, proc, &nlmsvc_callback_ops) < 0)
|
||||
goto error;
|
||||
|
||||
return rpc_success;
|
||||
@ -528,10 +529,9 @@ nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
|
||||
return rpc_system_err;
|
||||
}
|
||||
|
||||
static void
|
||||
nlmsvc_callback_exit(struct rpc_task *task)
|
||||
static void nlmsvc_callback_exit(struct rpc_task *task, void *data)
|
||||
{
|
||||
struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata;
|
||||
struct nlm_rqst *call = data;
|
||||
|
||||
if (task->tk_status < 0) {
|
||||
dprintk("lockd: %4d callback failed (errno = %d)\n",
|
||||
@ -541,6 +541,10 @@ nlmsvc_callback_exit(struct rpc_task *task)
|
||||
kfree(call);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nlmsvc_callback_ops = {
|
||||
.rpc_call_done = nlmsvc_callback_exit,
|
||||
};
|
||||
|
||||
/*
|
||||
* NLM Server procedures.
|
||||
*/
|
||||
|
@ -354,7 +354,9 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
|
||||
return 0;
|
||||
argp->state = ntohl(*p++);
|
||||
/* Preserve the address in network byte order */
|
||||
argp->addr = *p++;
|
||||
argp->addr = *p++;
|
||||
argp->vers = *p++;
|
||||
argp->proto = *p++;
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
|
||||
|
20
fs/locks.c
20
fs/locks.c
@ -1958,22 +1958,18 @@ EXPORT_SYMBOL(posix_block_lock);
|
||||
*
|
||||
* lockd needs to block waiting for locks.
|
||||
*/
|
||||
void
|
||||
int
|
||||
posix_unblock_lock(struct file *filp, struct file_lock *waiter)
|
||||
{
|
||||
/*
|
||||
* A remote machine may cancel the lock request after it's been
|
||||
* granted locally. If that happens, we need to delete the lock.
|
||||
*/
|
||||
int status = 0;
|
||||
|
||||
lock_kernel();
|
||||
if (waiter->fl_next) {
|
||||
if (waiter->fl_next)
|
||||
__locks_delete_block(waiter);
|
||||
unlock_kernel();
|
||||
} else {
|
||||
unlock_kernel();
|
||||
waiter->fl_type = F_UNLCK;
|
||||
posix_lock_file(filp, waiter);
|
||||
}
|
||||
else
|
||||
status = -ENOENT;
|
||||
unlock_kernel();
|
||||
return status;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(posix_unblock_lock);
|
||||
|
@ -13,4 +13,5 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
|
||||
delegation.o idmap.o \
|
||||
callback.o callback_xdr.o callback_proc.o
|
||||
nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
|
||||
nfs-$(CONFIG_SYSCTL) += sysctl.o
|
||||
nfs-objs := $(nfs-y)
|
||||
|
@ -34,6 +34,7 @@ static struct nfs_callback_data nfs_callback_info;
|
||||
static DECLARE_MUTEX(nfs_callback_sema);
|
||||
static struct svc_program nfs4_callback_program;
|
||||
|
||||
unsigned int nfs_callback_set_tcpport;
|
||||
unsigned short nfs_callback_tcpport;
|
||||
|
||||
/*
|
||||
@ -98,7 +99,7 @@ int nfs_callback_up(void)
|
||||
if (!serv)
|
||||
goto out_err;
|
||||
/* FIXME: We don't want to register this socket with the portmapper */
|
||||
ret = svc_makesock(serv, IPPROTO_TCP, 0);
|
||||
ret = svc_makesock(serv, IPPROTO_TCP, nfs_callback_set_tcpport);
|
||||
if (ret < 0)
|
||||
goto out_destroy;
|
||||
if (!list_empty(&serv->sv_permsocks)) {
|
||||
|
@ -65,6 +65,7 @@ extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
|
||||
extern int nfs_callback_up(void);
|
||||
extern int nfs_callback_down(void);
|
||||
|
||||
extern unsigned int nfs_callback_set_tcpport;
|
||||
extern unsigned short nfs_callback_tcpport;
|
||||
|
||||
#endif /* __LINUX_FS_NFS_CALLBACK_H */
|
||||
|
@ -35,7 +35,9 @@ unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres
|
||||
if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0)
|
||||
goto out_iput;
|
||||
res->size = i_size_read(inode);
|
||||
res->change_attr = NFS_CHANGE_ATTR(inode);
|
||||
res->change_attr = delegation->change_attr;
|
||||
if (nfsi->npages != 0)
|
||||
res->change_attr++;
|
||||
res->ctime = inode->i_ctime;
|
||||
res->mtime = inode->i_mtime;
|
||||
res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) &
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
#include <linux/config.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spinlock.h>
|
||||
@ -130,6 +131,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
|
||||
sizeof(delegation->stateid.data));
|
||||
delegation->type = res->delegation_type;
|
||||
delegation->maxsize = res->maxsize;
|
||||
delegation->change_attr = nfsi->change_attr;
|
||||
delegation->cred = get_rpccred(cred);
|
||||
delegation->inode = inode;
|
||||
|
||||
@ -157,8 +159,6 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
__nfs_revalidate_inode(NFS_SERVER(inode), inode);
|
||||
|
||||
res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid);
|
||||
nfs_free_delegation(delegation);
|
||||
return res;
|
||||
@ -231,6 +231,49 @@ restart:
|
||||
spin_unlock(&clp->cl_lock);
|
||||
}
|
||||
|
||||
int nfs_do_expire_all_delegations(void *ptr)
|
||||
{
|
||||
struct nfs4_client *clp = ptr;
|
||||
struct nfs_delegation *delegation;
|
||||
struct inode *inode;
|
||||
|
||||
allow_signal(SIGKILL);
|
||||
restart:
|
||||
spin_lock(&clp->cl_lock);
|
||||
if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0)
|
||||
goto out;
|
||||
if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0)
|
||||
goto out;
|
||||
list_for_each_entry(delegation, &clp->cl_delegations, super_list) {
|
||||
inode = igrab(delegation->inode);
|
||||
if (inode == NULL)
|
||||
continue;
|
||||
spin_unlock(&clp->cl_lock);
|
||||
nfs_inode_return_delegation(inode);
|
||||
iput(inode);
|
||||
goto restart;
|
||||
}
|
||||
out:
|
||||
spin_unlock(&clp->cl_lock);
|
||||
nfs4_put_client(clp);
|
||||
module_put_and_exit(0);
|
||||
}
|
||||
|
||||
void nfs_expire_all_delegations(struct nfs4_client *clp)
|
||||
{
|
||||
struct task_struct *task;
|
||||
|
||||
__module_get(THIS_MODULE);
|
||||
atomic_inc(&clp->cl_count);
|
||||
task = kthread_run(nfs_do_expire_all_delegations, clp,
|
||||
"%u.%u.%u.%u-delegreturn",
|
||||
NIPQUAD(clp->cl_addr));
|
||||
if (!IS_ERR(task))
|
||||
return;
|
||||
nfs4_put_client(clp);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return all delegations following an NFS4ERR_CB_PATH_DOWN error.
|
||||
*/
|
||||
|
@ -21,6 +21,7 @@ struct nfs_delegation {
|
||||
#define NFS_DELEGATION_NEED_RECLAIM 1
|
||||
long flags;
|
||||
loff_t maxsize;
|
||||
__u64 change_attr;
|
||||
};
|
||||
|
||||
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
|
||||
@ -30,6 +31,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s
|
||||
|
||||
struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle);
|
||||
void nfs_return_all_delegations(struct super_block *sb);
|
||||
void nfs_expire_all_delegations(struct nfs4_client *clp);
|
||||
void nfs_handle_cb_pathdown(struct nfs4_client *clp);
|
||||
|
||||
void nfs_delegation_mark_reclaim(struct nfs4_client *clp);
|
||||
|
@ -1550,8 +1550,10 @@ go_ahead:
|
||||
}
|
||||
nfs_inode_return_delegation(old_inode);
|
||||
|
||||
if (new_inode)
|
||||
if (new_inode != NULL) {
|
||||
nfs_inode_return_delegation(new_inode);
|
||||
d_delete(new_dentry);
|
||||
}
|
||||
|
||||
nfs_begin_data_update(old_dir);
|
||||
nfs_begin_data_update(new_dir);
|
||||
|
@ -122,9 +122,10 @@ nfs_free_user_pages(struct page **pages, int npages, int do_dirty)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < npages; i++) {
|
||||
if (do_dirty)
|
||||
set_page_dirty_lock(pages[i]);
|
||||
page_cache_release(pages[i]);
|
||||
struct page *page = pages[i];
|
||||
if (do_dirty && !PageCompound(page))
|
||||
set_page_dirty_lock(page);
|
||||
page_cache_release(page);
|
||||
}
|
||||
kfree(pages);
|
||||
}
|
||||
@ -154,6 +155,7 @@ static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, unsigned int
|
||||
struct list_head *list;
|
||||
struct nfs_direct_req *dreq;
|
||||
unsigned int reads = 0;
|
||||
unsigned int rpages = (rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
||||
|
||||
dreq = kmem_cache_alloc(nfs_direct_cachep, SLAB_KERNEL);
|
||||
if (!dreq)
|
||||
@ -167,7 +169,7 @@ static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, unsigned int
|
||||
|
||||
list = &dreq->list;
|
||||
for(;;) {
|
||||
struct nfs_read_data *data = nfs_readdata_alloc();
|
||||
struct nfs_read_data *data = nfs_readdata_alloc(rpages);
|
||||
|
||||
if (unlikely(!data)) {
|
||||
while (!list_empty(list)) {
|
||||
@ -268,8 +270,6 @@ static void nfs_direct_read_schedule(struct nfs_direct_req *dreq,
|
||||
NFS_PROTO(inode)->read_setup(data);
|
||||
|
||||
data->task.tk_cookie = (unsigned long) inode;
|
||||
data->task.tk_calldata = data;
|
||||
data->task.tk_release = nfs_readdata_release;
|
||||
data->complete = nfs_direct_read_result;
|
||||
|
||||
lock_kernel();
|
||||
@ -433,7 +433,7 @@ static ssize_t nfs_direct_write_seg(struct inode *inode,
|
||||
struct nfs_writeverf first_verf;
|
||||
struct nfs_write_data *wdata;
|
||||
|
||||
wdata = nfs_writedata_alloc();
|
||||
wdata = nfs_writedata_alloc(NFS_SERVER(inode)->wpages);
|
||||
if (!wdata)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -662,10 +662,10 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t
|
||||
.iov_len = count,
|
||||
};
|
||||
|
||||
dprintk("nfs: direct read(%s/%s, %lu@%lu)\n",
|
||||
dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n",
|
||||
file->f_dentry->d_parent->d_name.name,
|
||||
file->f_dentry->d_name.name,
|
||||
(unsigned long) count, (unsigned long) pos);
|
||||
(unsigned long) count, (long long) pos);
|
||||
|
||||
if (!is_sync_kiocb(iocb))
|
||||
goto out;
|
||||
@ -718,9 +718,7 @@ out:
|
||||
ssize_t
|
||||
nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
|
||||
{
|
||||
ssize_t retval = -EINVAL;
|
||||
loff_t *ppos = &iocb->ki_pos;
|
||||
unsigned long limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
|
||||
ssize_t retval;
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct nfs_open_context *ctx =
|
||||
(struct nfs_open_context *) file->private_data;
|
||||
@ -728,35 +726,32 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count,
|
||||
struct inode *inode = mapping->host;
|
||||
struct iovec iov = {
|
||||
.iov_base = (char __user *)buf,
|
||||
.iov_len = count,
|
||||
};
|
||||
|
||||
dfprintk(VFS, "nfs: direct write(%s/%s(%ld), %lu@%lu)\n",
|
||||
dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n",
|
||||
file->f_dentry->d_parent->d_name.name,
|
||||
file->f_dentry->d_name.name, inode->i_ino,
|
||||
(unsigned long) count, (unsigned long) pos);
|
||||
file->f_dentry->d_name.name,
|
||||
(unsigned long) count, (long long) pos);
|
||||
|
||||
retval = -EINVAL;
|
||||
if (!is_sync_kiocb(iocb))
|
||||
goto out;
|
||||
if (count < 0)
|
||||
|
||||
retval = generic_write_checks(file, &pos, &count, 0);
|
||||
if (retval)
|
||||
goto out;
|
||||
if (pos < 0)
|
||||
|
||||
retval = -EINVAL;
|
||||
if ((ssize_t) count < 0)
|
||||
goto out;
|
||||
retval = -EFAULT;
|
||||
if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len))
|
||||
goto out;
|
||||
retval = -EFBIG;
|
||||
if (limit != RLIM_INFINITY) {
|
||||
if (pos >= limit) {
|
||||
send_sig(SIGXFSZ, current, 0);
|
||||
goto out;
|
||||
}
|
||||
if (count > limit - (unsigned long) pos)
|
||||
count = limit - (unsigned long) pos;
|
||||
}
|
||||
retval = 0;
|
||||
if (!count)
|
||||
goto out;
|
||||
iov.iov_len = count,
|
||||
|
||||
retval = -EFAULT;
|
||||
if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len))
|
||||
goto out;
|
||||
|
||||
retval = nfs_sync_mapping(mapping);
|
||||
if (retval)
|
||||
@ -766,7 +761,7 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count,
|
||||
if (mapping->nrpages)
|
||||
invalidate_inode_pages2(mapping);
|
||||
if (retval > 0)
|
||||
*ppos = pos + retval;
|
||||
iocb->ki_pos = pos + retval;
|
||||
|
||||
out:
|
||||
return retval;
|
||||
|
@ -54,7 +54,11 @@
|
||||
|
||||
#define IDMAP_HASH_SZ 128
|
||||
|
||||
/* Default cache timeout is 10 minutes */
|
||||
unsigned int nfs_idmap_cache_timeout = 600 * HZ;
|
||||
|
||||
struct idmap_hashent {
|
||||
unsigned long ih_expires;
|
||||
__u32 ih_id;
|
||||
int ih_namelen;
|
||||
char ih_name[IDMAP_NAMESZ];
|
||||
@ -149,6 +153,8 @@ idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len)
|
||||
|
||||
if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0)
|
||||
return NULL;
|
||||
if (time_after(jiffies, he->ih_expires))
|
||||
return NULL;
|
||||
return he;
|
||||
}
|
||||
|
||||
@ -164,6 +170,8 @@ idmap_lookup_id(struct idmap_hashtable *h, __u32 id)
|
||||
struct idmap_hashent *he = idmap_id_hash(h, id);
|
||||
if (he->ih_id != id || he->ih_namelen == 0)
|
||||
return NULL;
|
||||
if (time_after(jiffies, he->ih_expires))
|
||||
return NULL;
|
||||
return he;
|
||||
}
|
||||
|
||||
@ -192,6 +200,7 @@ idmap_update_entry(struct idmap_hashent *he, const char *name,
|
||||
memcpy(he->ih_name, name, namelen);
|
||||
he->ih_name[namelen] = '\0';
|
||||
he->ih_namelen = namelen;
|
||||
he->ih_expires = jiffies + nfs_idmap_cache_timeout;
|
||||
}
|
||||
|
||||
/*
|
||||
|
178
fs/nfs/inode.c
178
fs/nfs/inode.c
@ -40,6 +40,7 @@
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "nfs4_fs.h"
|
||||
#include "callback.h"
|
||||
#include "delegation.h"
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_VFS
|
||||
@ -221,10 +222,10 @@ nfs_calc_block_size(u64 tsize)
|
||||
static inline unsigned long
|
||||
nfs_block_size(unsigned long bsize, unsigned char *nrbitsp)
|
||||
{
|
||||
if (bsize < 1024)
|
||||
bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
|
||||
else if (bsize >= NFS_MAX_FILE_IO_BUFFER_SIZE)
|
||||
bsize = NFS_MAX_FILE_IO_BUFFER_SIZE;
|
||||
if (bsize < NFS_MIN_FILE_IO_SIZE)
|
||||
bsize = NFS_DEF_FILE_IO_SIZE;
|
||||
else if (bsize >= NFS_MAX_FILE_IO_SIZE)
|
||||
bsize = NFS_MAX_FILE_IO_SIZE;
|
||||
|
||||
return nfs_block_bits(bsize, nrbitsp);
|
||||
}
|
||||
@ -307,20 +308,15 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
|
||||
max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
|
||||
if (server->rsize > max_rpc_payload)
|
||||
server->rsize = max_rpc_payload;
|
||||
if (server->rsize > NFS_MAX_FILE_IO_SIZE)
|
||||
server->rsize = NFS_MAX_FILE_IO_SIZE;
|
||||
server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
||||
|
||||
if (server->wsize > max_rpc_payload)
|
||||
server->wsize = max_rpc_payload;
|
||||
|
||||
server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
||||
if (server->rpages > NFS_READ_MAXIOV) {
|
||||
server->rpages = NFS_READ_MAXIOV;
|
||||
server->rsize = server->rpages << PAGE_CACHE_SHIFT;
|
||||
}
|
||||
|
||||
if (server->wsize > NFS_MAX_FILE_IO_SIZE)
|
||||
server->wsize = NFS_MAX_FILE_IO_SIZE;
|
||||
server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
||||
if (server->wpages > NFS_WRITE_MAXIOV) {
|
||||
server->wpages = NFS_WRITE_MAXIOV;
|
||||
server->wsize = server->wpages << PAGE_CACHE_SHIFT;
|
||||
}
|
||||
|
||||
if (sb->s_blocksize == 0)
|
||||
sb->s_blocksize = nfs_block_bits(server->wsize,
|
||||
@ -417,7 +413,6 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data)
|
||||
|
||||
clnt->cl_intr = 1;
|
||||
clnt->cl_softrtry = 1;
|
||||
clnt->cl_chatty = 1;
|
||||
|
||||
return clnt;
|
||||
|
||||
@ -575,11 +570,10 @@ nfs_statfs(struct super_block *sb, struct kstatfs *buf)
|
||||
buf->f_namelen = server->namelen;
|
||||
out:
|
||||
unlock_kernel();
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
printk(KERN_WARNING "nfs_statfs: statfs error = %d\n", -error);
|
||||
dprintk("%s: statfs error = %d\n", __FUNCTION__, -error);
|
||||
buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
|
||||
goto out;
|
||||
|
||||
@ -958,6 +952,8 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
|
||||
int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
|
||||
int err;
|
||||
|
||||
/* Flush out writes to the server in order to update c/mtime */
|
||||
nfs_sync_inode(inode, 0, 0, FLUSH_WAIT|FLUSH_NOCOMMIT);
|
||||
if (__IS_FLG(inode, MS_NOATIME))
|
||||
need_atime = 0;
|
||||
else if (__IS_FLG(inode, MS_NODIRATIME) && S_ISDIR(inode->i_mode))
|
||||
@ -1252,6 +1248,33 @@ void nfs_end_data_update(struct inode *inode)
|
||||
atomic_dec(&nfsi->data_updates);
|
||||
}
|
||||
|
||||
static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
|
||||
if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0
|
||||
&& nfsi->change_attr == fattr->pre_change_attr) {
|
||||
nfsi->change_attr = fattr->change_attr;
|
||||
nfsi->cache_change_attribute = jiffies;
|
||||
}
|
||||
|
||||
/* If we have atomic WCC data, we may update some attributes */
|
||||
if ((fattr->valid & NFS_ATTR_WCC) != 0) {
|
||||
if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) {
|
||||
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
|
||||
nfsi->cache_change_attribute = jiffies;
|
||||
}
|
||||
if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
|
||||
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
|
||||
nfsi->cache_change_attribute = jiffies;
|
||||
}
|
||||
if (inode->i_size == fattr->pre_size && nfsi->npages == 0) {
|
||||
inode->i_size = fattr->size;
|
||||
nfsi->cache_change_attribute = jiffies;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_check_inode_attributes - verify consistency of the inode attribute cache
|
||||
* @inode - pointer to inode
|
||||
@ -1268,22 +1291,20 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
|
||||
int data_unstable;
|
||||
|
||||
|
||||
if ((fattr->valid & NFS_ATTR_FATTR) == 0)
|
||||
return 0;
|
||||
|
||||
/* Are we in the process of updating data on the server? */
|
||||
data_unstable = nfs_caches_unstable(inode);
|
||||
|
||||
if (fattr->valid & NFS_ATTR_FATTR_V4) {
|
||||
if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0
|
||||
&& nfsi->change_attr == fattr->pre_change_attr)
|
||||
nfsi->change_attr = fattr->change_attr;
|
||||
if (nfsi->change_attr != fattr->change_attr) {
|
||||
nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
|
||||
if (!data_unstable)
|
||||
nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE;
|
||||
}
|
||||
}
|
||||
/* Do atomic weak cache consistency updates */
|
||||
nfs_wcc_update_inode(inode, fattr);
|
||||
|
||||
if ((fattr->valid & NFS_ATTR_FATTR) == 0) {
|
||||
return 0;
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
|
||||
nfsi->change_attr != fattr->change_attr) {
|
||||
nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
|
||||
if (!data_unstable)
|
||||
nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE;
|
||||
}
|
||||
|
||||
/* Has the inode gone and changed behind our back? */
|
||||
@ -1295,14 +1316,6 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
|
||||
cur_size = i_size_read(inode);
|
||||
new_isize = nfs_size_to_loff_t(fattr->size);
|
||||
|
||||
/* If we have atomic WCC data, we may update some attributes */
|
||||
if ((fattr->valid & NFS_ATTR_WCC) != 0) {
|
||||
if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
|
||||
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
|
||||
if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime))
|
||||
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
|
||||
}
|
||||
|
||||
/* Verify a few of the more important attributes */
|
||||
if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
|
||||
nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
|
||||
@ -1410,14 +1423,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
||||
if ((fattr->valid & NFS_ATTR_FATTR) == 0)
|
||||
return 0;
|
||||
|
||||
if (nfsi->fileid != fattr->fileid) {
|
||||
printk(KERN_ERR "%s: inode number mismatch\n"
|
||||
"expected (%s/0x%Lx), got (%s/0x%Lx)\n",
|
||||
__FUNCTION__,
|
||||
inode->i_sb->s_id, (long long)nfsi->fileid,
|
||||
inode->i_sb->s_id, (long long)fattr->fileid);
|
||||
goto out_err;
|
||||
}
|
||||
if (nfsi->fileid != fattr->fileid)
|
||||
goto out_fileid;
|
||||
|
||||
/*
|
||||
* Make sure the inode's type hasn't changed.
|
||||
@ -1436,6 +1443,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
||||
if (data_stable)
|
||||
nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME);
|
||||
|
||||
/* Do atomic weak cache consistency updates */
|
||||
nfs_wcc_update_inode(inode, fattr);
|
||||
|
||||
/* Check if our cached file size is stale */
|
||||
new_isize = nfs_size_to_loff_t(fattr->size);
|
||||
cur_isize = i_size_read(inode);
|
||||
@ -1539,6 +1549,13 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
||||
*/
|
||||
nfs_invalidate_inode(inode);
|
||||
return -ESTALE;
|
||||
|
||||
out_fileid:
|
||||
printk(KERN_ERR "NFS: server %s error: fileid changed\n"
|
||||
"fsid %s: expected fileid 0x%Lx, got 0x%Lx\n",
|
||||
NFS_SERVER(inode)->hostname, inode->i_sb->s_id,
|
||||
(long long)nfsi->fileid, (long long)fattr->fileid);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1820,25 +1837,10 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
|
||||
}
|
||||
clnt->cl_intr = 1;
|
||||
clnt->cl_softrtry = 1;
|
||||
clnt->cl_chatty = 1;
|
||||
clp->cl_rpcclient = clnt;
|
||||
clp->cl_cred = rpcauth_lookupcred(clnt->cl_auth, 0);
|
||||
if (IS_ERR(clp->cl_cred)) {
|
||||
up_write(&clp->cl_sem);
|
||||
err = PTR_ERR(clp->cl_cred);
|
||||
clp->cl_cred = NULL;
|
||||
goto out_fail;
|
||||
}
|
||||
memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
|
||||
nfs_idmap_new(clp);
|
||||
}
|
||||
if (list_empty(&clp->cl_superblocks)) {
|
||||
err = nfs4_init_client(clp);
|
||||
if (err != 0) {
|
||||
up_write(&clp->cl_sem);
|
||||
goto out_fail;
|
||||
}
|
||||
}
|
||||
list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
|
||||
clnt = rpc_clone_client(clp->cl_rpcclient);
|
||||
if (!IS_ERR(clnt))
|
||||
@ -2033,6 +2035,35 @@ static struct file_system_type nfs4_fs_type = {
|
||||
.fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
|
||||
};
|
||||
|
||||
static const int nfs_set_port_min = 0;
|
||||
static const int nfs_set_port_max = 65535;
|
||||
static int param_set_port(const char *val, struct kernel_param *kp)
|
||||
{
|
||||
char *endp;
|
||||
int num = simple_strtol(val, &endp, 0);
|
||||
if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max)
|
||||
return -EINVAL;
|
||||
*((int *)kp->arg) = num;
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_param_call(callback_tcpport, param_set_port, param_get_int,
|
||||
&nfs_callback_set_tcpport, 0644);
|
||||
|
||||
static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
|
||||
{
|
||||
char *endp;
|
||||
int num = simple_strtol(val, &endp, 0);
|
||||
int jif = num * HZ;
|
||||
if (endp == val || *endp || num < 0 || jif < num)
|
||||
return -EINVAL;
|
||||
*((int *)kp->arg) = jif;
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
|
||||
&nfs_idmap_cache_timeout, 0644);
|
||||
|
||||
#define nfs4_init_once(nfsi) \
|
||||
do { \
|
||||
INIT_LIST_HEAD(&(nfsi)->open_states); \
|
||||
@ -2040,8 +2071,25 @@ static struct file_system_type nfs4_fs_type = {
|
||||
nfsi->delegation_state = 0; \
|
||||
init_rwsem(&nfsi->rwsem); \
|
||||
} while(0)
|
||||
#define register_nfs4fs() register_filesystem(&nfs4_fs_type)
|
||||
#define unregister_nfs4fs() unregister_filesystem(&nfs4_fs_type)
|
||||
|
||||
static inline int register_nfs4fs(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = nfs_register_sysctl();
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = register_filesystem(&nfs4_fs_type);
|
||||
if (ret != 0)
|
||||
nfs_unregister_sysctl();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void unregister_nfs4fs(void)
|
||||
{
|
||||
unregister_filesystem(&nfs4_fs_type);
|
||||
nfs_unregister_sysctl();
|
||||
}
|
||||
#else
|
||||
#define nfs4_init_once(nfsi) \
|
||||
do { } while (0)
|
||||
@ -2166,11 +2214,11 @@ out:
|
||||
#ifdef CONFIG_PROC_FS
|
||||
rpc_proc_unregister("nfs");
|
||||
#endif
|
||||
nfs_destroy_writepagecache();
|
||||
#ifdef CONFIG_NFS_DIRECTIO
|
||||
out0:
|
||||
nfs_destroy_directcache();
|
||||
out0:
|
||||
#endif
|
||||
nfs_destroy_writepagecache();
|
||||
out1:
|
||||
nfs_destroy_readpagecache();
|
||||
out2:
|
||||
|
@ -82,7 +82,6 @@ mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version,
|
||||
RPC_AUTH_UNIX);
|
||||
if (!IS_ERR(clnt)) {
|
||||
clnt->cl_softrtry = 1;
|
||||
clnt->cl_chatty = 1;
|
||||
clnt->cl_oneshot = 1;
|
||||
clnt->cl_intr = 1;
|
||||
}
|
||||
|
@ -146,23 +146,23 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
|
||||
return p;
|
||||
}
|
||||
|
||||
#define SATTR(p, attr, flag, field) \
|
||||
*p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
|
||||
static inline u32 *
|
||||
xdr_encode_sattr(u32 *p, struct iattr *attr)
|
||||
{
|
||||
SATTR(p, attr, ATTR_MODE, ia_mode);
|
||||
SATTR(p, attr, ATTR_UID, ia_uid);
|
||||
SATTR(p, attr, ATTR_GID, ia_gid);
|
||||
SATTR(p, attr, ATTR_SIZE, ia_size);
|
||||
const u32 not_set = __constant_htonl(0xFFFFFFFF);
|
||||
|
||||
*p++ = (attr->ia_valid & ATTR_MODE) ? htonl(attr->ia_mode) : not_set;
|
||||
*p++ = (attr->ia_valid & ATTR_UID) ? htonl(attr->ia_uid) : not_set;
|
||||
*p++ = (attr->ia_valid & ATTR_GID) ? htonl(attr->ia_gid) : not_set;
|
||||
*p++ = (attr->ia_valid & ATTR_SIZE) ? htonl(attr->ia_size) : not_set;
|
||||
|
||||
if (attr->ia_valid & ATTR_ATIME_SET) {
|
||||
p = xdr_encode_time(p, &attr->ia_atime);
|
||||
} else if (attr->ia_valid & ATTR_ATIME) {
|
||||
p = xdr_encode_current_server_time(p, &attr->ia_atime);
|
||||
} else {
|
||||
*p++ = ~(u32) 0;
|
||||
*p++ = ~(u32) 0;
|
||||
*p++ = not_set;
|
||||
*p++ = not_set;
|
||||
}
|
||||
|
||||
if (attr->ia_valid & ATTR_MTIME_SET) {
|
||||
@ -170,12 +170,11 @@ xdr_encode_sattr(u32 *p, struct iattr *attr)
|
||||
} else if (attr->ia_valid & ATTR_MTIME) {
|
||||
p = xdr_encode_current_server_time(p, &attr->ia_mtime);
|
||||
} else {
|
||||
*p++ = ~(u32) 0;
|
||||
*p++ = ~(u32) 0;
|
||||
*p++ = not_set;
|
||||
*p++ = not_set;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
#undef SATTR
|
||||
|
||||
/*
|
||||
* NFS encode functions
|
||||
|
@ -68,6 +68,23 @@ nfs3_async_handle_jukebox(struct rpc_task *task)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle,
|
||||
struct nfs_fsinfo *info)
|
||||
{
|
||||
int status;
|
||||
|
||||
dprintk("%s: call fsinfo\n", __FUNCTION__);
|
||||
nfs_fattr_init(info->fattr);
|
||||
status = rpc_call(client, NFS3PROC_FSINFO, fhandle, info, 0);
|
||||
dprintk("%s: reply fsinfo: %d\n", __FUNCTION__, status);
|
||||
if (!(info->fattr->valid & NFS_ATTR_FATTR)) {
|
||||
status = rpc_call(client, NFS3PROC_GETATTR, fhandle, info->fattr, 0);
|
||||
dprintk("%s: reply getattr: %d\n", __FUNCTION__, status);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bare-bones access to getattr: this is for nfs_read_super.
|
||||
*/
|
||||
@ -77,14 +94,9 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
{
|
||||
int status;
|
||||
|
||||
dprintk("%s: call fsinfo\n", __FUNCTION__);
|
||||
nfs_fattr_init(info->fattr);
|
||||
status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0);
|
||||
dprintk("%s: reply fsinfo: %d\n", __FUNCTION__, status);
|
||||
if (!(info->fattr->valid & NFS_ATTR_FATTR)) {
|
||||
status = rpc_call(server->client_sys, NFS3PROC_GETATTR, fhandle, info->fattr, 0);
|
||||
dprintk("%s: reply getattr: %d\n", __FUNCTION__, status);
|
||||
}
|
||||
status = do_proc_get_root(server->client, fhandle, info);
|
||||
if (status && server->client_sys != server->client)
|
||||
status = do_proc_get_root(server->client_sys, fhandle, info);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -732,19 +744,23 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
|
||||
extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
|
||||
|
||||
static void
|
||||
nfs3_read_done(struct rpc_task *task)
|
||||
static void nfs3_read_done(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
|
||||
struct nfs_read_data *data = calldata;
|
||||
|
||||
if (nfs3_async_handle_jukebox(task))
|
||||
return;
|
||||
/* Call back common NFS readpage processing */
|
||||
if (task->tk_status >= 0)
|
||||
nfs_refresh_inode(data->inode, &data->fattr);
|
||||
nfs_readpage_result(task);
|
||||
nfs_readpage_result(task, calldata);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs3_read_ops = {
|
||||
.rpc_call_done = nfs3_read_done,
|
||||
.rpc_release = nfs_readdata_release,
|
||||
};
|
||||
|
||||
static void
|
||||
nfs3_proc_read_setup(struct nfs_read_data *data)
|
||||
{
|
||||
@ -762,23 +778,26 @@ nfs3_proc_read_setup(struct nfs_read_data *data)
|
||||
flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
|
||||
|
||||
/* Finalize the task. */
|
||||
rpc_init_task(task, NFS_CLIENT(inode), nfs3_read_done, flags);
|
||||
rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs3_read_ops, data);
|
||||
rpc_call_setup(task, &msg, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
nfs3_write_done(struct rpc_task *task)
|
||||
static void nfs3_write_done(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_write_data *data;
|
||||
struct nfs_write_data *data = calldata;
|
||||
|
||||
if (nfs3_async_handle_jukebox(task))
|
||||
return;
|
||||
data = (struct nfs_write_data *)task->tk_calldata;
|
||||
if (task->tk_status >= 0)
|
||||
nfs_post_op_update_inode(data->inode, data->res.fattr);
|
||||
nfs_writeback_done(task);
|
||||
nfs_writeback_done(task, calldata);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs3_write_ops = {
|
||||
.rpc_call_done = nfs3_write_done,
|
||||
.rpc_release = nfs_writedata_release,
|
||||
};
|
||||
|
||||
static void
|
||||
nfs3_proc_write_setup(struct nfs_write_data *data, int how)
|
||||
{
|
||||
@ -806,23 +825,26 @@ nfs3_proc_write_setup(struct nfs_write_data *data, int how)
|
||||
flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
|
||||
|
||||
/* Finalize the task. */
|
||||
rpc_init_task(task, NFS_CLIENT(inode), nfs3_write_done, flags);
|
||||
rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs3_write_ops, data);
|
||||
rpc_call_setup(task, &msg, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
nfs3_commit_done(struct rpc_task *task)
|
||||
static void nfs3_commit_done(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_write_data *data;
|
||||
struct nfs_write_data *data = calldata;
|
||||
|
||||
if (nfs3_async_handle_jukebox(task))
|
||||
return;
|
||||
data = (struct nfs_write_data *)task->tk_calldata;
|
||||
if (task->tk_status >= 0)
|
||||
nfs_post_op_update_inode(data->inode, data->res.fattr);
|
||||
nfs_commit_done(task);
|
||||
nfs_commit_done(task, calldata);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs3_commit_ops = {
|
||||
.rpc_call_done = nfs3_commit_done,
|
||||
.rpc_release = nfs_commit_release,
|
||||
};
|
||||
|
||||
static void
|
||||
nfs3_proc_commit_setup(struct nfs_write_data *data, int how)
|
||||
{
|
||||
@ -840,7 +862,7 @@ nfs3_proc_commit_setup(struct nfs_write_data *data, int how)
|
||||
flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
|
||||
|
||||
/* Finalize the task. */
|
||||
rpc_init_task(task, NFS_CLIENT(inode), nfs3_commit_done, flags);
|
||||
rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs3_commit_ops, data);
|
||||
rpc_call_setup(task, &msg, 0);
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,7 @@ xdr_encode_sattr(u32 *p, struct iattr *attr)
|
||||
{
|
||||
if (attr->ia_valid & ATTR_MODE) {
|
||||
*p++ = xdr_one;
|
||||
*p++ = htonl(attr->ia_mode);
|
||||
*p++ = htonl(attr->ia_mode & S_IALLUGO);
|
||||
} else {
|
||||
*p++ = xdr_zero;
|
||||
}
|
||||
|
@ -38,7 +38,8 @@ struct idmap;
|
||||
((err) != NFSERR_NOFILEHANDLE))
|
||||
|
||||
enum nfs4_client_state {
|
||||
NFS4CLNT_OK = 0,
|
||||
NFS4CLNT_STATE_RECOVER = 0,
|
||||
NFS4CLNT_LEASE_EXPIRED,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -67,7 +68,6 @@ struct nfs4_client {
|
||||
atomic_t cl_count;
|
||||
|
||||
struct rpc_clnt * cl_rpcclient;
|
||||
struct rpc_cred * cl_cred;
|
||||
|
||||
struct list_head cl_superblocks; /* List of nfs_server structs */
|
||||
|
||||
@ -76,7 +76,6 @@ struct nfs4_client {
|
||||
struct work_struct cl_renewd;
|
||||
struct work_struct cl_recoverd;
|
||||
|
||||
wait_queue_head_t cl_waitq;
|
||||
struct rpc_wait_queue cl_rpcwaitq;
|
||||
|
||||
/* used for the setclientid verifier */
|
||||
@ -182,8 +181,9 @@ struct nfs4_state {
|
||||
|
||||
nfs4_stateid stateid;
|
||||
|
||||
unsigned int nreaders;
|
||||
unsigned int nwriters;
|
||||
unsigned int n_rdonly;
|
||||
unsigned int n_wronly;
|
||||
unsigned int n_rdwr;
|
||||
int state; /* State on the server (R,W, or RW) */
|
||||
atomic_t count;
|
||||
};
|
||||
@ -210,10 +210,10 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t);
|
||||
|
||||
/* nfs4proc.c */
|
||||
extern int nfs4_map_errors(int err);
|
||||
extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short);
|
||||
extern int nfs4_proc_setclientid_confirm(struct nfs4_client *);
|
||||
extern int nfs4_proc_async_renew(struct nfs4_client *);
|
||||
extern int nfs4_proc_renew(struct nfs4_client *);
|
||||
extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short, struct rpc_cred *);
|
||||
extern int nfs4_proc_setclientid_confirm(struct nfs4_client *, struct rpc_cred *);
|
||||
extern int nfs4_proc_async_renew(struct nfs4_client *, struct rpc_cred *);
|
||||
extern int nfs4_proc_renew(struct nfs4_client *, struct rpc_cred *);
|
||||
extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state);
|
||||
extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
|
||||
extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
|
||||
@ -237,8 +237,8 @@ extern void init_nfsv4_state(struct nfs_server *);
|
||||
extern void destroy_nfsv4_state(struct nfs_server *);
|
||||
extern struct nfs4_client *nfs4_get_client(struct in_addr *);
|
||||
extern void nfs4_put_client(struct nfs4_client *clp);
|
||||
extern int nfs4_init_client(struct nfs4_client *clp);
|
||||
extern struct nfs4_client *nfs4_find_client(struct in_addr *);
|
||||
struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp);
|
||||
extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *);
|
||||
|
||||
extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
|
||||
|
1480
fs/nfs/nfs4proc.c
1480
fs/nfs/nfs4proc.c
File diff suppressed because it is too large
Load Diff
@ -54,6 +54,7 @@
|
||||
#include <linux/nfs4.h>
|
||||
#include <linux/nfs_fs.h>
|
||||
#include "nfs4_fs.h"
|
||||
#include "delegation.h"
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_PROC
|
||||
|
||||
@ -61,6 +62,7 @@ void
|
||||
nfs4_renew_state(void *data)
|
||||
{
|
||||
struct nfs4_client *clp = (struct nfs4_client *)data;
|
||||
struct rpc_cred *cred;
|
||||
long lease, timeout;
|
||||
unsigned long last, now;
|
||||
|
||||
@ -68,7 +70,7 @@ nfs4_renew_state(void *data)
|
||||
dprintk("%s: start\n", __FUNCTION__);
|
||||
/* Are there any active superblocks? */
|
||||
if (list_empty(&clp->cl_superblocks))
|
||||
goto out;
|
||||
goto out;
|
||||
spin_lock(&clp->cl_lock);
|
||||
lease = clp->cl_lease_time;
|
||||
last = clp->cl_last_renewal;
|
||||
@ -76,9 +78,17 @@ nfs4_renew_state(void *data)
|
||||
timeout = (2 * lease) / 3 + (long)last - (long)now;
|
||||
/* Are we close to a lease timeout? */
|
||||
if (time_after(now, last + lease/3)) {
|
||||
cred = nfs4_get_renew_cred(clp);
|
||||
if (cred == NULL) {
|
||||
set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
nfs_expire_all_delegations(clp);
|
||||
goto out;
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
/* Queue an asynchronous RENEW. */
|
||||
nfs4_proc_async_renew(clp);
|
||||
nfs4_proc_async_renew(clp, cred);
|
||||
put_rpccred(cred);
|
||||
timeout = (2 * lease) / 3;
|
||||
spin_lock(&clp->cl_lock);
|
||||
} else
|
||||
|
@ -43,6 +43,8 @@
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/nfs_fs.h>
|
||||
#include <linux/nfs_idmap.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
@ -57,8 +59,6 @@ const nfs4_stateid zero_stateid;
|
||||
static DEFINE_SPINLOCK(state_spinlock);
|
||||
static LIST_HEAD(nfs4_clientid_list);
|
||||
|
||||
static void nfs4_recover_state(void *);
|
||||
|
||||
void
|
||||
init_nfsv4_state(struct nfs_server *server)
|
||||
{
|
||||
@ -91,11 +91,10 @@ nfs4_alloc_client(struct in_addr *addr)
|
||||
|
||||
if (nfs_callback_up() < 0)
|
||||
return NULL;
|
||||
if ((clp = kmalloc(sizeof(*clp), GFP_KERNEL)) == NULL) {
|
||||
if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) {
|
||||
nfs_callback_down();
|
||||
return NULL;
|
||||
}
|
||||
memset(clp, 0, sizeof(*clp));
|
||||
memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr));
|
||||
init_rwsem(&clp->cl_sem);
|
||||
INIT_LIST_HEAD(&clp->cl_delegations);
|
||||
@ -103,14 +102,12 @@ nfs4_alloc_client(struct in_addr *addr)
|
||||
INIT_LIST_HEAD(&clp->cl_unused);
|
||||
spin_lock_init(&clp->cl_lock);
|
||||
atomic_set(&clp->cl_count, 1);
|
||||
INIT_WORK(&clp->cl_recoverd, nfs4_recover_state, clp);
|
||||
INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
|
||||
INIT_LIST_HEAD(&clp->cl_superblocks);
|
||||
init_waitqueue_head(&clp->cl_waitq);
|
||||
rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client");
|
||||
clp->cl_rpcclient = ERR_PTR(-EINVAL);
|
||||
clp->cl_boot_time = CURRENT_TIME;
|
||||
clp->cl_state = 1 << NFS4CLNT_OK;
|
||||
clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
|
||||
return clp;
|
||||
}
|
||||
|
||||
@ -127,8 +124,6 @@ nfs4_free_client(struct nfs4_client *clp)
|
||||
kfree(sp);
|
||||
}
|
||||
BUG_ON(!list_empty(&clp->cl_state_owners));
|
||||
if (clp->cl_cred)
|
||||
put_rpccred(clp->cl_cred);
|
||||
nfs_idmap_delete(clp);
|
||||
if (!IS_ERR(clp->cl_rpcclient))
|
||||
rpc_shutdown_client(clp->cl_rpcclient);
|
||||
@ -193,27 +188,22 @@ nfs4_put_client(struct nfs4_client *clp)
|
||||
list_del(&clp->cl_servers);
|
||||
spin_unlock(&state_spinlock);
|
||||
BUG_ON(!list_empty(&clp->cl_superblocks));
|
||||
wake_up_all(&clp->cl_waitq);
|
||||
rpc_wake_up(&clp->cl_rpcwaitq);
|
||||
nfs4_kill_renewd(clp);
|
||||
nfs4_free_client(clp);
|
||||
}
|
||||
|
||||
static int __nfs4_init_client(struct nfs4_client *clp)
|
||||
static int nfs4_init_client(struct nfs4_client *clp, struct rpc_cred *cred)
|
||||
{
|
||||
int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, nfs_callback_tcpport);
|
||||
int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK,
|
||||
nfs_callback_tcpport, cred);
|
||||
if (status == 0)
|
||||
status = nfs4_proc_setclientid_confirm(clp);
|
||||
status = nfs4_proc_setclientid_confirm(clp, cred);
|
||||
if (status == 0)
|
||||
nfs4_schedule_state_renewal(clp);
|
||||
return status;
|
||||
}
|
||||
|
||||
int nfs4_init_client(struct nfs4_client *clp)
|
||||
{
|
||||
return nfs4_map_errors(__nfs4_init_client(clp));
|
||||
}
|
||||
|
||||
u32
|
||||
nfs4_alloc_lockowner_id(struct nfs4_client *clp)
|
||||
{
|
||||
@ -235,6 +225,32 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred)
|
||||
return sp;
|
||||
}
|
||||
|
||||
struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp)
|
||||
{
|
||||
struct nfs4_state_owner *sp;
|
||||
struct rpc_cred *cred = NULL;
|
||||
|
||||
list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
|
||||
if (list_empty(&sp->so_states))
|
||||
continue;
|
||||
cred = get_rpccred(sp->so_cred);
|
||||
break;
|
||||
}
|
||||
return cred;
|
||||
}
|
||||
|
||||
struct rpc_cred *nfs4_get_setclientid_cred(struct nfs4_client *clp)
|
||||
{
|
||||
struct nfs4_state_owner *sp;
|
||||
|
||||
if (!list_empty(&clp->cl_state_owners)) {
|
||||
sp = list_entry(clp->cl_state_owners.next,
|
||||
struct nfs4_state_owner, so_list);
|
||||
return get_rpccred(sp->so_cred);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nfs4_state_owner *
|
||||
nfs4_find_state_owner(struct nfs4_client *clp, struct rpc_cred *cred)
|
||||
{
|
||||
@ -349,14 +365,9 @@ nfs4_alloc_open_state(void)
|
||||
{
|
||||
struct nfs4_state *state;
|
||||
|
||||
state = kmalloc(sizeof(*state), GFP_KERNEL);
|
||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return NULL;
|
||||
state->state = 0;
|
||||
state->nreaders = 0;
|
||||
state->nwriters = 0;
|
||||
state->flags = 0;
|
||||
memset(state->stateid.data, 0, sizeof(state->stateid.data));
|
||||
atomic_set(&state->count, 1);
|
||||
INIT_LIST_HEAD(&state->lock_states);
|
||||
spin_lock_init(&state->state_lock);
|
||||
@ -475,15 +486,23 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode)
|
||||
/* Protect against nfs4_find_state() */
|
||||
spin_lock(&owner->so_lock);
|
||||
spin_lock(&inode->i_lock);
|
||||
if (mode & FMODE_READ)
|
||||
state->nreaders--;
|
||||
if (mode & FMODE_WRITE)
|
||||
state->nwriters--;
|
||||
switch (mode & (FMODE_READ | FMODE_WRITE)) {
|
||||
case FMODE_READ:
|
||||
state->n_rdonly--;
|
||||
break;
|
||||
case FMODE_WRITE:
|
||||
state->n_wronly--;
|
||||
break;
|
||||
case FMODE_READ|FMODE_WRITE:
|
||||
state->n_rdwr--;
|
||||
}
|
||||
oldstate = newstate = state->state;
|
||||
if (state->nreaders == 0)
|
||||
newstate &= ~FMODE_READ;
|
||||
if (state->nwriters == 0)
|
||||
newstate &= ~FMODE_WRITE;
|
||||
if (state->n_rdwr == 0) {
|
||||
if (state->n_rdonly == 0)
|
||||
newstate &= ~FMODE_READ;
|
||||
if (state->n_wronly == 0)
|
||||
newstate &= ~FMODE_WRITE;
|
||||
}
|
||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
|
||||
nfs4_state_set_mode_locked(state, newstate);
|
||||
oldstate = newstate;
|
||||
@ -733,45 +752,43 @@ out:
|
||||
}
|
||||
|
||||
static int reclaimer(void *);
|
||||
struct reclaimer_args {
|
||||
struct nfs4_client *clp;
|
||||
struct completion complete;
|
||||
};
|
||||
|
||||
static inline void nfs4_clear_recover_bit(struct nfs4_client *clp)
|
||||
{
|
||||
smp_mb__before_clear_bit();
|
||||
clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state);
|
||||
smp_mb__after_clear_bit();
|
||||
wake_up_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER);
|
||||
rpc_wake_up(&clp->cl_rpcwaitq);
|
||||
}
|
||||
|
||||
/*
|
||||
* State recovery routine
|
||||
*/
|
||||
void
|
||||
nfs4_recover_state(void *data)
|
||||
static void nfs4_recover_state(struct nfs4_client *clp)
|
||||
{
|
||||
struct nfs4_client *clp = (struct nfs4_client *)data;
|
||||
struct reclaimer_args args = {
|
||||
.clp = clp,
|
||||
};
|
||||
might_sleep();
|
||||
struct task_struct *task;
|
||||
|
||||
init_completion(&args.complete);
|
||||
|
||||
if (kernel_thread(reclaimer, &args, CLONE_KERNEL) < 0)
|
||||
goto out_failed_clear;
|
||||
wait_for_completion(&args.complete);
|
||||
return;
|
||||
out_failed_clear:
|
||||
set_bit(NFS4CLNT_OK, &clp->cl_state);
|
||||
wake_up_all(&clp->cl_waitq);
|
||||
rpc_wake_up(&clp->cl_rpcwaitq);
|
||||
__module_get(THIS_MODULE);
|
||||
atomic_inc(&clp->cl_count);
|
||||
task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim",
|
||||
NIPQUAD(clp->cl_addr));
|
||||
if (!IS_ERR(task))
|
||||
return;
|
||||
nfs4_clear_recover_bit(clp);
|
||||
nfs4_put_client(clp);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Schedule a state recovery attempt
|
||||
*/
|
||||
void
|
||||
nfs4_schedule_state_recovery(struct nfs4_client *clp)
|
||||
void nfs4_schedule_state_recovery(struct nfs4_client *clp)
|
||||
{
|
||||
if (!clp)
|
||||
return;
|
||||
if (test_and_clear_bit(NFS4CLNT_OK, &clp->cl_state))
|
||||
schedule_work(&clp->cl_recoverd);
|
||||
if (test_and_set_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0)
|
||||
nfs4_recover_state(clp);
|
||||
}
|
||||
|
||||
static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_state *state)
|
||||
@ -887,18 +904,14 @@ static void nfs4_state_mark_reclaim(struct nfs4_client *clp)
|
||||
|
||||
static int reclaimer(void *ptr)
|
||||
{
|
||||
struct reclaimer_args *args = (struct reclaimer_args *)ptr;
|
||||
struct nfs4_client *clp = args->clp;
|
||||
struct nfs4_client *clp = ptr;
|
||||
struct nfs4_state_owner *sp;
|
||||
struct nfs4_state_recovery_ops *ops;
|
||||
struct rpc_cred *cred;
|
||||
int status = 0;
|
||||
|
||||
daemonize("%u.%u.%u.%u-reclaim", NIPQUAD(clp->cl_addr));
|
||||
allow_signal(SIGKILL);
|
||||
|
||||
atomic_inc(&clp->cl_count);
|
||||
complete(&args->complete);
|
||||
|
||||
/* Ensure exclusive access to NFSv4 state */
|
||||
lock_kernel();
|
||||
down_write(&clp->cl_sem);
|
||||
@ -906,20 +919,33 @@ static int reclaimer(void *ptr)
|
||||
if (list_empty(&clp->cl_superblocks))
|
||||
goto out;
|
||||
restart_loop:
|
||||
status = nfs4_proc_renew(clp);
|
||||
switch (status) {
|
||||
case 0:
|
||||
case -NFS4ERR_CB_PATH_DOWN:
|
||||
goto out;
|
||||
case -NFS4ERR_STALE_CLIENTID:
|
||||
case -NFS4ERR_LEASE_MOVED:
|
||||
ops = &nfs4_reboot_recovery_ops;
|
||||
break;
|
||||
default:
|
||||
ops = &nfs4_network_partition_recovery_ops;
|
||||
};
|
||||
ops = &nfs4_network_partition_recovery_ops;
|
||||
/* Are there any open files on this volume? */
|
||||
cred = nfs4_get_renew_cred(clp);
|
||||
if (cred != NULL) {
|
||||
/* Yes there are: try to renew the old lease */
|
||||
status = nfs4_proc_renew(clp, cred);
|
||||
switch (status) {
|
||||
case 0:
|
||||
case -NFS4ERR_CB_PATH_DOWN:
|
||||
put_rpccred(cred);
|
||||
goto out;
|
||||
case -NFS4ERR_STALE_CLIENTID:
|
||||
case -NFS4ERR_LEASE_MOVED:
|
||||
ops = &nfs4_reboot_recovery_ops;
|
||||
}
|
||||
} else {
|
||||
/* "reboot" to ensure we clear all state on the server */
|
||||
clp->cl_boot_time = CURRENT_TIME;
|
||||
cred = nfs4_get_setclientid_cred(clp);
|
||||
}
|
||||
/* We're going to have to re-establish a clientid */
|
||||
nfs4_state_mark_reclaim(clp);
|
||||
status = __nfs4_init_client(clp);
|
||||
status = -ENOENT;
|
||||
if (cred != NULL) {
|
||||
status = nfs4_init_client(clp, cred);
|
||||
put_rpccred(cred);
|
||||
}
|
||||
if (status)
|
||||
goto out_error;
|
||||
/* Mark all delegations for reclaim */
|
||||
@ -940,14 +966,13 @@ restart_loop:
|
||||
}
|
||||
nfs_delegation_reap_unclaimed(clp);
|
||||
out:
|
||||
set_bit(NFS4CLNT_OK, &clp->cl_state);
|
||||
up_write(&clp->cl_sem);
|
||||
unlock_kernel();
|
||||
wake_up_all(&clp->cl_waitq);
|
||||
rpc_wake_up(&clp->cl_rpcwaitq);
|
||||
if (status == -NFS4ERR_CB_PATH_DOWN)
|
||||
nfs_handle_cb_pathdown(clp);
|
||||
nfs4_clear_recover_bit(clp);
|
||||
nfs4_put_client(clp);
|
||||
module_put_and_exit(0);
|
||||
return 0;
|
||||
out_error:
|
||||
printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n",
|
||||
|
187
fs/nfs/nfs4xdr.c
187
fs/nfs/nfs4xdr.c
@ -392,9 +392,11 @@ static int nfs_stat_to_errno(int);
|
||||
decode_getattr_maxsz)
|
||||
#define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \
|
||||
encode_putfh_maxsz + \
|
||||
encode_delegreturn_maxsz)
|
||||
encode_delegreturn_maxsz + \
|
||||
encode_getattr_maxsz)
|
||||
#define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
|
||||
decode_delegreturn_maxsz)
|
||||
decode_delegreturn_maxsz + \
|
||||
decode_getattr_maxsz)
|
||||
#define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \
|
||||
encode_putfh_maxsz + \
|
||||
encode_getattr_maxsz)
|
||||
@ -564,7 +566,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
|
||||
}
|
||||
if (iap->ia_valid & ATTR_MODE) {
|
||||
bmval1 |= FATTR4_WORD1_MODE;
|
||||
WRITE32(iap->ia_mode);
|
||||
WRITE32(iap->ia_mode & S_IALLUGO);
|
||||
}
|
||||
if (iap->ia_valid & ATTR_UID) {
|
||||
bmval1 |= FATTR4_WORD1_OWNER;
|
||||
@ -742,69 +744,80 @@ static int encode_link(struct xdr_stream *xdr, const struct qstr *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int nfs4_lock_type(struct file_lock *fl, int block)
|
||||
{
|
||||
if ((fl->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) == F_RDLCK)
|
||||
return block ? NFS4_READW_LT : NFS4_READ_LT;
|
||||
return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT;
|
||||
}
|
||||
|
||||
static inline uint64_t nfs4_lock_length(struct file_lock *fl)
|
||||
{
|
||||
if (fl->fl_end == OFFSET_MAX)
|
||||
return ~(uint64_t)0;
|
||||
return fl->fl_end - fl->fl_start + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* opcode,type,reclaim,offset,length,new_lock_owner = 32
|
||||
* open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
|
||||
*/
|
||||
static int encode_lock(struct xdr_stream *xdr, const struct nfs_lockargs *arg)
|
||||
static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args)
|
||||
{
|
||||
uint32_t *p;
|
||||
struct nfs_lock_opargs *opargs = arg->u.lock;
|
||||
|
||||
RESERVE_SPACE(32);
|
||||
WRITE32(OP_LOCK);
|
||||
WRITE32(arg->type);
|
||||
WRITE32(opargs->reclaim);
|
||||
WRITE64(arg->offset);
|
||||
WRITE64(arg->length);
|
||||
WRITE32(opargs->new_lock_owner);
|
||||
if (opargs->new_lock_owner){
|
||||
WRITE32(nfs4_lock_type(args->fl, args->block));
|
||||
WRITE32(args->reclaim);
|
||||
WRITE64(args->fl->fl_start);
|
||||
WRITE64(nfs4_lock_length(args->fl));
|
||||
WRITE32(args->new_lock_owner);
|
||||
if (args->new_lock_owner){
|
||||
RESERVE_SPACE(40);
|
||||
WRITE32(opargs->open_seqid->sequence->counter);
|
||||
WRITEMEM(opargs->open_stateid->data, sizeof(opargs->open_stateid->data));
|
||||
WRITE32(opargs->lock_seqid->sequence->counter);
|
||||
WRITE64(opargs->lock_owner.clientid);
|
||||
WRITE32(args->open_seqid->sequence->counter);
|
||||
WRITEMEM(args->open_stateid->data, sizeof(args->open_stateid->data));
|
||||
WRITE32(args->lock_seqid->sequence->counter);
|
||||
WRITE64(args->lock_owner.clientid);
|
||||
WRITE32(4);
|
||||
WRITE32(opargs->lock_owner.id);
|
||||
WRITE32(args->lock_owner.id);
|
||||
}
|
||||
else {
|
||||
RESERVE_SPACE(20);
|
||||
WRITEMEM(opargs->lock_stateid->data, sizeof(opargs->lock_stateid->data));
|
||||
WRITE32(opargs->lock_seqid->sequence->counter);
|
||||
WRITEMEM(args->lock_stateid->data, sizeof(args->lock_stateid->data));
|
||||
WRITE32(args->lock_seqid->sequence->counter);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockargs *arg)
|
||||
static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args)
|
||||
{
|
||||
uint32_t *p;
|
||||
struct nfs_lowner *opargs = arg->u.lockt;
|
||||
|
||||
RESERVE_SPACE(40);
|
||||
WRITE32(OP_LOCKT);
|
||||
WRITE32(arg->type);
|
||||
WRITE64(arg->offset);
|
||||
WRITE64(arg->length);
|
||||
WRITE64(opargs->clientid);
|
||||
WRITE32(nfs4_lock_type(args->fl, 0));
|
||||
WRITE64(args->fl->fl_start);
|
||||
WRITE64(nfs4_lock_length(args->fl));
|
||||
WRITE64(args->lock_owner.clientid);
|
||||
WRITE32(4);
|
||||
WRITE32(opargs->id);
|
||||
WRITE32(args->lock_owner.id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int encode_locku(struct xdr_stream *xdr, const struct nfs_lockargs *arg)
|
||||
static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args)
|
||||
{
|
||||
uint32_t *p;
|
||||
struct nfs_locku_opargs *opargs = arg->u.locku;
|
||||
|
||||
RESERVE_SPACE(44);
|
||||
WRITE32(OP_LOCKU);
|
||||
WRITE32(arg->type);
|
||||
WRITE32(opargs->seqid->sequence->counter);
|
||||
WRITEMEM(opargs->stateid->data, sizeof(opargs->stateid->data));
|
||||
WRITE64(arg->offset);
|
||||
WRITE64(arg->length);
|
||||
WRITE32(nfs4_lock_type(args->fl, 0));
|
||||
WRITE32(args->seqid->sequence->counter);
|
||||
WRITEMEM(args->stateid->data, sizeof(args->stateid->data));
|
||||
WRITE64(args->fl->fl_start);
|
||||
WRITE64(nfs4_lock_length(args->fl));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -964,9 +977,9 @@ static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_con
|
||||
{
|
||||
uint32_t *p;
|
||||
|
||||
RESERVE_SPACE(8+sizeof(arg->stateid.data));
|
||||
RESERVE_SPACE(8+sizeof(arg->stateid->data));
|
||||
WRITE32(OP_OPEN_CONFIRM);
|
||||
WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data));
|
||||
WRITEMEM(arg->stateid->data, sizeof(arg->stateid->data));
|
||||
WRITE32(arg->seqid->sequence->counter);
|
||||
|
||||
return 0;
|
||||
@ -1499,9 +1512,6 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_opena
|
||||
};
|
||||
int status;
|
||||
|
||||
status = nfs_wait_on_sequence(args->seqid, req->rq_task);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
||||
encode_compound_hdr(&xdr, &hdr);
|
||||
status = encode_putfh(&xdr, args->fh);
|
||||
@ -1538,9 +1548,6 @@ static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct n
|
||||
};
|
||||
int status;
|
||||
|
||||
status = nfs_wait_on_sequence(args->seqid, req->rq_task);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
||||
encode_compound_hdr(&xdr, &hdr);
|
||||
status = encode_putfh(&xdr, args->fh);
|
||||
@ -1558,19 +1565,19 @@ static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, uint32_t *p, struct nf
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
struct compound_hdr hdr = {
|
||||
.nops = 2,
|
||||
.nops = 3,
|
||||
};
|
||||
int status;
|
||||
|
||||
status = nfs_wait_on_sequence(args->seqid, req->rq_task);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
||||
encode_compound_hdr(&xdr, &hdr);
|
||||
status = encode_putfh(&xdr, args->fh);
|
||||
if (status)
|
||||
goto out;
|
||||
status = encode_open(&xdr, args);
|
||||
if (status)
|
||||
goto out;
|
||||
status = encode_getfattr(&xdr, args->bitmask);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
@ -1602,21 +1609,14 @@ out:
|
||||
/*
|
||||
* Encode a LOCK request
|
||||
*/
|
||||
static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
|
||||
static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lock_args *args)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
struct compound_hdr hdr = {
|
||||
.nops = 2,
|
||||
};
|
||||
struct nfs_lock_opargs *opargs = args->u.lock;
|
||||
int status;
|
||||
|
||||
status = nfs_wait_on_sequence(opargs->lock_seqid, req->rq_task);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
/* Do we need to do an open_to_lock_owner? */
|
||||
if (opargs->lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)
|
||||
opargs->new_lock_owner = 0;
|
||||
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
||||
encode_compound_hdr(&xdr, &hdr);
|
||||
status = encode_putfh(&xdr, args->fh);
|
||||
@ -1630,7 +1630,7 @@ out:
|
||||
/*
|
||||
* Encode a LOCKT request
|
||||
*/
|
||||
static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
|
||||
static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockt_args *args)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
struct compound_hdr hdr = {
|
||||
@ -1651,7 +1651,7 @@ out:
|
||||
/*
|
||||
* Encode a LOCKU request
|
||||
*/
|
||||
static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
|
||||
static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_locku_args *args)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
struct compound_hdr hdr = {
|
||||
@ -1985,14 +1985,20 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, uint32_t *p, const str
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
struct compound_hdr hdr = {
|
||||
.nops = 2,
|
||||
.nops = 3,
|
||||
};
|
||||
int status;
|
||||
|
||||
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
||||
encode_compound_hdr(&xdr, &hdr);
|
||||
if ((status = encode_putfh(&xdr, args->fhandle)) == 0)
|
||||
status = encode_delegreturn(&xdr, args->stateid);
|
||||
status = encode_putfh(&xdr, args->fhandle);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
status = encode_delegreturn(&xdr, args->stateid);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
status = encode_getfattr(&xdr, args->bitmask);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -2955,55 +2961,64 @@ static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
|
||||
/*
|
||||
* We create the owner, so we know a proper owner.id length is 4.
|
||||
*/
|
||||
static int decode_lock_denied (struct xdr_stream *xdr, struct nfs_lock_denied *denied)
|
||||
static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
|
||||
{
|
||||
uint64_t offset, length, clientid;
|
||||
uint32_t *p;
|
||||
uint32_t namelen;
|
||||
uint32_t namelen, type;
|
||||
|
||||
READ_BUF(32);
|
||||
READ64(denied->offset);
|
||||
READ64(denied->length);
|
||||
READ32(denied->type);
|
||||
READ64(denied->owner.clientid);
|
||||
READ64(offset);
|
||||
READ64(length);
|
||||
READ32(type);
|
||||
if (fl != NULL) {
|
||||
fl->fl_start = (loff_t)offset;
|
||||
fl->fl_end = fl->fl_start + (loff_t)length - 1;
|
||||
if (length == ~(uint64_t)0)
|
||||
fl->fl_end = OFFSET_MAX;
|
||||
fl->fl_type = F_WRLCK;
|
||||
if (type & 1)
|
||||
fl->fl_type = F_RDLCK;
|
||||
fl->fl_pid = 0;
|
||||
}
|
||||
READ64(clientid);
|
||||
READ32(namelen);
|
||||
READ_BUF(namelen);
|
||||
if (namelen == 4)
|
||||
READ32(denied->owner.id);
|
||||
return -NFS4ERR_DENIED;
|
||||
}
|
||||
|
||||
static int decode_lock(struct xdr_stream *xdr, struct nfs_lockres *res)
|
||||
static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
|
||||
{
|
||||
uint32_t *p;
|
||||
int status;
|
||||
|
||||
status = decode_op_hdr(xdr, OP_LOCK);
|
||||
if (status == 0) {
|
||||
READ_BUF(sizeof(res->u.stateid.data));
|
||||
COPYMEM(res->u.stateid.data, sizeof(res->u.stateid.data));
|
||||
READ_BUF(sizeof(res->stateid.data));
|
||||
COPYMEM(res->stateid.data, sizeof(res->stateid.data));
|
||||
} else if (status == -NFS4ERR_DENIED)
|
||||
return decode_lock_denied(xdr, &res->u.denied);
|
||||
return decode_lock_denied(xdr, NULL);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockres *res)
|
||||
static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res)
|
||||
{
|
||||
int status;
|
||||
status = decode_op_hdr(xdr, OP_LOCKT);
|
||||
if (status == -NFS4ERR_DENIED)
|
||||
return decode_lock_denied(xdr, &res->u.denied);
|
||||
return decode_lock_denied(xdr, res->denied);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res)
|
||||
static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
|
||||
{
|
||||
uint32_t *p;
|
||||
int status;
|
||||
|
||||
status = decode_op_hdr(xdr, OP_LOCKU);
|
||||
if (status == 0) {
|
||||
READ_BUF(sizeof(res->u.stateid.data));
|
||||
COPYMEM(res->u.stateid.data, sizeof(res->u.stateid.data));
|
||||
READ_BUF(sizeof(res->stateid.data));
|
||||
COPYMEM(res->stateid.data, sizeof(res->stateid.data));
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@ -3831,6 +3846,9 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, uint32_t *p, struct
|
||||
if (status)
|
||||
goto out;
|
||||
status = decode_open(&xdr, res);
|
||||
if (status)
|
||||
goto out;
|
||||
decode_getfattr(&xdr, res->f_attr, res->server);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
@ -3864,7 +3882,7 @@ out:
|
||||
/*
|
||||
* Decode LOCK response
|
||||
*/
|
||||
static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
|
||||
static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lock_res *res)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
struct compound_hdr hdr;
|
||||
@ -3885,7 +3903,7 @@ out:
|
||||
/*
|
||||
* Decode LOCKT response
|
||||
*/
|
||||
static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
|
||||
static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockt_res *res)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
struct compound_hdr hdr;
|
||||
@ -3906,7 +3924,7 @@ out:
|
||||
/*
|
||||
* Decode LOCKU response
|
||||
*/
|
||||
static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
|
||||
static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_locku_res *res)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
struct compound_hdr hdr;
|
||||
@ -4174,7 +4192,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s
|
||||
/*
|
||||
* DELEGRETURN request
|
||||
*/
|
||||
static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, void *dummy)
|
||||
static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_delegreturnres *res)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
struct compound_hdr hdr;
|
||||
@ -4182,11 +4200,14 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, void *d
|
||||
|
||||
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
|
||||
status = decode_compound_hdr(&xdr, &hdr);
|
||||
if (status == 0) {
|
||||
status = decode_putfh(&xdr);
|
||||
if (status == 0)
|
||||
status = decode_delegreturn(&xdr);
|
||||
}
|
||||
if (status != 0)
|
||||
goto out;
|
||||
status = decode_putfh(&xdr);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
status = decode_delegreturn(&xdr);
|
||||
decode_getfattr(&xdr, res->fattr, res->server);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -296,8 +296,8 @@ static int __init root_nfs_name(char *name)
|
||||
nfs_port = -1;
|
||||
nfs_data.version = NFS_MOUNT_VERSION;
|
||||
nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */
|
||||
nfs_data.rsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
|
||||
nfs_data.wsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
|
||||
nfs_data.rsize = NFS_DEF_FILE_IO_SIZE;
|
||||
nfs_data.wsize = NFS_DEF_FILE_IO_SIZE;
|
||||
nfs_data.acregmin = 3;
|
||||
nfs_data.acregmax = 60;
|
||||
nfs_data.acdirmin = 30;
|
||||
|
@ -111,6 +111,9 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
|
||||
};
|
||||
int status;
|
||||
|
||||
/* Mask out the non-modebit related stuff from attr->ia_mode */
|
||||
sattr->ia_mode &= S_IALLUGO;
|
||||
|
||||
dprintk("NFS call setattr\n");
|
||||
nfs_fattr_init(fattr);
|
||||
status = rpc_call(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, 0);
|
||||
@ -547,10 +550,9 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
|
||||
extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
|
||||
|
||||
static void
|
||||
nfs_read_done(struct rpc_task *task)
|
||||
static void nfs_read_done(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
|
||||
struct nfs_read_data *data = calldata;
|
||||
|
||||
if (task->tk_status >= 0) {
|
||||
nfs_refresh_inode(data->inode, data->res.fattr);
|
||||
@ -560,9 +562,14 @@ nfs_read_done(struct rpc_task *task)
|
||||
if (data->args.offset + data->args.count >= data->res.fattr->size)
|
||||
data->res.eof = 1;
|
||||
}
|
||||
nfs_readpage_result(task);
|
||||
nfs_readpage_result(task, calldata);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs_read_ops = {
|
||||
.rpc_call_done = nfs_read_done,
|
||||
.rpc_release = nfs_readdata_release,
|
||||
};
|
||||
|
||||
static void
|
||||
nfs_proc_read_setup(struct nfs_read_data *data)
|
||||
{
|
||||
@ -580,20 +587,24 @@ nfs_proc_read_setup(struct nfs_read_data *data)
|
||||
flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
|
||||
|
||||
/* Finalize the task. */
|
||||
rpc_init_task(task, NFS_CLIENT(inode), nfs_read_done, flags);
|
||||
rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs_read_ops, data);
|
||||
rpc_call_setup(task, &msg, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
nfs_write_done(struct rpc_task *task)
|
||||
static void nfs_write_done(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
|
||||
struct nfs_write_data *data = calldata;
|
||||
|
||||
if (task->tk_status >= 0)
|
||||
nfs_post_op_update_inode(data->inode, data->res.fattr);
|
||||
nfs_writeback_done(task);
|
||||
nfs_writeback_done(task, calldata);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs_write_ops = {
|
||||
.rpc_call_done = nfs_write_done,
|
||||
.rpc_release = nfs_writedata_release,
|
||||
};
|
||||
|
||||
static void
|
||||
nfs_proc_write_setup(struct nfs_write_data *data, int how)
|
||||
{
|
||||
@ -614,7 +625,7 @@ nfs_proc_write_setup(struct nfs_write_data *data, int how)
|
||||
flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
|
||||
|
||||
/* Finalize the task. */
|
||||
rpc_init_task(task, NFS_CLIENT(inode), nfs_write_done, flags);
|
||||
rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs_write_ops, data);
|
||||
rpc_call_setup(task, &msg, 0);
|
||||
}
|
||||
|
||||
|
@ -42,9 +42,8 @@ mempool_t *nfs_rdata_mempool;
|
||||
|
||||
#define MIN_POOL_READ (32)
|
||||
|
||||
void nfs_readdata_release(struct rpc_task *task)
|
||||
void nfs_readdata_release(void *data)
|
||||
{
|
||||
struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata;
|
||||
nfs_readdata_free(data);
|
||||
}
|
||||
|
||||
@ -84,7 +83,7 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode,
|
||||
int result;
|
||||
struct nfs_read_data *rdata;
|
||||
|
||||
rdata = nfs_readdata_alloc();
|
||||
rdata = nfs_readdata_alloc(1);
|
||||
if (!rdata)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -220,9 +219,6 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
|
||||
NFS_PROTO(inode)->read_setup(data);
|
||||
|
||||
data->task.tk_cookie = (unsigned long)inode;
|
||||
data->task.tk_calldata = data;
|
||||
/* Release requests */
|
||||
data->task.tk_release = nfs_readdata_release;
|
||||
|
||||
dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n",
|
||||
data->task.tk_pid,
|
||||
@ -287,7 +283,7 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode)
|
||||
|
||||
nbytes = req->wb_bytes;
|
||||
for(;;) {
|
||||
data = nfs_readdata_alloc();
|
||||
data = nfs_readdata_alloc(1);
|
||||
if (!data)
|
||||
goto out_bad;
|
||||
INIT_LIST_HEAD(&data->pages);
|
||||
@ -343,7 +339,7 @@ static int nfs_pagein_one(struct list_head *head, struct inode *inode)
|
||||
if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
|
||||
return nfs_pagein_multi(head, inode);
|
||||
|
||||
data = nfs_readdata_alloc();
|
||||
data = nfs_readdata_alloc(NFS_SERVER(inode)->rpages);
|
||||
if (!data)
|
||||
goto out_bad;
|
||||
|
||||
@ -452,9 +448,9 @@ static void nfs_readpage_result_full(struct nfs_read_data *data, int status)
|
||||
* This is the callback from RPC telling us whether a reply was
|
||||
* received or some error occurred (timeout or socket shutdown).
|
||||
*/
|
||||
void nfs_readpage_result(struct rpc_task *task)
|
||||
void nfs_readpage_result(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata;
|
||||
struct nfs_read_data *data = calldata;
|
||||
struct nfs_readargs *argp = &data->args;
|
||||
struct nfs_readres *resp = &data->res;
|
||||
int status = task->tk_status;
|
||||
|
84
fs/nfs/sysctl.c
Normal file
84
fs/nfs/sysctl.c
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* linux/fs/nfs/sysctl.c
|
||||
*
|
||||
* Sysctl interface to NFS parameters
|
||||
*/
|
||||
#include <linux/config.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nfs4.h>
|
||||
#include <linux/nfs_idmap.h>
|
||||
|
||||
#include "callback.h"
|
||||
|
||||
static const int nfs_set_port_min = 0;
|
||||
static const int nfs_set_port_max = 65535;
|
||||
static struct ctl_table_header *nfs_callback_sysctl_table;
|
||||
/*
|
||||
* Something that isn't CTL_ANY, CTL_NONE or a value that may clash.
|
||||
* Use the same values as fs/lockd/svc.c
|
||||
*/
|
||||
#define CTL_UNNUMBERED -2
|
||||
|
||||
static ctl_table nfs_cb_sysctls[] = {
|
||||
#ifdef CONFIG_NFS_V4
|
||||
{
|
||||
.ctl_name = CTL_UNNUMBERED,
|
||||
.procname = "nfs_callback_tcpport",
|
||||
.data = &nfs_callback_set_tcpport,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_minmax,
|
||||
.extra1 = (int *)&nfs_set_port_min,
|
||||
.extra2 = (int *)&nfs_set_port_max,
|
||||
},
|
||||
{
|
||||
.ctl_name = CTL_UNNUMBERED,
|
||||
.procname = "idmap_cache_timeout",
|
||||
.data = &nfs_idmap_cache_timeout,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
.strategy = &sysctl_jiffies,
|
||||
},
|
||||
#endif
|
||||
{ .ctl_name = 0 }
|
||||
};
|
||||
|
||||
static ctl_table nfs_cb_sysctl_dir[] = {
|
||||
{
|
||||
.ctl_name = CTL_UNNUMBERED,
|
||||
.procname = "nfs",
|
||||
.mode = 0555,
|
||||
.child = nfs_cb_sysctls,
|
||||
},
|
||||
{ .ctl_name = 0 }
|
||||
};
|
||||
|
||||
static ctl_table nfs_cb_sysctl_root[] = {
|
||||
{
|
||||
.ctl_name = CTL_FS,
|
||||
.procname = "fs",
|
||||
.mode = 0555,
|
||||
.child = nfs_cb_sysctl_dir,
|
||||
},
|
||||
{ .ctl_name = 0 }
|
||||
};
|
||||
|
||||
int nfs_register_sysctl(void)
|
||||
{
|
||||
nfs_callback_sysctl_table = register_sysctl_table(nfs_cb_sysctl_root, 0);
|
||||
if (nfs_callback_sysctl_table == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nfs_unregister_sysctl(void)
|
||||
{
|
||||
unregister_sysctl_table(nfs_callback_sysctl_table);
|
||||
nfs_callback_sysctl_table = NULL;
|
||||
}
|
@ -87,10 +87,9 @@ nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
|
||||
* We delay initializing RPC info until after the call to dentry_iput()
|
||||
* in order to minimize races against rename().
|
||||
*/
|
||||
static void
|
||||
nfs_async_unlink_init(struct rpc_task *task)
|
||||
static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata;
|
||||
struct nfs_unlinkdata *data = calldata;
|
||||
struct dentry *dir = data->dir;
|
||||
struct rpc_message msg = {
|
||||
.rpc_cred = data->cred,
|
||||
@ -116,10 +115,9 @@ nfs_async_unlink_init(struct rpc_task *task)
|
||||
*
|
||||
* Do the directory attribute update.
|
||||
*/
|
||||
static void
|
||||
nfs_async_unlink_done(struct rpc_task *task)
|
||||
static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata;
|
||||
struct nfs_unlinkdata *data = calldata;
|
||||
struct dentry *dir = data->dir;
|
||||
struct inode *dir_i;
|
||||
|
||||
@ -141,13 +139,18 @@ nfs_async_unlink_done(struct rpc_task *task)
|
||||
* We need to call nfs_put_unlinkdata as a 'tk_release' task since the
|
||||
* rpc_task would be freed too.
|
||||
*/
|
||||
static void
|
||||
nfs_async_unlink_release(struct rpc_task *task)
|
||||
static void nfs_async_unlink_release(void *calldata)
|
||||
{
|
||||
struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata;
|
||||
struct nfs_unlinkdata *data = calldata;
|
||||
nfs_put_unlinkdata(data);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs_unlink_ops = {
|
||||
.rpc_call_prepare = nfs_async_unlink_init,
|
||||
.rpc_call_done = nfs_async_unlink_done,
|
||||
.rpc_release = nfs_async_unlink_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* nfs_async_unlink - asynchronous unlinking of a file
|
||||
* @dentry: dentry to unlink
|
||||
@ -157,7 +160,6 @@ nfs_async_unlink(struct dentry *dentry)
|
||||
{
|
||||
struct dentry *dir = dentry->d_parent;
|
||||
struct nfs_unlinkdata *data;
|
||||
struct rpc_task *task;
|
||||
struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode);
|
||||
int status = -ENOMEM;
|
||||
|
||||
@ -178,17 +180,13 @@ nfs_async_unlink(struct dentry *dentry)
|
||||
nfs_deletes = data;
|
||||
data->count = 1;
|
||||
|
||||
task = &data->task;
|
||||
rpc_init_task(task, clnt, nfs_async_unlink_done , RPC_TASK_ASYNC);
|
||||
task->tk_calldata = data;
|
||||
task->tk_action = nfs_async_unlink_init;
|
||||
task->tk_release = nfs_async_unlink_release;
|
||||
rpc_init_task(&data->task, clnt, RPC_TASK_ASYNC, &nfs_unlink_ops, data);
|
||||
|
||||
spin_lock(&dentry->d_lock);
|
||||
dentry->d_flags |= DCACHE_NFSFS_RENAMED;
|
||||
spin_unlock(&dentry->d_lock);
|
||||
|
||||
rpc_sleep_on(&nfs_delete_queue, task, NULL, NULL);
|
||||
rpc_sleep_on(&nfs_delete_queue, &data->task, NULL, NULL);
|
||||
status = 0;
|
||||
out:
|
||||
return status;
|
||||
|
@ -89,24 +89,38 @@ static mempool_t *nfs_commit_mempool;
|
||||
|
||||
static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion);
|
||||
|
||||
static inline struct nfs_write_data *nfs_commit_alloc(void)
|
||||
static inline struct nfs_write_data *nfs_commit_alloc(unsigned int pagecount)
|
||||
{
|
||||
struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS);
|
||||
|
||||
if (p) {
|
||||
memset(p, 0, sizeof(*p));
|
||||
INIT_LIST_HEAD(&p->pages);
|
||||
if (pagecount < NFS_PAGEVEC_SIZE)
|
||||
p->pagevec = &p->page_array[0];
|
||||
else {
|
||||
size_t size = ++pagecount * sizeof(struct page *);
|
||||
p->pagevec = kmalloc(size, GFP_NOFS);
|
||||
if (p->pagevec) {
|
||||
memset(p->pagevec, 0, size);
|
||||
} else {
|
||||
mempool_free(p, nfs_commit_mempool);
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline void nfs_commit_free(struct nfs_write_data *p)
|
||||
{
|
||||
if (p && (p->pagevec != &p->page_array[0]))
|
||||
kfree(p->pagevec);
|
||||
mempool_free(p, nfs_commit_mempool);
|
||||
}
|
||||
|
||||
static void nfs_writedata_release(struct rpc_task *task)
|
||||
void nfs_writedata_release(void *wdata)
|
||||
{
|
||||
struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata;
|
||||
nfs_writedata_free(wdata);
|
||||
}
|
||||
|
||||
@ -168,7 +182,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode,
|
||||
int result, written = 0;
|
||||
struct nfs_write_data *wdata;
|
||||
|
||||
wdata = nfs_writedata_alloc();
|
||||
wdata = nfs_writedata_alloc(1);
|
||||
if (!wdata)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -232,19 +246,16 @@ static int nfs_writepage_async(struct nfs_open_context *ctx,
|
||||
unsigned int offset, unsigned int count)
|
||||
{
|
||||
struct nfs_page *req;
|
||||
int status;
|
||||
|
||||
req = nfs_update_request(ctx, inode, page, offset, count);
|
||||
status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
|
||||
if (status < 0)
|
||||
goto out;
|
||||
if (IS_ERR(req))
|
||||
return PTR_ERR(req);
|
||||
/* Update file length */
|
||||
nfs_grow_file(page, offset, count);
|
||||
/* Set the PG_uptodate flag? */
|
||||
nfs_mark_uptodate(page, offset, count);
|
||||
nfs_unlock_request(req);
|
||||
out:
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wb_priority(struct writeback_control *wbc)
|
||||
@ -304,11 +315,8 @@ do_it:
|
||||
lock_kernel();
|
||||
if (!IS_SYNC(inode) && inode_referenced) {
|
||||
err = nfs_writepage_async(ctx, inode, page, 0, offset);
|
||||
if (err >= 0) {
|
||||
err = 0;
|
||||
if (wbc->for_reclaim)
|
||||
nfs_flush_inode(inode, 0, 0, FLUSH_STABLE);
|
||||
}
|
||||
if (!wbc->for_writepages)
|
||||
nfs_flush_inode(inode, 0, 0, wb_priority(wbc));
|
||||
} else {
|
||||
err = nfs_writepage_sync(ctx, inode, page, 0,
|
||||
offset, priority);
|
||||
@ -877,9 +885,6 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
|
||||
|
||||
data->task.tk_priority = flush_task_priority(how);
|
||||
data->task.tk_cookie = (unsigned long)inode;
|
||||
data->task.tk_calldata = data;
|
||||
/* Release requests */
|
||||
data->task.tk_release = nfs_writedata_release;
|
||||
|
||||
dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n",
|
||||
data->task.tk_pid,
|
||||
@ -919,7 +924,7 @@ static int nfs_flush_multi(struct list_head *head, struct inode *inode, int how)
|
||||
|
||||
nbytes = req->wb_bytes;
|
||||
for (;;) {
|
||||
data = nfs_writedata_alloc();
|
||||
data = nfs_writedata_alloc(1);
|
||||
if (!data)
|
||||
goto out_bad;
|
||||
list_add(&data->pages, &list);
|
||||
@ -983,7 +988,7 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how)
|
||||
if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE)
|
||||
return nfs_flush_multi(head, inode, how);
|
||||
|
||||
data = nfs_writedata_alloc();
|
||||
data = nfs_writedata_alloc(NFS_SERVER(inode)->wpages);
|
||||
if (!data)
|
||||
goto out_bad;
|
||||
|
||||
@ -1137,9 +1142,9 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status)
|
||||
/*
|
||||
* This function is called when the WRITE call is complete.
|
||||
*/
|
||||
void nfs_writeback_done(struct rpc_task *task)
|
||||
void nfs_writeback_done(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
|
||||
struct nfs_write_data *data = calldata;
|
||||
struct nfs_writeargs *argp = &data->args;
|
||||
struct nfs_writeres *resp = &data->res;
|
||||
|
||||
@ -1206,9 +1211,8 @@ void nfs_writeback_done(struct rpc_task *task)
|
||||
|
||||
|
||||
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
|
||||
static void nfs_commit_release(struct rpc_task *task)
|
||||
void nfs_commit_release(void *wdata)
|
||||
{
|
||||
struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata;
|
||||
nfs_commit_free(wdata);
|
||||
}
|
||||
|
||||
@ -1244,9 +1248,6 @@ static void nfs_commit_rpcsetup(struct list_head *head,
|
||||
|
||||
data->task.tk_priority = flush_task_priority(how);
|
||||
data->task.tk_cookie = (unsigned long)inode;
|
||||
data->task.tk_calldata = data;
|
||||
/* Release requests */
|
||||
data->task.tk_release = nfs_commit_release;
|
||||
|
||||
dprintk("NFS: %4d initiated commit call\n", data->task.tk_pid);
|
||||
}
|
||||
@ -1255,12 +1256,12 @@ static void nfs_commit_rpcsetup(struct list_head *head,
|
||||
* Commit dirty pages
|
||||
*/
|
||||
static int
|
||||
nfs_commit_list(struct list_head *head, int how)
|
||||
nfs_commit_list(struct inode *inode, struct list_head *head, int how)
|
||||
{
|
||||
struct nfs_write_data *data;
|
||||
struct nfs_page *req;
|
||||
|
||||
data = nfs_commit_alloc();
|
||||
data = nfs_commit_alloc(NFS_SERVER(inode)->wpages);
|
||||
|
||||
if (!data)
|
||||
goto out_bad;
|
||||
@ -1283,10 +1284,9 @@ nfs_commit_list(struct list_head *head, int how)
|
||||
/*
|
||||
* COMMIT call returned
|
||||
*/
|
||||
void
|
||||
nfs_commit_done(struct rpc_task *task)
|
||||
void nfs_commit_done(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata;
|
||||
struct nfs_write_data *data = calldata;
|
||||
struct nfs_page *req;
|
||||
int res = 0;
|
||||
|
||||
@ -1366,7 +1366,7 @@ int nfs_commit_inode(struct inode *inode, int how)
|
||||
res = nfs_scan_commit(inode, &head, 0, 0);
|
||||
spin_unlock(&nfsi->req_lock);
|
||||
if (res) {
|
||||
error = nfs_commit_list(&head, how);
|
||||
error = nfs_commit_list(inode, &head, how);
|
||||
if (error < 0)
|
||||
return error;
|
||||
}
|
||||
@ -1377,22 +1377,23 @@ int nfs_commit_inode(struct inode *inode, int how)
|
||||
int nfs_sync_inode(struct inode *inode, unsigned long idx_start,
|
||||
unsigned int npages, int how)
|
||||
{
|
||||
int error,
|
||||
wait;
|
||||
int nocommit = how & FLUSH_NOCOMMIT;
|
||||
int wait = how & FLUSH_WAIT;
|
||||
int error;
|
||||
|
||||
wait = how & FLUSH_WAIT;
|
||||
how &= ~FLUSH_WAIT;
|
||||
how &= ~(FLUSH_WAIT|FLUSH_NOCOMMIT);
|
||||
|
||||
do {
|
||||
error = 0;
|
||||
if (wait)
|
||||
if (wait) {
|
||||
error = nfs_wait_on_requests(inode, idx_start, npages);
|
||||
if (error == 0)
|
||||
error = nfs_flush_inode(inode, idx_start, npages, how);
|
||||
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
|
||||
if (error == 0)
|
||||
if (error != 0)
|
||||
continue;
|
||||
}
|
||||
error = nfs_flush_inode(inode, idx_start, npages, how);
|
||||
if (error != 0)
|
||||
continue;
|
||||
if (!nocommit)
|
||||
error = nfs_commit_inode(inode, how);
|
||||
#endif
|
||||
} while (error > 0);
|
||||
return error;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@
|
||||
#define NFSPROC4_CB_COMPOUND 1
|
||||
|
||||
/* declarations */
|
||||
static void nfs4_cb_null(struct rpc_task *task);
|
||||
static const struct rpc_call_ops nfs4_cb_null_ops;
|
||||
|
||||
/* Index of predefined Linux callback client operations */
|
||||
|
||||
@ -431,7 +431,6 @@ nfsd4_probe_callback(struct nfs4_client *clp)
|
||||
}
|
||||
clnt->cl_intr = 0;
|
||||
clnt->cl_softrtry = 1;
|
||||
clnt->cl_chatty = 1;
|
||||
|
||||
/* Kick rpciod, put the call on the wire. */
|
||||
|
||||
@ -447,7 +446,7 @@ nfsd4_probe_callback(struct nfs4_client *clp)
|
||||
msg.rpc_cred = nfsd4_lookupcred(clp,0);
|
||||
if (IS_ERR(msg.rpc_cred))
|
||||
goto out_rpciod;
|
||||
status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, nfs4_cb_null, NULL);
|
||||
status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL);
|
||||
put_rpccred(msg.rpc_cred);
|
||||
|
||||
if (status != 0) {
|
||||
@ -469,7 +468,7 @@ out_err:
|
||||
}
|
||||
|
||||
static void
|
||||
nfs4_cb_null(struct rpc_task *task)
|
||||
nfs4_cb_null(struct rpc_task *task, void *dummy)
|
||||
{
|
||||
struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp;
|
||||
struct nfs4_callback *cb = &clp->cl_callback;
|
||||
@ -488,6 +487,10 @@ out:
|
||||
put_nfs4_client(clp);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs4_cb_null_ops = {
|
||||
.rpc_call_done = nfs4_cb_null,
|
||||
};
|
||||
|
||||
/*
|
||||
* called with dp->dl_count inc'ed.
|
||||
* nfs4_lock_state() may or may not have been called.
|
||||
|
@ -760,7 +760,7 @@ extern struct file_lock *posix_test_lock(struct file *, struct file_lock *);
|
||||
extern int posix_lock_file(struct file *, struct file_lock *);
|
||||
extern int posix_lock_file_wait(struct file *, struct file_lock *);
|
||||
extern void posix_block_lock(struct file_lock *, struct file_lock *);
|
||||
extern void posix_unblock_lock(struct file *, struct file_lock *);
|
||||
extern int posix_unblock_lock(struct file *, struct file_lock *);
|
||||
extern int posix_locks_deadlock(struct file_lock *, struct file_lock *);
|
||||
extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
|
||||
extern int __break_lease(struct inode *inode, unsigned int flags);
|
||||
|
@ -172,7 +172,7 @@ extern struct nlm_host *nlm_find_client(void);
|
||||
/*
|
||||
* Server-side lock handling
|
||||
*/
|
||||
int nlmsvc_async_call(struct nlm_rqst *, u32, rpc_action);
|
||||
int nlmsvc_async_call(struct nlm_rqst *, u32, const struct rpc_call_ops *);
|
||||
u32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
|
||||
struct nlm_lock *, int, struct nlm_cookie *);
|
||||
u32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
|
||||
|
@ -38,9 +38,6 @@
|
||||
# define NFS_DEBUG
|
||||
#endif
|
||||
|
||||
#define NFS_MAX_FILE_IO_BUFFER_SIZE 32768
|
||||
#define NFS_DEF_FILE_IO_BUFFER_SIZE 4096
|
||||
|
||||
/* Default timeout values */
|
||||
#define NFS_MAX_UDP_TIMEOUT (60*HZ)
|
||||
#define NFS_MAX_TCP_TIMEOUT (600*HZ)
|
||||
@ -65,6 +62,7 @@
|
||||
#define FLUSH_STABLE 4 /* commit to stable storage */
|
||||
#define FLUSH_LOWPRI 8 /* low priority background flush */
|
||||
#define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */
|
||||
#define FLUSH_NOCOMMIT 32 /* Don't send the NFSv3/v4 COMMIT */
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
@ -393,6 +391,17 @@ extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_
|
||||
*/
|
||||
extern struct inode_operations nfs_symlink_inode_operations;
|
||||
|
||||
/*
|
||||
* linux/fs/nfs/sysctl.c
|
||||
*/
|
||||
#ifdef CONFIG_SYSCTL
|
||||
extern int nfs_register_sysctl(void);
|
||||
extern void nfs_unregister_sysctl(void);
|
||||
#else
|
||||
#define nfs_register_sysctl() do { } while(0)
|
||||
#define nfs_unregister_sysctl() do { } while(0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* linux/fs/nfs/unlink.c
|
||||
*/
|
||||
@ -406,10 +415,12 @@ extern int nfs_writepage(struct page *page, struct writeback_control *wbc);
|
||||
extern int nfs_writepages(struct address_space *, struct writeback_control *);
|
||||
extern int nfs_flush_incompatible(struct file *file, struct page *page);
|
||||
extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
|
||||
extern void nfs_writeback_done(struct rpc_task *task);
|
||||
extern void nfs_writeback_done(struct rpc_task *task, void *data);
|
||||
extern void nfs_writedata_release(void *data);
|
||||
|
||||
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
|
||||
extern void nfs_commit_done(struct rpc_task *);
|
||||
extern void nfs_commit_done(struct rpc_task *, void *data);
|
||||
extern void nfs_commit_release(void *data);
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -460,18 +471,33 @@ static inline int nfs_wb_page(struct inode *inode, struct page* page)
|
||||
*/
|
||||
extern mempool_t *nfs_wdata_mempool;
|
||||
|
||||
static inline struct nfs_write_data *nfs_writedata_alloc(void)
|
||||
static inline struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
|
||||
{
|
||||
struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, SLAB_NOFS);
|
||||
|
||||
if (p) {
|
||||
memset(p, 0, sizeof(*p));
|
||||
INIT_LIST_HEAD(&p->pages);
|
||||
if (pagecount < NFS_PAGEVEC_SIZE)
|
||||
p->pagevec = &p->page_array[0];
|
||||
else {
|
||||
size_t size = ++pagecount * sizeof(struct page *);
|
||||
p->pagevec = kmalloc(size, GFP_NOFS);
|
||||
if (p->pagevec) {
|
||||
memset(p->pagevec, 0, size);
|
||||
} else {
|
||||
mempool_free(p, nfs_wdata_mempool);
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline void nfs_writedata_free(struct nfs_write_data *p)
|
||||
{
|
||||
if (p && (p->pagevec != &p->page_array[0]))
|
||||
kfree(p->pagevec);
|
||||
mempool_free(p, nfs_wdata_mempool);
|
||||
}
|
||||
|
||||
@ -481,28 +507,45 @@ static inline void nfs_writedata_free(struct nfs_write_data *p)
|
||||
extern int nfs_readpage(struct file *, struct page *);
|
||||
extern int nfs_readpages(struct file *, struct address_space *,
|
||||
struct list_head *, unsigned);
|
||||
extern void nfs_readpage_result(struct rpc_task *);
|
||||
extern void nfs_readpage_result(struct rpc_task *, void *);
|
||||
extern void nfs_readdata_release(void *data);
|
||||
|
||||
|
||||
/*
|
||||
* Allocate and free nfs_read_data structures
|
||||
*/
|
||||
extern mempool_t *nfs_rdata_mempool;
|
||||
|
||||
static inline struct nfs_read_data *nfs_readdata_alloc(void)
|
||||
static inline struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
|
||||
{
|
||||
struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, SLAB_NOFS);
|
||||
if (p)
|
||||
|
||||
if (p) {
|
||||
memset(p, 0, sizeof(*p));
|
||||
INIT_LIST_HEAD(&p->pages);
|
||||
if (pagecount < NFS_PAGEVEC_SIZE)
|
||||
p->pagevec = &p->page_array[0];
|
||||
else {
|
||||
size_t size = ++pagecount * sizeof(struct page *);
|
||||
p->pagevec = kmalloc(size, GFP_NOFS);
|
||||
if (p->pagevec) {
|
||||
memset(p->pagevec, 0, size);
|
||||
} else {
|
||||
mempool_free(p, nfs_rdata_mempool);
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline void nfs_readdata_free(struct nfs_read_data *p)
|
||||
{
|
||||
if (p && (p->pagevec != &p->page_array[0]))
|
||||
kfree(p->pagevec);
|
||||
mempool_free(p, nfs_rdata_mempool);
|
||||
}
|
||||
|
||||
extern void nfs_readdata_release(struct rpc_task *task);
|
||||
|
||||
/*
|
||||
* linux/fs/nfs3proc.c
|
||||
*/
|
||||
|
@ -71,6 +71,8 @@ int nfs_map_name_to_uid(struct nfs4_client *, const char *, size_t, __u32 *);
|
||||
int nfs_map_group_to_gid(struct nfs4_client *, const char *, size_t, __u32 *);
|
||||
int nfs_map_uid_to_name(struct nfs4_client *, __u32, char *);
|
||||
int nfs_map_gid_to_group(struct nfs4_client *, __u32, char *);
|
||||
|
||||
extern unsigned int nfs_idmap_cache_timeout;
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* NFS_IDMAP_H */
|
||||
|
@ -79,9 +79,7 @@ extern void nfs_clear_page_writeback(struct nfs_page *req);
|
||||
static inline int
|
||||
nfs_lock_request_dontget(struct nfs_page *req)
|
||||
{
|
||||
if (test_and_set_bit(PG_BUSY, &req->wb_flags))
|
||||
return 0;
|
||||
return 1;
|
||||
return !test_and_set_bit(PG_BUSY, &req->wb_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -125,9 +123,7 @@ nfs_list_remove_request(struct nfs_page *req)
|
||||
static inline int
|
||||
nfs_defer_commit(struct nfs_page *req)
|
||||
{
|
||||
if (test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags))
|
||||
return 0;
|
||||
return 1;
|
||||
return !test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -141,9 +137,7 @@ nfs_clear_commit(struct nfs_page *req)
|
||||
static inline int
|
||||
nfs_defer_reschedule(struct nfs_page *req)
|
||||
{
|
||||
if (test_and_set_bit(PG_NEED_RESCHED, &req->wb_flags))
|
||||
return 0;
|
||||
return 1;
|
||||
return !test_and_set_bit(PG_NEED_RESCHED, &req->wb_flags);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -4,6 +4,16 @@
|
||||
#include <linux/sunrpc/xprt.h>
|
||||
#include <linux/nfsacl.h>
|
||||
|
||||
/*
|
||||
* To change the maximum rsize and wsize supported by the NFS client, adjust
|
||||
* NFS_MAX_FILE_IO_SIZE. 64KB is a typical maximum, but some servers can
|
||||
* support a megabyte or more. The default is left at 4096 bytes, which is
|
||||
* reasonable for NFS over UDP.
|
||||
*/
|
||||
#define NFS_MAX_FILE_IO_SIZE (1048576U)
|
||||
#define NFS_DEF_FILE_IO_SIZE (4096U)
|
||||
#define NFS_MIN_FILE_IO_SIZE (1024U)
|
||||
|
||||
struct nfs4_fsid {
|
||||
__u64 major;
|
||||
__u64 minor;
|
||||
@ -137,7 +147,7 @@ struct nfs_openres {
|
||||
*/
|
||||
struct nfs_open_confirmargs {
|
||||
const struct nfs_fh * fh;
|
||||
nfs4_stateid stateid;
|
||||
nfs4_stateid * stateid;
|
||||
struct nfs_seqid * seqid;
|
||||
};
|
||||
|
||||
@ -165,66 +175,62 @@ struct nfs_closeres {
|
||||
* * Arguments to the lock,lockt, and locku call.
|
||||
* */
|
||||
struct nfs_lowner {
|
||||
__u64 clientid;
|
||||
u32 id;
|
||||
__u64 clientid;
|
||||
u32 id;
|
||||
};
|
||||
|
||||
struct nfs_lock_opargs {
|
||||
struct nfs_lock_args {
|
||||
struct nfs_fh * fh;
|
||||
struct file_lock * fl;
|
||||
struct nfs_seqid * lock_seqid;
|
||||
nfs4_stateid * lock_stateid;
|
||||
struct nfs_seqid * open_seqid;
|
||||
nfs4_stateid * open_stateid;
|
||||
struct nfs_lowner lock_owner;
|
||||
__u32 reclaim;
|
||||
__u32 new_lock_owner;
|
||||
struct nfs_lowner lock_owner;
|
||||
unsigned char block : 1;
|
||||
unsigned char reclaim : 1;
|
||||
unsigned char new_lock_owner : 1;
|
||||
};
|
||||
|
||||
struct nfs_locku_opargs {
|
||||
struct nfs_lock_res {
|
||||
nfs4_stateid stateid;
|
||||
};
|
||||
|
||||
struct nfs_locku_args {
|
||||
struct nfs_fh * fh;
|
||||
struct file_lock * fl;
|
||||
struct nfs_seqid * seqid;
|
||||
nfs4_stateid * stateid;
|
||||
};
|
||||
|
||||
struct nfs_lockargs {
|
||||
struct nfs_fh * fh;
|
||||
__u32 type;
|
||||
__u64 offset;
|
||||
__u64 length;
|
||||
union {
|
||||
struct nfs_lock_opargs *lock; /* LOCK */
|
||||
struct nfs_lowner *lockt; /* LOCKT */
|
||||
struct nfs_locku_opargs *locku; /* LOCKU */
|
||||
} u;
|
||||
struct nfs_locku_res {
|
||||
nfs4_stateid stateid;
|
||||
};
|
||||
|
||||
struct nfs_lock_denied {
|
||||
__u64 offset;
|
||||
__u64 length;
|
||||
__u32 type;
|
||||
struct nfs_lowner owner;
|
||||
struct nfs_lockt_args {
|
||||
struct nfs_fh * fh;
|
||||
struct file_lock * fl;
|
||||
struct nfs_lowner lock_owner;
|
||||
};
|
||||
|
||||
struct nfs_lockres {
|
||||
union {
|
||||
nfs4_stateid stateid;/* LOCK success, LOCKU */
|
||||
struct nfs_lock_denied denied; /* LOCK failed, LOCKT success */
|
||||
} u;
|
||||
const struct nfs_server * server;
|
||||
struct nfs_lockt_res {
|
||||
struct file_lock * denied; /* LOCK, LOCKT failed */
|
||||
};
|
||||
|
||||
struct nfs4_delegreturnargs {
|
||||
const struct nfs_fh *fhandle;
|
||||
const nfs4_stateid *stateid;
|
||||
const u32 * bitmask;
|
||||
};
|
||||
|
||||
struct nfs4_delegreturnres {
|
||||
struct nfs_fattr * fattr;
|
||||
const struct nfs_server *server;
|
||||
};
|
||||
|
||||
/*
|
||||
* Arguments to the read call.
|
||||
*/
|
||||
|
||||
#define NFS_READ_MAXIOV (9U)
|
||||
#if (NFS_READ_MAXIOV > (MAX_IOVEC -2))
|
||||
#error "NFS_READ_MAXIOV is too large"
|
||||
#endif
|
||||
|
||||
struct nfs_readargs {
|
||||
struct nfs_fh * fh;
|
||||
struct nfs_open_context *context;
|
||||
@ -243,11 +249,6 @@ struct nfs_readres {
|
||||
/*
|
||||
* Arguments to the write call.
|
||||
*/
|
||||
#define NFS_WRITE_MAXIOV (9U)
|
||||
#if (NFS_WRITE_MAXIOV > (MAX_IOVEC -2))
|
||||
#error "NFS_WRITE_MAXIOV is too large"
|
||||
#endif
|
||||
|
||||
struct nfs_writeargs {
|
||||
struct nfs_fh * fh;
|
||||
struct nfs_open_context *context;
|
||||
@ -678,6 +679,8 @@ struct nfs4_server_caps_res {
|
||||
|
||||
struct nfs_page;
|
||||
|
||||
#define NFS_PAGEVEC_SIZE (8U)
|
||||
|
||||
struct nfs_read_data {
|
||||
int flags;
|
||||
struct rpc_task task;
|
||||
@ -686,13 +689,14 @@ struct nfs_read_data {
|
||||
struct nfs_fattr fattr; /* fattr storage */
|
||||
struct list_head pages; /* Coalesced read requests */
|
||||
struct nfs_page *req; /* multi ops per nfs_page */
|
||||
struct page *pagevec[NFS_READ_MAXIOV];
|
||||
struct page **pagevec;
|
||||
struct nfs_readargs args;
|
||||
struct nfs_readres res;
|
||||
#ifdef CONFIG_NFS_V4
|
||||
unsigned long timestamp; /* For lease renewal */
|
||||
#endif
|
||||
void (*complete) (struct nfs_read_data *, int);
|
||||
struct page *page_array[NFS_PAGEVEC_SIZE + 1];
|
||||
};
|
||||
|
||||
struct nfs_write_data {
|
||||
@ -704,13 +708,14 @@ struct nfs_write_data {
|
||||
struct nfs_writeverf verf;
|
||||
struct list_head pages; /* Coalesced requests we wish to flush */
|
||||
struct nfs_page *req; /* multi ops per nfs_page */
|
||||
struct page *pagevec[NFS_WRITE_MAXIOV];
|
||||
struct page **pagevec;
|
||||
struct nfs_writeargs args; /* argument struct */
|
||||
struct nfs_writeres res; /* result struct */
|
||||
#ifdef CONFIG_NFS_V4
|
||||
unsigned long timestamp; /* For lease renewal */
|
||||
#endif
|
||||
void (*complete) (struct nfs_write_data *, int);
|
||||
struct page *page_array[NFS_PAGEVEC_SIZE + 1];
|
||||
};
|
||||
|
||||
struct nfs_access_entry;
|
||||
|
@ -49,7 +49,6 @@ struct rpc_clnt {
|
||||
|
||||
unsigned int cl_softrtry : 1,/* soft timeouts */
|
||||
cl_intr : 1,/* interruptible */
|
||||
cl_chatty : 1,/* be verbose */
|
||||
cl_autobind : 1,/* use getport() */
|
||||
cl_oneshot : 1,/* dispose after use */
|
||||
cl_dead : 1;/* abandoned */
|
||||
@ -126,7 +125,8 @@ int rpc_register(u32, u32, int, unsigned short, int *);
|
||||
void rpc_call_setup(struct rpc_task *, struct rpc_message *, int);
|
||||
|
||||
int rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg,
|
||||
int flags, rpc_action callback, void *clntdata);
|
||||
int flags, const struct rpc_call_ops *tk_ops,
|
||||
void *calldata);
|
||||
int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg,
|
||||
int flags);
|
||||
void rpc_restart_call(struct rpc_task *);
|
||||
@ -134,6 +134,7 @@ void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset);
|
||||
void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset);
|
||||
void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
|
||||
size_t rpc_max_payload(struct rpc_clnt *);
|
||||
void rpc_force_rebind(struct rpc_clnt *);
|
||||
int rpc_ping(struct rpc_clnt *clnt, int flags);
|
||||
|
||||
static __inline__
|
||||
|
@ -48,7 +48,7 @@ u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, struc
|
||||
#define CKSUMTYPE_RSA_MD5 0x0007
|
||||
|
||||
s32 make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
|
||||
struct xdr_netobj *cksum);
|
||||
int body_offset, struct xdr_netobj *cksum);
|
||||
void asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits);
|
||||
int decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen,
|
||||
int explen);
|
||||
|
@ -27,6 +27,7 @@ struct rpc_message {
|
||||
struct rpc_cred * rpc_cred; /* Credentials */
|
||||
};
|
||||
|
||||
struct rpc_call_ops;
|
||||
struct rpc_wait_queue;
|
||||
struct rpc_wait {
|
||||
struct list_head list; /* wait queue links */
|
||||
@ -41,6 +42,7 @@ struct rpc_task {
|
||||
#ifdef RPC_DEBUG
|
||||
unsigned long tk_magic; /* 0xf00baa */
|
||||
#endif
|
||||
atomic_t tk_count; /* Reference count */
|
||||
struct list_head tk_task; /* global list of tasks */
|
||||
struct rpc_clnt * tk_client; /* RPC client */
|
||||
struct rpc_rqst * tk_rqstp; /* RPC request */
|
||||
@ -50,8 +52,6 @@ struct rpc_task {
|
||||
* RPC call state
|
||||
*/
|
||||
struct rpc_message tk_msg; /* RPC call info */
|
||||
__u32 * tk_buffer; /* XDR buffer */
|
||||
size_t tk_bufsize;
|
||||
__u8 tk_garb_retry;
|
||||
__u8 tk_cred_retry;
|
||||
|
||||
@ -61,13 +61,12 @@ struct rpc_task {
|
||||
* timeout_fn to be executed by timer bottom half
|
||||
* callback to be executed after waking up
|
||||
* action next procedure for async tasks
|
||||
* exit exit async task and report to caller
|
||||
* tk_ops caller callbacks
|
||||
*/
|
||||
void (*tk_timeout_fn)(struct rpc_task *);
|
||||
void (*tk_callback)(struct rpc_task *);
|
||||
void (*tk_action)(struct rpc_task *);
|
||||
void (*tk_exit)(struct rpc_task *);
|
||||
void (*tk_release)(struct rpc_task *);
|
||||
const struct rpc_call_ops *tk_ops;
|
||||
void * tk_calldata;
|
||||
|
||||
/*
|
||||
@ -78,7 +77,6 @@ struct rpc_task {
|
||||
struct timer_list tk_timer; /* kernel timer */
|
||||
unsigned long tk_timeout; /* timeout for rpc_sleep() */
|
||||
unsigned short tk_flags; /* misc flags */
|
||||
unsigned char tk_active : 1;/* Task has been activated */
|
||||
unsigned char tk_priority : 2;/* Task priority */
|
||||
unsigned long tk_runstate; /* Task run status */
|
||||
struct workqueue_struct *tk_workqueue; /* Normally rpciod, but could
|
||||
@ -111,6 +109,13 @@ struct rpc_task {
|
||||
|
||||
typedef void (*rpc_action)(struct rpc_task *);
|
||||
|
||||
struct rpc_call_ops {
|
||||
void (*rpc_call_prepare)(struct rpc_task *, void *);
|
||||
void (*rpc_call_done)(struct rpc_task *, void *);
|
||||
void (*rpc_release)(void *);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* RPC task flags
|
||||
*/
|
||||
@ -129,7 +134,6 @@ typedef void (*rpc_action)(struct rpc_task *);
|
||||
#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER)
|
||||
#define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS)
|
||||
#define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED)
|
||||
#define RPC_IS_ACTIVATED(t) ((t)->tk_active)
|
||||
#define RPC_DO_CALLBACK(t) ((t)->tk_callback != NULL)
|
||||
#define RPC_IS_SOFT(t) ((t)->tk_flags & RPC_TASK_SOFT)
|
||||
#define RPC_TASK_UNINTERRUPTIBLE(t) ((t)->tk_flags & RPC_TASK_NOINTR)
|
||||
@ -138,6 +142,7 @@ typedef void (*rpc_action)(struct rpc_task *);
|
||||
#define RPC_TASK_QUEUED 1
|
||||
#define RPC_TASK_WAKEUP 2
|
||||
#define RPC_TASK_HAS_TIMER 3
|
||||
#define RPC_TASK_ACTIVE 4
|
||||
|
||||
#define RPC_IS_RUNNING(t) (test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
|
||||
#define rpc_set_running(t) (set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
|
||||
@ -168,6 +173,15 @@ typedef void (*rpc_action)(struct rpc_task *);
|
||||
smp_mb__after_clear_bit(); \
|
||||
} while (0)
|
||||
|
||||
#define RPC_IS_ACTIVATED(t) (test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate))
|
||||
#define rpc_set_active(t) (set_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate))
|
||||
#define rpc_clear_active(t) \
|
||||
do { \
|
||||
smp_mb__before_clear_bit(); \
|
||||
clear_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate); \
|
||||
smp_mb__after_clear_bit(); \
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
* Task priorities.
|
||||
* Note: if you change these, you must also change
|
||||
@ -228,11 +242,16 @@ struct rpc_wait_queue {
|
||||
/*
|
||||
* Function prototypes
|
||||
*/
|
||||
struct rpc_task *rpc_new_task(struct rpc_clnt *, rpc_action, int flags);
|
||||
struct rpc_task *rpc_new_task(struct rpc_clnt *, int flags,
|
||||
const struct rpc_call_ops *ops, void *data);
|
||||
struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags,
|
||||
const struct rpc_call_ops *ops, void *data);
|
||||
struct rpc_task *rpc_new_child(struct rpc_clnt *, struct rpc_task *parent);
|
||||
void rpc_init_task(struct rpc_task *, struct rpc_clnt *,
|
||||
rpc_action exitfunc, int flags);
|
||||
void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt,
|
||||
int flags, const struct rpc_call_ops *ops,
|
||||
void *data);
|
||||
void rpc_release_task(struct rpc_task *);
|
||||
void rpc_exit_task(struct rpc_task *);
|
||||
void rpc_killall_tasks(struct rpc_clnt *);
|
||||
int rpc_execute(struct rpc_task *);
|
||||
void rpc_run_child(struct rpc_task *parent, struct rpc_task *child,
|
||||
@ -247,9 +266,11 @@ struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
|
||||
void rpc_wake_up_status(struct rpc_wait_queue *, int);
|
||||
void rpc_delay(struct rpc_task *, unsigned long);
|
||||
void * rpc_malloc(struct rpc_task *, size_t);
|
||||
void rpc_free(struct rpc_task *);
|
||||
int rpciod_up(void);
|
||||
void rpciod_down(void);
|
||||
void rpciod_wake_up(void);
|
||||
int __rpc_wait_for_completion_task(struct rpc_task *task, int (*)(void *));
|
||||
#ifdef RPC_DEBUG
|
||||
void rpc_show_tasks(void);
|
||||
#endif
|
||||
@ -259,7 +280,12 @@ void rpc_destroy_mempool(void);
|
||||
static inline void rpc_exit(struct rpc_task *task, int status)
|
||||
{
|
||||
task->tk_status = status;
|
||||
task->tk_action = NULL;
|
||||
task->tk_action = rpc_exit_task;
|
||||
}
|
||||
|
||||
static inline int rpc_wait_for_completion_task(struct rpc_task *task)
|
||||
{
|
||||
return __rpc_wait_for_completion_task(task, NULL);
|
||||
}
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
|
@ -91,7 +91,6 @@ struct xdr_buf {
|
||||
u32 * xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int len);
|
||||
u32 * xdr_encode_opaque(u32 *p, const void *ptr, unsigned int len);
|
||||
u32 * xdr_encode_string(u32 *p, const char *s);
|
||||
u32 * xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen);
|
||||
u32 * xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen);
|
||||
u32 * xdr_encode_netobj(u32 *p, const struct xdr_netobj *);
|
||||
u32 * xdr_decode_netobj(u32 *p, struct xdr_netobj *);
|
||||
@ -134,11 +133,6 @@ xdr_adjust_iovec(struct kvec *iov, u32 *p)
|
||||
return iov->iov_len = ((u8 *) p - (u8 *) iov->iov_base);
|
||||
}
|
||||
|
||||
/*
|
||||
* Maximum number of iov's we use.
|
||||
*/
|
||||
#define MAX_IOVEC (12)
|
||||
|
||||
/*
|
||||
* XDR buffer helper functions
|
||||
*/
|
||||
|
@ -79,21 +79,19 @@ struct rpc_rqst {
|
||||
void (*rq_release_snd_buf)(struct rpc_rqst *); /* release rq_enc_pages */
|
||||
struct list_head rq_list;
|
||||
|
||||
__u32 * rq_buffer; /* XDR encode buffer */
|
||||
size_t rq_bufsize;
|
||||
|
||||
struct xdr_buf rq_private_buf; /* The receive buffer
|
||||
* used in the softirq.
|
||||
*/
|
||||
unsigned long rq_majortimeo; /* major timeout alarm */
|
||||
unsigned long rq_timeout; /* Current timeout value */
|
||||
unsigned int rq_retries; /* # of retries */
|
||||
/*
|
||||
* For authentication (e.g. auth_des)
|
||||
*/
|
||||
u32 rq_creddata[2];
|
||||
|
||||
/*
|
||||
* Partial send handling
|
||||
*/
|
||||
|
||||
u32 rq_bytes_sent; /* Bytes we have sent */
|
||||
|
||||
unsigned long rq_xtime; /* when transmitted */
|
||||
@ -106,7 +104,10 @@ struct rpc_xprt_ops {
|
||||
void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize);
|
||||
int (*reserve_xprt)(struct rpc_task *task);
|
||||
void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task);
|
||||
void (*set_port)(struct rpc_xprt *xprt, unsigned short port);
|
||||
void (*connect)(struct rpc_task *task);
|
||||
void * (*buf_alloc)(struct rpc_task *task, size_t size);
|
||||
void (*buf_free)(struct rpc_task *task);
|
||||
int (*send_request)(struct rpc_task *task);
|
||||
void (*set_retrans_timeout)(struct rpc_task *task);
|
||||
void (*timer)(struct rpc_task *task);
|
||||
@ -253,6 +254,7 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to);
|
||||
#define XPRT_LOCKED (0)
|
||||
#define XPRT_CONNECTED (1)
|
||||
#define XPRT_CONNECTING (2)
|
||||
#define XPRT_CLOSE_WAIT (3)
|
||||
|
||||
static inline void xprt_set_connected(struct rpc_xprt *xprt)
|
||||
{
|
||||
|
@ -53,10 +53,11 @@ struct writeback_control {
|
||||
loff_t start;
|
||||
loff_t end;
|
||||
|
||||
unsigned nonblocking:1; /* Don't get stuck on request queues */
|
||||
unsigned encountered_congestion:1; /* An output: a queue is full */
|
||||
unsigned for_kupdate:1; /* A kupdate writeback */
|
||||
unsigned for_reclaim:1; /* Invoked from the page allocator */
|
||||
unsigned nonblocking:1; /* Don't get stuck on request queues */
|
||||
unsigned encountered_congestion:1; /* An output: a queue is full */
|
||||
unsigned for_kupdate:1; /* A kupdate writeback */
|
||||
unsigned for_reclaim:1; /* Invoked from the page allocator */
|
||||
unsigned for_writepages:1; /* This is a writepages() call */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -550,11 +550,17 @@ void __init page_writeback_init(void)
|
||||
|
||||
int do_writepages(struct address_space *mapping, struct writeback_control *wbc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (wbc->nr_to_write <= 0)
|
||||
return 0;
|
||||
wbc->for_writepages = 1;
|
||||
if (mapping->a_ops->writepages)
|
||||
return mapping->a_ops->writepages(mapping, wbc);
|
||||
return generic_writepages(mapping, wbc);
|
||||
ret = mapping->a_ops->writepages(mapping, wbc);
|
||||
else
|
||||
ret = generic_writepages(mapping, wbc);
|
||||
wbc->for_writepages = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,13 +97,17 @@ get_key(const void *p, const void *end, struct crypto_tfm **res)
|
||||
alg_mode = CRYPTO_TFM_MODE_CBC;
|
||||
break;
|
||||
default:
|
||||
dprintk("RPC: get_key: unsupported algorithm %d\n", alg);
|
||||
printk("gss_kerberos_mech: unsupported algorithm %d\n", alg);
|
||||
goto out_err_free_key;
|
||||
}
|
||||
if (!(*res = crypto_alloc_tfm(alg_name, alg_mode)))
|
||||
if (!(*res = crypto_alloc_tfm(alg_name, alg_mode))) {
|
||||
printk("gss_kerberos_mech: unable to initialize crypto algorithm %s\n", alg_name);
|
||||
goto out_err_free_key;
|
||||
if (crypto_cipher_setkey(*res, key.data, key.len))
|
||||
}
|
||||
if (crypto_cipher_setkey(*res, key.data, key.len)) {
|
||||
printk("gss_kerberos_mech: error setting key for crypto algorithm %s\n", alg_name);
|
||||
goto out_err_free_tfm;
|
||||
}
|
||||
|
||||
kfree(key.data);
|
||||
return p;
|
||||
|
@ -111,14 +111,18 @@ get_key(const void *p, const void *end, struct crypto_tfm **res, int *resalg)
|
||||
setkey = 0;
|
||||
break;
|
||||
default:
|
||||
dprintk("RPC: SPKM3 get_key: unsupported algorithm %d", *resalg);
|
||||
dprintk("gss_spkm3_mech: unsupported algorithm %d\n", *resalg);
|
||||
goto out_err_free_key;
|
||||
}
|
||||
if (!(*res = crypto_alloc_tfm(alg_name, alg_mode)))
|
||||
if (!(*res = crypto_alloc_tfm(alg_name, alg_mode))) {
|
||||
printk("gss_spkm3_mech: unable to initialize crypto algorthm %s\n", alg_name);
|
||||
goto out_err_free_key;
|
||||
}
|
||||
if (setkey) {
|
||||
if (crypto_cipher_setkey(*res, key.data, key.len))
|
||||
if (crypto_cipher_setkey(*res, key.data, key.len)) {
|
||||
printk("gss_spkm3_mech: error setting key for crypto algorthm %s\n", alg_name);
|
||||
goto out_err_free_tfm;
|
||||
}
|
||||
}
|
||||
|
||||
if(key.len > 0)
|
||||
|
@ -59,7 +59,7 @@ spkm3_make_token(struct spkm3_ctx *ctx,
|
||||
char tokhdrbuf[25];
|
||||
struct xdr_netobj md5cksum = {.len = 0, .data = NULL};
|
||||
struct xdr_netobj mic_hdr = {.len = 0, .data = tokhdrbuf};
|
||||
int tmsglen, tokenlen = 0;
|
||||
int tokenlen = 0;
|
||||
unsigned char *ptr;
|
||||
s32 now;
|
||||
int ctxelen = 0, ctxzbit = 0;
|
||||
@ -92,24 +92,23 @@ spkm3_make_token(struct spkm3_ctx *ctx,
|
||||
}
|
||||
|
||||
if (toktype == SPKM_MIC_TOK) {
|
||||
tmsglen = 0;
|
||||
/* Calculate checksum over the mic-header */
|
||||
asn1_bitstring_len(&ctx->ctx_id, &ctxelen, &ctxzbit);
|
||||
spkm3_mic_header(&mic_hdr.data, &mic_hdr.len, ctx->ctx_id.data,
|
||||
ctxelen, ctxzbit);
|
||||
|
||||
if (make_checksum(checksum_type, mic_hdr.data, mic_hdr.len,
|
||||
text, &md5cksum))
|
||||
text, 0, &md5cksum))
|
||||
goto out_err;
|
||||
|
||||
asn1_bitstring_len(&md5cksum, &md5elen, &md5zbit);
|
||||
tokenlen = 10 + ctxelen + 1 + 2 + md5elen + 1;
|
||||
tokenlen = 10 + ctxelen + 1 + md5elen + 1;
|
||||
|
||||
/* Create token header using generic routines */
|
||||
token->len = g_token_size(&ctx->mech_used, tokenlen + tmsglen);
|
||||
token->len = g_token_size(&ctx->mech_used, tokenlen);
|
||||
|
||||
ptr = token->data;
|
||||
g_make_token_header(&ctx->mech_used, tokenlen + tmsglen, &ptr);
|
||||
g_make_token_header(&ctx->mech_used, tokenlen, &ptr);
|
||||
|
||||
spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit);
|
||||
} else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */
|
||||
|
@ -182,6 +182,7 @@ spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen, unsigned char *ct
|
||||
* *tokp points to the beginning of the SPKM_MIC token described
|
||||
* in rfc 2025, section 3.2.1:
|
||||
*
|
||||
* toklen is the inner token length
|
||||
*/
|
||||
void
|
||||
spkm3_make_mic_token(unsigned char **tokp, int toklen, struct xdr_netobj *mic_hdr, struct xdr_netobj *md5cksum, int md5elen, int md5zbit)
|
||||
@ -189,7 +190,7 @@ spkm3_make_mic_token(unsigned char **tokp, int toklen, struct xdr_netobj *mic_hd
|
||||
unsigned char *ict = *tokp;
|
||||
|
||||
*(u8 *)ict++ = 0xa4;
|
||||
*(u8 *)ict++ = toklen - 2;
|
||||
*(u8 *)ict++ = toklen;
|
||||
memcpy(ict, mic_hdr->data, mic_hdr->len);
|
||||
ict += mic_hdr->len;
|
||||
|
||||
|
@ -95,7 +95,7 @@ spkm3_read_token(struct spkm3_ctx *ctx,
|
||||
ret = GSS_S_DEFECTIVE_TOKEN;
|
||||
code = make_checksum(CKSUMTYPE_RSA_MD5, ptr + 2,
|
||||
mic_hdrlen + 2,
|
||||
message_buffer, &md5cksum);
|
||||
message_buffer, 0, &md5cksum);
|
||||
|
||||
if (code)
|
||||
goto out;
|
||||
|
@ -374,19 +374,23 @@ out:
|
||||
* Default callback for async RPC calls
|
||||
*/
|
||||
static void
|
||||
rpc_default_callback(struct rpc_task *task)
|
||||
rpc_default_callback(struct rpc_task *task, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops rpc_default_ops = {
|
||||
.rpc_call_done = rpc_default_callback,
|
||||
};
|
||||
|
||||
/*
|
||||
* Export the signal mask handling for synchronous code that
|
||||
* sleeps on RPC calls
|
||||
*/
|
||||
#define RPC_INTR_SIGNALS (sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGKILL))
|
||||
#define RPC_INTR_SIGNALS (sigmask(SIGHUP) | sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGTERM))
|
||||
|
||||
static void rpc_save_sigmask(sigset_t *oldset, int intr)
|
||||
{
|
||||
unsigned long sigallow = 0;
|
||||
unsigned long sigallow = sigmask(SIGKILL);
|
||||
sigset_t sigmask;
|
||||
|
||||
/* Block all signals except those listed in sigallow */
|
||||
@ -432,7 +436,7 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
|
||||
BUG_ON(flags & RPC_TASK_ASYNC);
|
||||
|
||||
status = -ENOMEM;
|
||||
task = rpc_new_task(clnt, NULL, flags);
|
||||
task = rpc_new_task(clnt, flags, &rpc_default_ops, NULL);
|
||||
if (task == NULL)
|
||||
goto out;
|
||||
|
||||
@ -442,14 +446,15 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
|
||||
rpc_call_setup(task, msg, 0);
|
||||
|
||||
/* Set up the call info struct and execute the task */
|
||||
if (task->tk_status == 0) {
|
||||
status = task->tk_status;
|
||||
if (status == 0) {
|
||||
atomic_inc(&task->tk_count);
|
||||
status = rpc_execute(task);
|
||||
} else {
|
||||
status = task->tk_status;
|
||||
rpc_release_task(task);
|
||||
if (status == 0)
|
||||
status = task->tk_status;
|
||||
}
|
||||
|
||||
rpc_restore_sigmask(&oldset);
|
||||
rpc_release_task(task);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
@ -459,7 +464,7 @@ out:
|
||||
*/
|
||||
int
|
||||
rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags,
|
||||
rpc_action callback, void *data)
|
||||
const struct rpc_call_ops *tk_ops, void *data)
|
||||
{
|
||||
struct rpc_task *task;
|
||||
sigset_t oldset;
|
||||
@ -472,12 +477,9 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags,
|
||||
flags |= RPC_TASK_ASYNC;
|
||||
|
||||
/* Create/initialize a new RPC task */
|
||||
if (!callback)
|
||||
callback = rpc_default_callback;
|
||||
status = -ENOMEM;
|
||||
if (!(task = rpc_new_task(clnt, callback, flags)))
|
||||
if (!(task = rpc_new_task(clnt, flags, tk_ops, data)))
|
||||
goto out;
|
||||
task->tk_calldata = data;
|
||||
|
||||
/* Mask signals on GSS_AUTH upcalls */
|
||||
rpc_task_sigmask(task, &oldset);
|
||||
@ -511,7 +513,7 @@ rpc_call_setup(struct rpc_task *task, struct rpc_message *msg, int flags)
|
||||
if (task->tk_status == 0)
|
||||
task->tk_action = call_start;
|
||||
else
|
||||
task->tk_action = NULL;
|
||||
task->tk_action = rpc_exit_task;
|
||||
}
|
||||
|
||||
void
|
||||
@ -536,6 +538,18 @@ size_t rpc_max_payload(struct rpc_clnt *clnt)
|
||||
}
|
||||
EXPORT_SYMBOL(rpc_max_payload);
|
||||
|
||||
/**
|
||||
* rpc_force_rebind - force transport to check that remote port is unchanged
|
||||
* @clnt: client to rebind
|
||||
*
|
||||
*/
|
||||
void rpc_force_rebind(struct rpc_clnt *clnt)
|
||||
{
|
||||
if (clnt->cl_autobind)
|
||||
clnt->cl_port = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rpc_force_rebind);
|
||||
|
||||
/*
|
||||
* Restart an (async) RPC call. Usually called from within the
|
||||
* exit handler.
|
||||
@ -642,24 +656,26 @@ call_reserveresult(struct rpc_task *task)
|
||||
|
||||
/*
|
||||
* 2. Allocate the buffer. For details, see sched.c:rpc_malloc.
|
||||
* (Note: buffer memory is freed in rpc_task_release).
|
||||
* (Note: buffer memory is freed in xprt_release).
|
||||
*/
|
||||
static void
|
||||
call_allocate(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_rqst *req = task->tk_rqstp;
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
unsigned int bufsiz;
|
||||
|
||||
dprintk("RPC: %4d call_allocate (status %d)\n",
|
||||
task->tk_pid, task->tk_status);
|
||||
task->tk_action = call_bind;
|
||||
if (task->tk_buffer)
|
||||
if (req->rq_buffer)
|
||||
return;
|
||||
|
||||
/* FIXME: compute buffer requirements more exactly using
|
||||
* auth->au_wslack */
|
||||
bufsiz = task->tk_msg.rpc_proc->p_bufsiz + RPC_SLACK_SPACE;
|
||||
|
||||
if (rpc_malloc(task, bufsiz << 1) != NULL)
|
||||
if (xprt->ops->buf_alloc(task, bufsiz << 1) != NULL)
|
||||
return;
|
||||
printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task);
|
||||
|
||||
@ -702,14 +718,14 @@ call_encode(struct rpc_task *task)
|
||||
task->tk_pid, task->tk_status);
|
||||
|
||||
/* Default buffer setup */
|
||||
bufsiz = task->tk_bufsize >> 1;
|
||||
sndbuf->head[0].iov_base = (void *)task->tk_buffer;
|
||||
bufsiz = req->rq_bufsize >> 1;
|
||||
sndbuf->head[0].iov_base = (void *)req->rq_buffer;
|
||||
sndbuf->head[0].iov_len = bufsiz;
|
||||
sndbuf->tail[0].iov_len = 0;
|
||||
sndbuf->page_len = 0;
|
||||
sndbuf->len = 0;
|
||||
sndbuf->buflen = bufsiz;
|
||||
rcvbuf->head[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz);
|
||||
rcvbuf->head[0].iov_base = (void *)((char *)req->rq_buffer + bufsiz);
|
||||
rcvbuf->head[0].iov_len = bufsiz;
|
||||
rcvbuf->tail[0].iov_len = 0;
|
||||
rcvbuf->page_len = 0;
|
||||
@ -849,8 +865,7 @@ call_connect_status(struct rpc_task *task)
|
||||
}
|
||||
|
||||
/* Something failed: remote service port may have changed */
|
||||
if (clnt->cl_autobind)
|
||||
clnt->cl_port = 0;
|
||||
rpc_force_rebind(clnt);
|
||||
|
||||
switch (status) {
|
||||
case -ENOTCONN:
|
||||
@ -892,7 +907,7 @@ call_transmit(struct rpc_task *task)
|
||||
if (task->tk_status < 0)
|
||||
return;
|
||||
if (!task->tk_msg.rpc_proc->p_decode) {
|
||||
task->tk_action = NULL;
|
||||
task->tk_action = rpc_exit_task;
|
||||
rpc_wake_up_task(task);
|
||||
}
|
||||
return;
|
||||
@ -931,8 +946,7 @@ call_status(struct rpc_task *task)
|
||||
break;
|
||||
case -ECONNREFUSED:
|
||||
case -ENOTCONN:
|
||||
if (clnt->cl_autobind)
|
||||
clnt->cl_port = 0;
|
||||
rpc_force_rebind(clnt);
|
||||
task->tk_action = call_bind;
|
||||
break;
|
||||
case -EAGAIN:
|
||||
@ -943,8 +957,7 @@ call_status(struct rpc_task *task)
|
||||
rpc_exit(task, status);
|
||||
break;
|
||||
default:
|
||||
if (clnt->cl_chatty)
|
||||
printk("%s: RPC call returned error %d\n",
|
||||
printk("%s: RPC call returned error %d\n",
|
||||
clnt->cl_protname, -status);
|
||||
rpc_exit(task, status);
|
||||
break;
|
||||
@ -979,20 +992,18 @@ call_timeout(struct rpc_task *task)
|
||||
|
||||
dprintk("RPC: %4d call_timeout (major)\n", task->tk_pid);
|
||||
if (RPC_IS_SOFT(task)) {
|
||||
if (clnt->cl_chatty)
|
||||
printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
|
||||
printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
|
||||
clnt->cl_protname, clnt->cl_server);
|
||||
rpc_exit(task, -EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN)) {
|
||||
if (!(task->tk_flags & RPC_CALL_MAJORSEEN)) {
|
||||
task->tk_flags |= RPC_CALL_MAJORSEEN;
|
||||
printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
|
||||
clnt->cl_protname, clnt->cl_server);
|
||||
}
|
||||
if (clnt->cl_autobind)
|
||||
clnt->cl_port = 0;
|
||||
rpc_force_rebind(clnt);
|
||||
|
||||
retry:
|
||||
clnt->cl_stats->rpcretrans++;
|
||||
@ -1014,7 +1025,7 @@ call_decode(struct rpc_task *task)
|
||||
dprintk("RPC: %4d call_decode (status %d)\n",
|
||||
task->tk_pid, task->tk_status);
|
||||
|
||||
if (clnt->cl_chatty && (task->tk_flags & RPC_CALL_MAJORSEEN)) {
|
||||
if (task->tk_flags & RPC_CALL_MAJORSEEN) {
|
||||
printk(KERN_NOTICE "%s: server %s OK\n",
|
||||
clnt->cl_protname, clnt->cl_server);
|
||||
task->tk_flags &= ~RPC_CALL_MAJORSEEN;
|
||||
@ -1039,13 +1050,14 @@ call_decode(struct rpc_task *task)
|
||||
sizeof(req->rq_rcv_buf)) != 0);
|
||||
|
||||
/* Verify the RPC header */
|
||||
if (!(p = call_verify(task))) {
|
||||
if (task->tk_action == NULL)
|
||||
return;
|
||||
goto out_retry;
|
||||
p = call_verify(task);
|
||||
if (IS_ERR(p)) {
|
||||
if (p == ERR_PTR(-EAGAIN))
|
||||
goto out_retry;
|
||||
return;
|
||||
}
|
||||
|
||||
task->tk_action = NULL;
|
||||
task->tk_action = rpc_exit_task;
|
||||
|
||||
if (decode)
|
||||
task->tk_status = rpcauth_unwrap_resp(task, decode, req, p,
|
||||
@ -1138,7 +1150,7 @@ call_verify(struct rpc_task *task)
|
||||
|
||||
if ((n = ntohl(*p++)) != RPC_REPLY) {
|
||||
printk(KERN_WARNING "call_verify: not an RPC reply: %x\n", n);
|
||||
goto out_retry;
|
||||
goto out_garbage;
|
||||
}
|
||||
if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
|
||||
if (--len < 0)
|
||||
@ -1168,7 +1180,7 @@ call_verify(struct rpc_task *task)
|
||||
task->tk_pid);
|
||||
rpcauth_invalcred(task);
|
||||
task->tk_action = call_refresh;
|
||||
return NULL;
|
||||
goto out_retry;
|
||||
case RPC_AUTH_BADCRED:
|
||||
case RPC_AUTH_BADVERF:
|
||||
/* possibly garbled cred/verf? */
|
||||
@ -1178,7 +1190,7 @@ call_verify(struct rpc_task *task)
|
||||
dprintk("RPC: %4d call_verify: retry garbled creds\n",
|
||||
task->tk_pid);
|
||||
task->tk_action = call_bind;
|
||||
return NULL;
|
||||
goto out_retry;
|
||||
case RPC_AUTH_TOOWEAK:
|
||||
printk(KERN_NOTICE "call_verify: server requires stronger "
|
||||
"authentication.\n");
|
||||
@ -1193,7 +1205,7 @@ call_verify(struct rpc_task *task)
|
||||
}
|
||||
if (!(p = rpcauth_checkverf(task, p))) {
|
||||
printk(KERN_WARNING "call_verify: auth check failed\n");
|
||||
goto out_retry; /* bad verifier, retry */
|
||||
goto out_garbage; /* bad verifier, retry */
|
||||
}
|
||||
len = p - (u32 *)iov->iov_base - 1;
|
||||
if (len < 0)
|
||||
@ -1230,23 +1242,24 @@ call_verify(struct rpc_task *task)
|
||||
/* Also retry */
|
||||
}
|
||||
|
||||
out_retry:
|
||||
out_garbage:
|
||||
task->tk_client->cl_stats->rpcgarbage++;
|
||||
if (task->tk_garb_retry) {
|
||||
task->tk_garb_retry--;
|
||||
dprintk("RPC %s: retrying %4d\n", __FUNCTION__, task->tk_pid);
|
||||
task->tk_action = call_bind;
|
||||
return NULL;
|
||||
out_retry:
|
||||
return ERR_PTR(-EAGAIN);
|
||||
}
|
||||
printk(KERN_WARNING "RPC %s: retry failed, exit EIO\n", __FUNCTION__);
|
||||
out_eio:
|
||||
error = -EIO;
|
||||
out_err:
|
||||
rpc_exit(task, error);
|
||||
return NULL;
|
||||
return ERR_PTR(error);
|
||||
out_overflow:
|
||||
printk(KERN_WARNING "RPC %s: server reply was truncated.\n", __FUNCTION__);
|
||||
goto out_retry;
|
||||
goto out_garbage;
|
||||
}
|
||||
|
||||
static int rpcproc_encode_null(void *rqstp, u32 *data, void *obj)
|
||||
|
@ -90,8 +90,7 @@ bailout:
|
||||
map->pm_binding = 0;
|
||||
rpc_wake_up(&map->pm_bindwait);
|
||||
spin_unlock(&pmap_lock);
|
||||
task->tk_status = -EIO;
|
||||
task->tk_action = NULL;
|
||||
rpc_exit(task, -EIO);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ROOT_NFS
|
||||
@ -132,21 +131,22 @@ static void
|
||||
pmap_getport_done(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_clnt *clnt = task->tk_client;
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
struct rpc_portmap *map = clnt->cl_pmap;
|
||||
|
||||
dprintk("RPC: %4d pmap_getport_done(status %d, port %d)\n",
|
||||
task->tk_pid, task->tk_status, clnt->cl_port);
|
||||
|
||||
xprt->ops->set_port(xprt, 0);
|
||||
if (task->tk_status < 0) {
|
||||
/* Make the calling task exit with an error */
|
||||
task->tk_action = NULL;
|
||||
task->tk_action = rpc_exit_task;
|
||||
} else if (clnt->cl_port == 0) {
|
||||
/* Program not registered */
|
||||
task->tk_status = -EACCES;
|
||||
task->tk_action = NULL;
|
||||
rpc_exit(task, -EACCES);
|
||||
} else {
|
||||
/* byte-swap port number first */
|
||||
xprt->ops->set_port(xprt, clnt->cl_port);
|
||||
clnt->cl_port = htons(clnt->cl_port);
|
||||
clnt->cl_xprt->addr.sin_port = clnt->cl_port;
|
||||
}
|
||||
spin_lock(&pmap_lock);
|
||||
map->pm_binding = 0;
|
||||
@ -207,7 +207,7 @@ pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto, int privileg
|
||||
xprt = xprt_create_proto(proto, srvaddr, NULL);
|
||||
if (IS_ERR(xprt))
|
||||
return (struct rpc_clnt *)xprt;
|
||||
xprt->addr.sin_port = htons(RPC_PMAP_PORT);
|
||||
xprt->ops->set_port(xprt, RPC_PMAP_PORT);
|
||||
if (!privileged)
|
||||
xprt->resvport = 0;
|
||||
|
||||
@ -217,7 +217,6 @@ pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto, int privileg
|
||||
RPC_AUTH_UNIX);
|
||||
if (!IS_ERR(clnt)) {
|
||||
clnt->cl_softrtry = 1;
|
||||
clnt->cl_chatty = 1;
|
||||
clnt->cl_oneshot = 1;
|
||||
}
|
||||
return clnt;
|
||||
|
@ -70,8 +70,11 @@ rpc_timeout_upcall_queue(void *data)
|
||||
struct inode *inode = &rpci->vfs_inode;
|
||||
|
||||
down(&inode->i_sem);
|
||||
if (rpci->ops == NULL)
|
||||
goto out;
|
||||
if (rpci->nreaders == 0 && !list_empty(&rpci->pipe))
|
||||
__rpc_purge_upcall(inode, -ETIMEDOUT);
|
||||
out:
|
||||
up(&inode->i_sem);
|
||||
}
|
||||
|
||||
@ -113,8 +116,6 @@ rpc_close_pipes(struct inode *inode)
|
||||
{
|
||||
struct rpc_inode *rpci = RPC_I(inode);
|
||||
|
||||
cancel_delayed_work(&rpci->queue_timeout);
|
||||
flush_scheduled_work();
|
||||
down(&inode->i_sem);
|
||||
if (rpci->ops != NULL) {
|
||||
rpci->nreaders = 0;
|
||||
@ -127,6 +128,8 @@ rpc_close_pipes(struct inode *inode)
|
||||
}
|
||||
rpc_inode_setowner(inode, NULL);
|
||||
up(&inode->i_sem);
|
||||
cancel_delayed_work(&rpci->queue_timeout);
|
||||
flush_scheduled_work();
|
||||
}
|
||||
|
||||
static struct inode *
|
||||
@ -166,7 +169,7 @@ rpc_pipe_open(struct inode *inode, struct file *filp)
|
||||
static int
|
||||
rpc_pipe_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode);
|
||||
struct rpc_inode *rpci = RPC_I(inode);
|
||||
struct rpc_pipe_msg *msg;
|
||||
|
||||
down(&inode->i_sem);
|
||||
|
@ -41,8 +41,6 @@ static mempool_t *rpc_buffer_mempool __read_mostly;
|
||||
|
||||
static void __rpc_default_timer(struct rpc_task *task);
|
||||
static void rpciod_killall(void);
|
||||
static void rpc_free(struct rpc_task *task);
|
||||
|
||||
static void rpc_async_schedule(void *);
|
||||
|
||||
/*
|
||||
@ -264,6 +262,35 @@ void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname)
|
||||
}
|
||||
EXPORT_SYMBOL(rpc_init_wait_queue);
|
||||
|
||||
static int rpc_wait_bit_interruptible(void *word)
|
||||
{
|
||||
if (signal_pending(current))
|
||||
return -ERESTARTSYS;
|
||||
schedule();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark an RPC call as having completed by clearing the 'active' bit
|
||||
*/
|
||||
static inline void rpc_mark_complete_task(struct rpc_task *task)
|
||||
{
|
||||
rpc_clear_active(task);
|
||||
wake_up_bit(&task->tk_runstate, RPC_TASK_ACTIVE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow callers to wait for completion of an RPC call
|
||||
*/
|
||||
int __rpc_wait_for_completion_task(struct rpc_task *task, int (*action)(void *))
|
||||
{
|
||||
if (action == NULL)
|
||||
action = rpc_wait_bit_interruptible;
|
||||
return wait_on_bit(&task->tk_runstate, RPC_TASK_ACTIVE,
|
||||
action, TASK_INTERRUPTIBLE);
|
||||
}
|
||||
EXPORT_SYMBOL(__rpc_wait_for_completion_task);
|
||||
|
||||
/*
|
||||
* Make an RPC task runnable.
|
||||
*
|
||||
@ -299,10 +326,7 @@ static void rpc_make_runnable(struct rpc_task *task)
|
||||
static inline void
|
||||
rpc_schedule_run(struct rpc_task *task)
|
||||
{
|
||||
/* Don't run a child twice! */
|
||||
if (RPC_IS_ACTIVATED(task))
|
||||
return;
|
||||
task->tk_active = 1;
|
||||
rpc_set_active(task);
|
||||
rpc_make_runnable(task);
|
||||
}
|
||||
|
||||
@ -324,8 +348,7 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
|
||||
}
|
||||
|
||||
/* Mark the task as being activated if so needed */
|
||||
if (!RPC_IS_ACTIVATED(task))
|
||||
task->tk_active = 1;
|
||||
rpc_set_active(task);
|
||||
|
||||
__rpc_add_wait_queue(q, task);
|
||||
|
||||
@ -555,36 +578,29 @@ __rpc_atrun(struct rpc_task *task)
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper that calls task->tk_exit if it exists and then returns
|
||||
* true if we should exit __rpc_execute.
|
||||
* Helper to call task->tk_ops->rpc_call_prepare
|
||||
*/
|
||||
static inline int __rpc_do_exit(struct rpc_task *task)
|
||||
static void rpc_prepare_task(struct rpc_task *task)
|
||||
{
|
||||
if (task->tk_exit != NULL) {
|
||||
lock_kernel();
|
||||
task->tk_exit(task);
|
||||
unlock_kernel();
|
||||
/* If tk_action is non-null, we should restart the call */
|
||||
if (task->tk_action != NULL) {
|
||||
if (!RPC_ASSASSINATED(task)) {
|
||||
/* Release RPC slot and buffer memory */
|
||||
xprt_release(task);
|
||||
rpc_free(task);
|
||||
return 0;
|
||||
}
|
||||
printk(KERN_ERR "RPC: dead task tried to walk away.\n");
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
task->tk_ops->rpc_call_prepare(task, task->tk_calldata);
|
||||
}
|
||||
|
||||
static int rpc_wait_bit_interruptible(void *word)
|
||||
/*
|
||||
* Helper that calls task->tk_ops->rpc_call_done if it exists
|
||||
*/
|
||||
void rpc_exit_task(struct rpc_task *task)
|
||||
{
|
||||
if (signal_pending(current))
|
||||
return -ERESTARTSYS;
|
||||
schedule();
|
||||
return 0;
|
||||
task->tk_action = NULL;
|
||||
if (task->tk_ops->rpc_call_done != NULL) {
|
||||
task->tk_ops->rpc_call_done(task, task->tk_calldata);
|
||||
if (task->tk_action != NULL) {
|
||||
WARN_ON(RPC_ASSASSINATED(task));
|
||||
/* Always release the RPC slot and buffer memory */
|
||||
xprt_release(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(rpc_exit_task);
|
||||
|
||||
/*
|
||||
* This is the RPC `scheduler' (or rather, the finite state machine).
|
||||
@ -631,12 +647,11 @@ static int __rpc_execute(struct rpc_task *task)
|
||||
* by someone else.
|
||||
*/
|
||||
if (!RPC_IS_QUEUED(task)) {
|
||||
if (task->tk_action != NULL) {
|
||||
lock_kernel();
|
||||
task->tk_action(task);
|
||||
unlock_kernel();
|
||||
} else if (__rpc_do_exit(task))
|
||||
if (task->tk_action == NULL)
|
||||
break;
|
||||
lock_kernel();
|
||||
task->tk_action(task);
|
||||
unlock_kernel();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -676,9 +691,9 @@ static int __rpc_execute(struct rpc_task *task)
|
||||
dprintk("RPC: %4d sync task resuming\n", task->tk_pid);
|
||||
}
|
||||
|
||||
dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status);
|
||||
status = task->tk_status;
|
||||
|
||||
dprintk("RPC: %4d, return %d, status %d\n", task->tk_pid, status, task->tk_status);
|
||||
/* Wake up anyone who is waiting for task completion */
|
||||
rpc_mark_complete_task(task);
|
||||
/* Release all resources associated with the task */
|
||||
rpc_release_task(task);
|
||||
return status;
|
||||
@ -696,9 +711,7 @@ static int __rpc_execute(struct rpc_task *task)
|
||||
int
|
||||
rpc_execute(struct rpc_task *task)
|
||||
{
|
||||
BUG_ON(task->tk_active);
|
||||
|
||||
task->tk_active = 1;
|
||||
rpc_set_active(task);
|
||||
rpc_set_running(task);
|
||||
return __rpc_execute(task);
|
||||
}
|
||||
@ -708,17 +721,19 @@ static void rpc_async_schedule(void *arg)
|
||||
__rpc_execute((struct rpc_task *)arg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate memory for RPC purposes.
|
||||
/**
|
||||
* rpc_malloc - allocate an RPC buffer
|
||||
* @task: RPC task that will use this buffer
|
||||
* @size: requested byte size
|
||||
*
|
||||
* We try to ensure that some NFS reads and writes can always proceed
|
||||
* by using a mempool when allocating 'small' buffers.
|
||||
* In order to avoid memory starvation triggering more writebacks of
|
||||
* NFS requests, we use GFP_NOFS rather than GFP_KERNEL.
|
||||
*/
|
||||
void *
|
||||
rpc_malloc(struct rpc_task *task, size_t size)
|
||||
void * rpc_malloc(struct rpc_task *task, size_t size)
|
||||
{
|
||||
struct rpc_rqst *req = task->tk_rqstp;
|
||||
gfp_t gfp;
|
||||
|
||||
if (task->tk_flags & RPC_TASK_SWAPPER)
|
||||
@ -727,42 +742,52 @@ rpc_malloc(struct rpc_task *task, size_t size)
|
||||
gfp = GFP_NOFS;
|
||||
|
||||
if (size > RPC_BUFFER_MAXSIZE) {
|
||||
task->tk_buffer = kmalloc(size, gfp);
|
||||
if (task->tk_buffer)
|
||||
task->tk_bufsize = size;
|
||||
req->rq_buffer = kmalloc(size, gfp);
|
||||
if (req->rq_buffer)
|
||||
req->rq_bufsize = size;
|
||||
} else {
|
||||
task->tk_buffer = mempool_alloc(rpc_buffer_mempool, gfp);
|
||||
if (task->tk_buffer)
|
||||
task->tk_bufsize = RPC_BUFFER_MAXSIZE;
|
||||
req->rq_buffer = mempool_alloc(rpc_buffer_mempool, gfp);
|
||||
if (req->rq_buffer)
|
||||
req->rq_bufsize = RPC_BUFFER_MAXSIZE;
|
||||
}
|
||||
return task->tk_buffer;
|
||||
return req->rq_buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_free(struct rpc_task *task)
|
||||
/**
|
||||
* rpc_free - free buffer allocated via rpc_malloc
|
||||
* @task: RPC task with a buffer to be freed
|
||||
*
|
||||
*/
|
||||
void rpc_free(struct rpc_task *task)
|
||||
{
|
||||
if (task->tk_buffer) {
|
||||
if (task->tk_bufsize == RPC_BUFFER_MAXSIZE)
|
||||
mempool_free(task->tk_buffer, rpc_buffer_mempool);
|
||||
struct rpc_rqst *req = task->tk_rqstp;
|
||||
|
||||
if (req->rq_buffer) {
|
||||
if (req->rq_bufsize == RPC_BUFFER_MAXSIZE)
|
||||
mempool_free(req->rq_buffer, rpc_buffer_mempool);
|
||||
else
|
||||
kfree(task->tk_buffer);
|
||||
task->tk_buffer = NULL;
|
||||
task->tk_bufsize = 0;
|
||||
kfree(req->rq_buffer);
|
||||
req->rq_buffer = NULL;
|
||||
req->rq_bufsize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Creation and deletion of RPC task structures
|
||||
*/
|
||||
void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, rpc_action callback, int flags)
|
||||
void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, const struct rpc_call_ops *tk_ops, void *calldata)
|
||||
{
|
||||
memset(task, 0, sizeof(*task));
|
||||
init_timer(&task->tk_timer);
|
||||
task->tk_timer.data = (unsigned long) task;
|
||||
task->tk_timer.function = (void (*)(unsigned long)) rpc_run_timer;
|
||||
atomic_set(&task->tk_count, 1);
|
||||
task->tk_client = clnt;
|
||||
task->tk_flags = flags;
|
||||
task->tk_exit = callback;
|
||||
task->tk_ops = tk_ops;
|
||||
if (tk_ops->rpc_call_prepare != NULL)
|
||||
task->tk_action = rpc_prepare_task;
|
||||
task->tk_calldata = calldata;
|
||||
|
||||
/* Initialize retry counters */
|
||||
task->tk_garb_retry = 2;
|
||||
@ -791,6 +816,8 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, rpc_action call
|
||||
list_add_tail(&task->tk_task, &all_tasks);
|
||||
spin_unlock(&rpc_sched_lock);
|
||||
|
||||
BUG_ON(task->tk_ops == NULL);
|
||||
|
||||
dprintk("RPC: %4d new task procpid %d\n", task->tk_pid,
|
||||
current->pid);
|
||||
}
|
||||
@ -801,8 +828,7 @@ rpc_alloc_task(void)
|
||||
return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOFS);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_default_free_task(struct rpc_task *task)
|
||||
static void rpc_free_task(struct rpc_task *task)
|
||||
{
|
||||
dprintk("RPC: %4d freeing task\n", task->tk_pid);
|
||||
mempool_free(task, rpc_task_mempool);
|
||||
@ -813,8 +839,7 @@ rpc_default_free_task(struct rpc_task *task)
|
||||
* clean up after an allocation failure, as the client may
|
||||
* have specified "oneshot".
|
||||
*/
|
||||
struct rpc_task *
|
||||
rpc_new_task(struct rpc_clnt *clnt, rpc_action callback, int flags)
|
||||
struct rpc_task *rpc_new_task(struct rpc_clnt *clnt, int flags, const struct rpc_call_ops *tk_ops, void *calldata)
|
||||
{
|
||||
struct rpc_task *task;
|
||||
|
||||
@ -822,10 +847,7 @@ rpc_new_task(struct rpc_clnt *clnt, rpc_action callback, int flags)
|
||||
if (!task)
|
||||
goto cleanup;
|
||||
|
||||
rpc_init_task(task, clnt, callback, flags);
|
||||
|
||||
/* Replace tk_release */
|
||||
task->tk_release = rpc_default_free_task;
|
||||
rpc_init_task(task, clnt, flags, tk_ops, calldata);
|
||||
|
||||
dprintk("RPC: %4d allocated task\n", task->tk_pid);
|
||||
task->tk_flags |= RPC_TASK_DYNAMIC;
|
||||
@ -845,11 +867,15 @@ cleanup:
|
||||
|
||||
void rpc_release_task(struct rpc_task *task)
|
||||
{
|
||||
dprintk("RPC: %4d release task\n", task->tk_pid);
|
||||
const struct rpc_call_ops *tk_ops = task->tk_ops;
|
||||
void *calldata = task->tk_calldata;
|
||||
|
||||
#ifdef RPC_DEBUG
|
||||
BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID);
|
||||
#endif
|
||||
if (!atomic_dec_and_test(&task->tk_count))
|
||||
return;
|
||||
dprintk("RPC: %4d release task\n", task->tk_pid);
|
||||
|
||||
/* Remove from global task list */
|
||||
spin_lock(&rpc_sched_lock);
|
||||
@ -857,7 +883,6 @@ void rpc_release_task(struct rpc_task *task)
|
||||
spin_unlock(&rpc_sched_lock);
|
||||
|
||||
BUG_ON (RPC_IS_QUEUED(task));
|
||||
task->tk_active = 0;
|
||||
|
||||
/* Synchronously delete any running timer */
|
||||
rpc_delete_timer(task);
|
||||
@ -867,7 +892,6 @@ void rpc_release_task(struct rpc_task *task)
|
||||
xprt_release(task);
|
||||
if (task->tk_msg.rpc_cred)
|
||||
rpcauth_unbindcred(task);
|
||||
rpc_free(task);
|
||||
if (task->tk_client) {
|
||||
rpc_release_client(task->tk_client);
|
||||
task->tk_client = NULL;
|
||||
@ -876,10 +900,33 @@ void rpc_release_task(struct rpc_task *task)
|
||||
#ifdef RPC_DEBUG
|
||||
task->tk_magic = 0;
|
||||
#endif
|
||||
if (task->tk_release)
|
||||
task->tk_release(task);
|
||||
if (task->tk_flags & RPC_TASK_DYNAMIC)
|
||||
rpc_free_task(task);
|
||||
if (tk_ops->rpc_release)
|
||||
tk_ops->rpc_release(calldata);
|
||||
}
|
||||
|
||||
/**
|
||||
* rpc_run_task - Allocate a new RPC task, then run rpc_execute against it
|
||||
* @clnt - pointer to RPC client
|
||||
* @flags - RPC flags
|
||||
* @ops - RPC call ops
|
||||
* @data - user call data
|
||||
*/
|
||||
struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags,
|
||||
const struct rpc_call_ops *ops,
|
||||
void *data)
|
||||
{
|
||||
struct rpc_task *task;
|
||||
task = rpc_new_task(clnt, flags, ops, data);
|
||||
if (task == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
atomic_inc(&task->tk_count);
|
||||
rpc_execute(task);
|
||||
return task;
|
||||
}
|
||||
EXPORT_SYMBOL(rpc_run_task);
|
||||
|
||||
/**
|
||||
* rpc_find_parent - find the parent of a child task.
|
||||
* @child: child task
|
||||
@ -890,12 +937,11 @@ void rpc_release_task(struct rpc_task *task)
|
||||
*
|
||||
* Caller must hold childq.lock
|
||||
*/
|
||||
static inline struct rpc_task *rpc_find_parent(struct rpc_task *child)
|
||||
static inline struct rpc_task *rpc_find_parent(struct rpc_task *child, struct rpc_task *parent)
|
||||
{
|
||||
struct rpc_task *task, *parent;
|
||||
struct rpc_task *task;
|
||||
struct list_head *le;
|
||||
|
||||
parent = (struct rpc_task *) child->tk_calldata;
|
||||
task_for_each(task, le, &childq.tasks[0])
|
||||
if (task == parent)
|
||||
return parent;
|
||||
@ -903,18 +949,22 @@ static inline struct rpc_task *rpc_find_parent(struct rpc_task *child)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rpc_child_exit(struct rpc_task *child)
|
||||
static void rpc_child_exit(struct rpc_task *child, void *calldata)
|
||||
{
|
||||
struct rpc_task *parent;
|
||||
|
||||
spin_lock_bh(&childq.lock);
|
||||
if ((parent = rpc_find_parent(child)) != NULL) {
|
||||
if ((parent = rpc_find_parent(child, calldata)) != NULL) {
|
||||
parent->tk_status = child->tk_status;
|
||||
__rpc_wake_up_task(parent);
|
||||
}
|
||||
spin_unlock_bh(&childq.lock);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops rpc_child_ops = {
|
||||
.rpc_call_done = rpc_child_exit,
|
||||
};
|
||||
|
||||
/*
|
||||
* Note: rpc_new_task releases the client after a failure.
|
||||
*/
|
||||
@ -923,11 +973,9 @@ rpc_new_child(struct rpc_clnt *clnt, struct rpc_task *parent)
|
||||
{
|
||||
struct rpc_task *task;
|
||||
|
||||
task = rpc_new_task(clnt, NULL, RPC_TASK_ASYNC | RPC_TASK_CHILD);
|
||||
task = rpc_new_task(clnt, RPC_TASK_ASYNC | RPC_TASK_CHILD, &rpc_child_ops, parent);
|
||||
if (!task)
|
||||
goto fail;
|
||||
task->tk_exit = rpc_child_exit;
|
||||
task->tk_calldata = parent;
|
||||
return task;
|
||||
|
||||
fail:
|
||||
@ -1063,7 +1111,7 @@ void rpc_show_tasks(void)
|
||||
return;
|
||||
}
|
||||
printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout "
|
||||
"-rpcwait -action- --exit--\n");
|
||||
"-rpcwait -action- ---ops--\n");
|
||||
alltask_for_each(t, le, &all_tasks) {
|
||||
const char *rpc_waitq = "none";
|
||||
|
||||
@ -1078,7 +1126,7 @@ void rpc_show_tasks(void)
|
||||
(t->tk_client ? t->tk_client->cl_prog : 0),
|
||||
t->tk_rqstp, t->tk_timeout,
|
||||
rpc_waitq,
|
||||
t->tk_action, t->tk_exit);
|
||||
t->tk_action, t->tk_ops);
|
||||
}
|
||||
spin_unlock(&rpc_sched_lock);
|
||||
}
|
||||
|
@ -30,8 +30,6 @@ EXPORT_SYMBOL(rpc_init_task);
|
||||
EXPORT_SYMBOL(rpc_sleep_on);
|
||||
EXPORT_SYMBOL(rpc_wake_up_next);
|
||||
EXPORT_SYMBOL(rpc_wake_up_task);
|
||||
EXPORT_SYMBOL(rpc_new_child);
|
||||
EXPORT_SYMBOL(rpc_run_child);
|
||||
EXPORT_SYMBOL(rpciod_down);
|
||||
EXPORT_SYMBOL(rpciod_up);
|
||||
EXPORT_SYMBOL(rpc_new_task);
|
||||
@ -45,7 +43,6 @@ EXPORT_SYMBOL(rpc_clone_client);
|
||||
EXPORT_SYMBOL(rpc_bind_new_program);
|
||||
EXPORT_SYMBOL(rpc_destroy_client);
|
||||
EXPORT_SYMBOL(rpc_shutdown_client);
|
||||
EXPORT_SYMBOL(rpc_release_client);
|
||||
EXPORT_SYMBOL(rpc_killall_tasks);
|
||||
EXPORT_SYMBOL(rpc_call_sync);
|
||||
EXPORT_SYMBOL(rpc_call_async);
|
||||
@ -120,7 +117,6 @@ EXPORT_SYMBOL(unix_domain_find);
|
||||
|
||||
/* Generic XDR */
|
||||
EXPORT_SYMBOL(xdr_encode_string);
|
||||
EXPORT_SYMBOL(xdr_decode_string);
|
||||
EXPORT_SYMBOL(xdr_decode_string_inplace);
|
||||
EXPORT_SYMBOL(xdr_decode_netobj);
|
||||
EXPORT_SYMBOL(xdr_encode_netobj);
|
||||
|
@ -92,27 +92,6 @@ xdr_encode_string(u32 *p, const char *string)
|
||||
return xdr_encode_array(p, string, strlen(string));
|
||||
}
|
||||
|
||||
u32 *
|
||||
xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen)
|
||||
{
|
||||
unsigned int len;
|
||||
char *string;
|
||||
|
||||
if ((len = ntohl(*p++)) > maxlen)
|
||||
return NULL;
|
||||
if (lenp)
|
||||
*lenp = len;
|
||||
if ((len % 4) != 0) {
|
||||
string = (char *) p;
|
||||
} else {
|
||||
string = (char *) (p - 1);
|
||||
memmove(string, p, len);
|
||||
}
|
||||
string[len] = '\0';
|
||||
*sp = string;
|
||||
return p + XDR_QUADLEN(len);
|
||||
}
|
||||
|
||||
u32 *
|
||||
xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen)
|
||||
{
|
||||
|
@ -119,6 +119,17 @@ out_sleep:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xprt_clear_locked(struct rpc_xprt *xprt)
|
||||
{
|
||||
xprt->snd_task = NULL;
|
||||
if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state) || xprt->shutdown) {
|
||||
smp_mb__before_clear_bit();
|
||||
clear_bit(XPRT_LOCKED, &xprt->state);
|
||||
smp_mb__after_clear_bit();
|
||||
} else
|
||||
schedule_work(&xprt->task_cleanup);
|
||||
}
|
||||
|
||||
/*
|
||||
* xprt_reserve_xprt_cong - serialize write access to transports
|
||||
* @task: task that is requesting access to the transport
|
||||
@ -145,9 +156,7 @@ int xprt_reserve_xprt_cong(struct rpc_task *task)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
smp_mb__before_clear_bit();
|
||||
clear_bit(XPRT_LOCKED, &xprt->state);
|
||||
smp_mb__after_clear_bit();
|
||||
xprt_clear_locked(xprt);
|
||||
out_sleep:
|
||||
dprintk("RPC: %4d failed to lock transport %p\n", task->tk_pid, xprt);
|
||||
task->tk_timeout = 0;
|
||||
@ -193,9 +202,7 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt)
|
||||
return;
|
||||
|
||||
out_unlock:
|
||||
smp_mb__before_clear_bit();
|
||||
clear_bit(XPRT_LOCKED, &xprt->state);
|
||||
smp_mb__after_clear_bit();
|
||||
xprt_clear_locked(xprt);
|
||||
}
|
||||
|
||||
static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
|
||||
@ -222,9 +229,7 @@ static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
|
||||
return;
|
||||
}
|
||||
out_unlock:
|
||||
smp_mb__before_clear_bit();
|
||||
clear_bit(XPRT_LOCKED, &xprt->state);
|
||||
smp_mb__after_clear_bit();
|
||||
xprt_clear_locked(xprt);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -237,10 +242,7 @@ out_unlock:
|
||||
void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
|
||||
{
|
||||
if (xprt->snd_task == task) {
|
||||
xprt->snd_task = NULL;
|
||||
smp_mb__before_clear_bit();
|
||||
clear_bit(XPRT_LOCKED, &xprt->state);
|
||||
smp_mb__after_clear_bit();
|
||||
xprt_clear_locked(xprt);
|
||||
__xprt_lock_write_next(xprt);
|
||||
}
|
||||
}
|
||||
@ -256,10 +258,7 @@ void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
|
||||
void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
|
||||
{
|
||||
if (xprt->snd_task == task) {
|
||||
xprt->snd_task = NULL;
|
||||
smp_mb__before_clear_bit();
|
||||
clear_bit(XPRT_LOCKED, &xprt->state);
|
||||
smp_mb__after_clear_bit();
|
||||
xprt_clear_locked(xprt);
|
||||
__xprt_lock_write_next_cong(xprt);
|
||||
}
|
||||
}
|
||||
@ -535,10 +534,6 @@ void xprt_connect(struct rpc_task *task)
|
||||
dprintk("RPC: %4d xprt_connect xprt %p %s connected\n", task->tk_pid,
|
||||
xprt, (xprt_connected(xprt) ? "is" : "is not"));
|
||||
|
||||
if (xprt->shutdown) {
|
||||
task->tk_status = -EIO;
|
||||
return;
|
||||
}
|
||||
if (!xprt->addr.sin_port) {
|
||||
task->tk_status = -EIO;
|
||||
return;
|
||||
@ -687,9 +682,6 @@ int xprt_prepare_transmit(struct rpc_task *task)
|
||||
|
||||
dprintk("RPC: %4d xprt_prepare_transmit\n", task->tk_pid);
|
||||
|
||||
if (xprt->shutdown)
|
||||
return -EIO;
|
||||
|
||||
spin_lock_bh(&xprt->transport_lock);
|
||||
if (req->rq_received && !req->rq_bytes_sent) {
|
||||
err = req->rq_received;
|
||||
@ -814,11 +806,9 @@ void xprt_reserve(struct rpc_task *task)
|
||||
struct rpc_xprt *xprt = task->tk_xprt;
|
||||
|
||||
task->tk_status = -EIO;
|
||||
if (!xprt->shutdown) {
|
||||
spin_lock(&xprt->reserve_lock);
|
||||
do_xprt_reserve(task);
|
||||
spin_unlock(&xprt->reserve_lock);
|
||||
}
|
||||
spin_lock(&xprt->reserve_lock);
|
||||
do_xprt_reserve(task);
|
||||
spin_unlock(&xprt->reserve_lock);
|
||||
}
|
||||
|
||||
static inline u32 xprt_alloc_xid(struct rpc_xprt *xprt)
|
||||
@ -838,6 +828,8 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
|
||||
req->rq_timeout = xprt->timeout.to_initval;
|
||||
req->rq_task = task;
|
||||
req->rq_xprt = xprt;
|
||||
req->rq_buffer = NULL;
|
||||
req->rq_bufsize = 0;
|
||||
req->rq_xid = xprt_alloc_xid(xprt);
|
||||
req->rq_release_snd_buf = NULL;
|
||||
dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid,
|
||||
@ -863,10 +855,11 @@ void xprt_release(struct rpc_task *task)
|
||||
if (!list_empty(&req->rq_list))
|
||||
list_del(&req->rq_list);
|
||||
xprt->last_used = jiffies;
|
||||
if (list_empty(&xprt->recv) && !xprt->shutdown)
|
||||
if (list_empty(&xprt->recv))
|
||||
mod_timer(&xprt->timer,
|
||||
xprt->last_used + xprt->idle_timeout);
|
||||
spin_unlock_bh(&xprt->transport_lock);
|
||||
xprt->ops->buf_free(task);
|
||||
task->tk_rqstp = NULL;
|
||||
if (req->rq_release_snd_buf)
|
||||
req->rq_release_snd_buf(req);
|
||||
@ -974,16 +967,6 @@ struct rpc_xprt *xprt_create_proto(int proto, struct sockaddr_in *sap, struct rp
|
||||
return xprt;
|
||||
}
|
||||
|
||||
static void xprt_shutdown(struct rpc_xprt *xprt)
|
||||
{
|
||||
xprt->shutdown = 1;
|
||||
rpc_wake_up(&xprt->sending);
|
||||
rpc_wake_up(&xprt->resend);
|
||||
xprt_wake_pending_tasks(xprt, -EIO);
|
||||
rpc_wake_up(&xprt->backlog);
|
||||
del_timer_sync(&xprt->timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* xprt_destroy - destroy an RPC transport, killing off all requests.
|
||||
* @xprt: transport to destroy
|
||||
@ -992,7 +975,8 @@ static void xprt_shutdown(struct rpc_xprt *xprt)
|
||||
int xprt_destroy(struct rpc_xprt *xprt)
|
||||
{
|
||||
dprintk("RPC: destroying transport %p\n", xprt);
|
||||
xprt_shutdown(xprt);
|
||||
xprt->shutdown = 1;
|
||||
del_timer_sync(&xprt->timer);
|
||||
xprt->ops->destroy(xprt);
|
||||
kfree(xprt);
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <linux/udp.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/sched.h>
|
||||
#include <linux/file.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
@ -424,7 +425,7 @@ static void xs_close(struct rpc_xprt *xprt)
|
||||
struct sock *sk = xprt->inet;
|
||||
|
||||
if (!sk)
|
||||
return;
|
||||
goto clear_close_wait;
|
||||
|
||||
dprintk("RPC: xs_close xprt %p\n", xprt);
|
||||
|
||||
@ -441,6 +442,10 @@ static void xs_close(struct rpc_xprt *xprt)
|
||||
sk->sk_no_check = 0;
|
||||
|
||||
sock_release(sock);
|
||||
clear_close_wait:
|
||||
smp_mb__before_clear_bit();
|
||||
clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
|
||||
smp_mb__after_clear_bit();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -800,9 +805,13 @@ static void xs_tcp_state_change(struct sock *sk)
|
||||
case TCP_SYN_SENT:
|
||||
case TCP_SYN_RECV:
|
||||
break;
|
||||
case TCP_CLOSE_WAIT:
|
||||
/* Try to schedule an autoclose RPC calls */
|
||||
set_bit(XPRT_CLOSE_WAIT, &xprt->state);
|
||||
if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
|
||||
schedule_work(&xprt->task_cleanup);
|
||||
default:
|
||||
xprt_disconnect(xprt);
|
||||
break;
|
||||
}
|
||||
out:
|
||||
read_unlock(&sk->sk_callback_lock);
|
||||
@ -920,6 +929,18 @@ static void xs_udp_timer(struct rpc_task *task)
|
||||
xprt_adjust_cwnd(task, -ETIMEDOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* xs_set_port - reset the port number in the remote endpoint address
|
||||
* @xprt: generic transport
|
||||
* @port: new port number
|
||||
*
|
||||
*/
|
||||
static void xs_set_port(struct rpc_xprt *xprt, unsigned short port)
|
||||
{
|
||||
dprintk("RPC: setting port for xprt %p to %u\n", xprt, port);
|
||||
xprt->addr.sin_port = htons(port);
|
||||
}
|
||||
|
||||
static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock)
|
||||
{
|
||||
struct sockaddr_in myaddr = {
|
||||
@ -1160,7 +1181,10 @@ static struct rpc_xprt_ops xs_udp_ops = {
|
||||
.set_buffer_size = xs_udp_set_buffer_size,
|
||||
.reserve_xprt = xprt_reserve_xprt_cong,
|
||||
.release_xprt = xprt_release_xprt_cong,
|
||||
.set_port = xs_set_port,
|
||||
.connect = xs_connect,
|
||||
.buf_alloc = rpc_malloc,
|
||||
.buf_free = rpc_free,
|
||||
.send_request = xs_udp_send_request,
|
||||
.set_retrans_timeout = xprt_set_retrans_timeout_rtt,
|
||||
.timer = xs_udp_timer,
|
||||
@ -1172,7 +1196,10 @@ static struct rpc_xprt_ops xs_udp_ops = {
|
||||
static struct rpc_xprt_ops xs_tcp_ops = {
|
||||
.reserve_xprt = xprt_reserve_xprt,
|
||||
.release_xprt = xprt_release_xprt,
|
||||
.set_port = xs_set_port,
|
||||
.connect = xs_connect,
|
||||
.buf_alloc = rpc_malloc,
|
||||
.buf_free = rpc_free,
|
||||
.send_request = xs_tcp_send_request,
|
||||
.set_retrans_timeout = xprt_set_retrans_timeout_def,
|
||||
.close = xs_close,
|
||||
|
Loading…
Reference in New Issue
Block a user