Commit 0d9f9e12 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-2.6.36' of git://linux-nfs.org/~bfields/linux

* 'for-2.6.36' of git://linux-nfs.org/~bfields/linux: (34 commits)
  nfsd4: fix file open accounting for RDWR opens
  nfsd: don't allow setting maxblksize after svc created
  nfsd: initialize nfsd versions before creating svc
  net: sunrpc: removed duplicated #include
  nfsd41: Fix a crash when a callback is retried
  nfsd: fix startup/shutdown order bug
  nfsd: minor nfsd read api cleanup
  gcc-4.6: nfsd: fix initialized but not read warnings
  nfsd4: share file descriptors between stateid's
  nfsd4: fix openmode checking on IO using lock stateid
  nfsd4: miscellaneous process_open2 cleanup
  nfsd4: don't pretend to support write delegations
  nfsd: bypass readahead cache when have struct file
  nfsd: minor nfsd_svc() cleanup
  nfsd: move more into nfsd_startup()
  nfsd: just keep single lockd reference for nfsd
  nfsd: clean up nfsd_create_serv error handling
  nfsd: fix error handling in __write_ports_addxprt
  nfsd: fix error handling when starting nfsd with rpcbind down
  nfsd4: fix v4 state shutdown error paths
  ...
parents df44f9f4 998db52c
...@@ -168,7 +168,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, ...@@ -168,7 +168,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
fh_copy(&resp->fh, &argp->fh); fh_copy(&resp->fh, &argp->fh);
nfserr = nfsd_read(rqstp, &resp->fh, NULL, nfserr = nfsd_read(rqstp, &resp->fh,
argp->offset, argp->offset,
rqstp->rq_vec, argp->vlen, rqstp->rq_vec, argp->vlen,
&resp->count); &resp->count);
...@@ -271,7 +271,7 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, ...@@ -271,7 +271,7 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
fh_init(&resp->fh, NFS3_FHSIZE); fh_init(&resp->fh, NFS3_FHSIZE);
nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
&argp->attrs, S_IFDIR, 0, &resp->fh); &argp->attrs, S_IFDIR, 0, &resp->fh);
fh_unlock(&resp->dirfh);
RETURN_STATUS(nfserr); RETURN_STATUS(nfserr);
} }
...@@ -327,7 +327,7 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp, ...@@ -327,7 +327,7 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
type = nfs3_ftypes[argp->ftype]; type = nfs3_ftypes[argp->ftype];
nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
&argp->attrs, type, rdev, &resp->fh); &argp->attrs, type, rdev, &resp->fh);
fh_unlock(&resp->dirfh);
RETURN_STATUS(nfserr); RETURN_STATUS(nfserr);
} }
...@@ -348,6 +348,7 @@ nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, ...@@ -348,6 +348,7 @@ nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
/* Unlink. -S_IFDIR means file must not be a directory */ /* Unlink. -S_IFDIR means file must not be a directory */
fh_copy(&resp->fh, &argp->fh); fh_copy(&resp->fh, &argp->fh);
nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len); nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
fh_unlock(&resp->fh);
RETURN_STATUS(nfserr); RETURN_STATUS(nfserr);
} }
...@@ -367,6 +368,7 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, ...@@ -367,6 +368,7 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
fh_copy(&resp->fh, &argp->fh); fh_copy(&resp->fh, &argp->fh);
nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len); nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len);
fh_unlock(&resp->fh);
RETURN_STATUS(nfserr); RETURN_STATUS(nfserr);
} }
......
...@@ -143,8 +143,6 @@ struct nfs4_cb_compound_hdr { ...@@ -143,8 +143,6 @@ struct nfs4_cb_compound_hdr {
u32 minorversion; u32 minorversion;
/* res */ /* res */
int status; int status;
u32 taglen;
char *tag;
}; };
static struct { static struct {
...@@ -204,6 +202,16 @@ nfs_cb_stat_to_errno(int stat) ...@@ -204,6 +202,16 @@ nfs_cb_stat_to_errno(int stat)
* XDR encode * XDR encode
*/ */
static void
encode_stateid(struct xdr_stream *xdr, stateid_t *sid)
{
__be32 *p;
RESERVE_SPACE(sizeof(stateid_t));
WRITE32(sid->si_generation);
WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
}
static void static void
encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr)
{ {
...@@ -229,10 +237,10 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp, ...@@ -229,10 +237,10 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp,
__be32 *p; __be32 *p;
int len = dp->dl_fh.fh_size; int len = dp->dl_fh.fh_size;
RESERVE_SPACE(12+sizeof(dp->dl_stateid) + len); RESERVE_SPACE(4);
WRITE32(OP_CB_RECALL); WRITE32(OP_CB_RECALL);
WRITE32(dp->dl_stateid.si_generation); encode_stateid(xdr, &dp->dl_stateid);
WRITEMEM(&dp->dl_stateid.si_opaque, sizeof(stateid_opaque_t)); RESERVE_SPACE(8 + (XDR_QUADLEN(len) << 2));
WRITE32(0); /* truncate optimization not implemented */ WRITE32(0); /* truncate optimization not implemented */
WRITE32(len); WRITE32(len);
WRITEMEM(&dp->dl_fh.fh_base, len); WRITEMEM(&dp->dl_fh.fh_base, len);
...@@ -293,13 +301,14 @@ nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, ...@@ -293,13 +301,14 @@ nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p,
static int static int
decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){ decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){
__be32 *p; __be32 *p;
u32 taglen;
READ_BUF(8); READ_BUF(8);
READ32(hdr->status); READ32(hdr->status);
READ32(hdr->taglen); /* We've got no use for the tag; ignore it: */
READ_BUF(hdr->taglen + 4); READ32(taglen);
hdr->tag = (char *)p; READ_BUF(taglen + 4);
p += XDR_QUADLEN(hdr->taglen); p += XDR_QUADLEN(taglen);
READ32(hdr->nops); READ32(hdr->nops);
return 0; return 0;
} }
...@@ -667,28 +676,28 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) ...@@ -667,28 +676,28 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
} }
switch (task->tk_status) { switch (task->tk_status) {
case -EIO: case 0:
/* Network partition? */
atomic_set(&clp->cl_cb_set, 0);
warn_no_callback_path(clp, task->tk_status);
if (current_rpc_client != task->tk_client) {
/* queue a callback on the new connection: */
nfsd4_cb_recall(dp);
return; return;
}
case -EBADHANDLE: case -EBADHANDLE:
case -NFS4ERR_BAD_STATEID: case -NFS4ERR_BAD_STATEID:
/* Race: client probably got cb_recall /* Race: client probably got cb_recall
* before open reply granting delegation */ * before open reply granting delegation */
break; break;
default: default:
/* success, or error we can't handle */ /* Network partition? */
atomic_set(&clp->cl_cb_set, 0);
warn_no_callback_path(clp, task->tk_status);
if (current_rpc_client != task->tk_client) {
/* queue a callback on the new connection: */
atomic_inc(&dp->dl_count);
nfsd4_cb_recall(dp);
return; return;
} }
}
if (dp->dl_retries--) { if (dp->dl_retries--) {
rpc_delay(task, 2*HZ); rpc_delay(task, 2*HZ);
task->tk_status = 0; task->tk_status = 0;
rpc_restart_call(task); rpc_restart_call_prepare(task);
return; return;
} else { } else {
atomic_set(&clp->cl_cb_set, 0); atomic_set(&clp->cl_cb_set, 0);
...@@ -752,18 +761,16 @@ static void _nfsd4_cb_recall(struct nfs4_delegation *dp) ...@@ -752,18 +761,16 @@ static void _nfsd4_cb_recall(struct nfs4_delegation *dp)
.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
.rpc_cred = callback_cred .rpc_cred = callback_cred
}; };
int status;
if (clnt == NULL) if (clnt == NULL) {
nfs4_put_delegation(dp);
return; /* Client is shutting down; give up. */ return; /* Client is shutting down; give up. */
}
args->args_op = dp; args->args_op = dp;
msg.rpc_argp = args; msg.rpc_argp = args;
dp->dl_retries = 1; dp->dl_retries = 1;
status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT, rpc_call_async(clnt, &msg, RPC_TASK_SOFT, &nfsd4_cb_recall_ops, dp);
&nfsd4_cb_recall_ops, dp);
if (status)
nfs4_put_delegation(dp);
} }
void nfsd4_do_callback_rpc(struct work_struct *w) void nfsd4_do_callback_rpc(struct work_struct *w)
......
This diff is collapsed.
...@@ -2630,7 +2630,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, ...@@ -2630,7 +2630,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
} }
read->rd_vlen = v; read->rd_vlen = v;
nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp, nfserr = nfsd_read_file(read->rd_rqstp, read->rd_fhp, read->rd_filp,
read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen, read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen,
&maxcount); &maxcount);
...@@ -3325,6 +3325,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo ...@@ -3325,6 +3325,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
} }
/* Renew the clientid on success and on replay */ /* Renew the clientid on success and on replay */
release_session_client(cs->session); release_session_client(cs->session);
nfsd4_put_session(cs->session);
} }
return 1; return 1;
} }
......
...@@ -949,15 +949,12 @@ static ssize_t __write_ports_addfd(char *buf) ...@@ -949,15 +949,12 @@ static ssize_t __write_ports_addfd(char *buf)
if (err != 0) if (err != 0)
return err; return err;
err = lockd_up();
if (err != 0)
goto out;
err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
if (err < 0) if (err < 0) {
lockd_down(); svc_destroy(nfsd_serv);
return err;
}
out:
/* Decrease the count, but don't shut down the service */ /* Decrease the count, but don't shut down the service */
nfsd_serv->sv_nrthreads--; nfsd_serv->sv_nrthreads--;
return err; return err;
...@@ -978,9 +975,6 @@ static ssize_t __write_ports_delfd(char *buf) ...@@ -978,9 +975,6 @@ static ssize_t __write_ports_delfd(char *buf)
if (nfsd_serv != NULL) if (nfsd_serv != NULL)
len = svc_sock_names(nfsd_serv, buf, len = svc_sock_names(nfsd_serv, buf,
SIMPLE_TRANSACTION_LIMIT, toclose); SIMPLE_TRANSACTION_LIMIT, toclose);
if (len >= 0)
lockd_down();
kfree(toclose); kfree(toclose);
return len; return len;
} }
...@@ -1014,6 +1008,9 @@ static ssize_t __write_ports_addxprt(char *buf) ...@@ -1014,6 +1008,9 @@ static ssize_t __write_ports_addxprt(char *buf)
PF_INET6, port, SVC_SOCK_ANONYMOUS); PF_INET6, port, SVC_SOCK_ANONYMOUS);
if (err < 0 && err != -EAFNOSUPPORT) if (err < 0 && err != -EAFNOSUPPORT)
goto out_close; goto out_close;
/* Decrease the count, but don't shut down the service */
nfsd_serv->sv_nrthreads--;
return 0; return 0;
out_close: out_close:
xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port); xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port);
...@@ -1022,8 +1019,7 @@ static ssize_t __write_ports_addxprt(char *buf) ...@@ -1022,8 +1019,7 @@ static ssize_t __write_ports_addxprt(char *buf)
svc_xprt_put(xprt); svc_xprt_put(xprt);
} }
out_err: out_err:
/* Decrease the count, but don't shut down the service */ svc_destroy(nfsd_serv);
nfsd_serv->sv_nrthreads--;
return err; return err;
} }
...@@ -1194,7 +1190,7 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) ...@@ -1194,7 +1190,7 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
bsize = NFSSVC_MAXBLKSIZE; bsize = NFSSVC_MAXBLKSIZE;
bsize &= ~(1024-1); bsize &= ~(1024-1);
mutex_lock(&nfsd_mutex); mutex_lock(&nfsd_mutex);
if (nfsd_serv && nfsd_serv->sv_nrthreads) { if (nfsd_serv) {
mutex_unlock(&nfsd_mutex); mutex_unlock(&nfsd_mutex);
return -EBUSY; return -EBUSY;
} }
...@@ -1310,6 +1306,8 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) ...@@ -1310,6 +1306,8 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
return -EINVAL; return -EINVAL;
status = nfs4_reset_recoverydir(recdir); status = nfs4_reset_recoverydir(recdir);
if (status)
return status;
} }
return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n", return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
......
...@@ -153,6 +153,7 @@ void nfsd_lockd_shutdown(void); ...@@ -153,6 +153,7 @@ void nfsd_lockd_shutdown(void);
#define nfserr_bad_seqid cpu_to_be32(NFSERR_BAD_SEQID) #define nfserr_bad_seqid cpu_to_be32(NFSERR_BAD_SEQID)
#define nfserr_symlink cpu_to_be32(NFSERR_SYMLINK) #define nfserr_symlink cpu_to_be32(NFSERR_SYMLINK)
#define nfserr_not_same cpu_to_be32(NFSERR_NOT_SAME) #define nfserr_not_same cpu_to_be32(NFSERR_NOT_SAME)
#define nfserr_lock_range cpu_to_be32(NFSERR_LOCK_RANGE)
#define nfserr_restorefh cpu_to_be32(NFSERR_RESTOREFH) #define nfserr_restorefh cpu_to_be32(NFSERR_RESTOREFH)
#define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP) #define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP)
#define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR) #define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR)
......
...@@ -144,7 +144,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, ...@@ -144,7 +144,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
svc_reserve_auth(rqstp, (19<<2) + argp->count + 4); svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
resp->count = argp->count; resp->count = argp->count;
nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL, nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
argp->offset, argp->offset,
rqstp->rq_vec, argp->vlen, rqstp->rq_vec, argp->vlen,
&resp->count); &resp->count);
...@@ -290,7 +290,6 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, ...@@ -290,7 +290,6 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
* gospel of sun micro * gospel of sun micro
*/ */
if (type != S_IFREG) { if (type != S_IFREG) {
int is_borc = 0;
if (type != S_IFBLK && type != S_IFCHR) { if (type != S_IFBLK && type != S_IFCHR) {
rdev = 0; rdev = 0;
} else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) { } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
...@@ -298,7 +297,6 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, ...@@ -298,7 +297,6 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
type = S_IFIFO; type = S_IFIFO;
} else { } else {
/* Okay, char or block special */ /* Okay, char or block special */
is_borc = 1;
if (!rdev) if (!rdev)
rdev = wanted; rdev = wanted;
} }
......
...@@ -180,15 +180,80 @@ int nfsd_nrthreads(void) ...@@ -180,15 +180,80 @@ int nfsd_nrthreads(void)
return rv; return rv;
} }
static void nfsd_last_thread(struct svc_serv *serv) static int nfsd_init_socks(int port)
{ {
/* When last nfsd thread exits we need to do some clean-up */ int error;
struct svc_xprt *xprt; if (!list_empty(&nfsd_serv->sv_permsocks))
list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) return 0;
error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port,
SVC_SOCK_DEFAULTS);
if (error < 0)
return error;
error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port,
SVC_SOCK_DEFAULTS);
if (error < 0)
return error;
return 0;
}
static bool nfsd_up = false;
static int nfsd_startup(unsigned short port, int nrservs)
{
int ret;
if (nfsd_up)
return 0;
/*
* Readahead param cache - will no-op if it already exists.
* (Note therefore results will be suboptimal if number of
* threads is modified after nfsd start.)
*/
ret = nfsd_racache_init(2*nrservs);
if (ret)
return ret;
ret = nfsd_init_socks(port);
if (ret)
goto out_racache;
ret = lockd_up();
if (ret)
goto out_racache;
ret = nfs4_state_start();
if (ret)
goto out_lockd;
nfsd_up = true;
return 0;
out_lockd:
lockd_down(); lockd_down();
nfsd_serv = NULL; out_racache:
nfsd_racache_shutdown(); nfsd_racache_shutdown();
return ret;
}
static void nfsd_shutdown(void)
{
/*
* write_ports can create the server without actually starting
* any threads--if we get shut down before any threads are
* started, then nfsd_last_thread will be run before any of this
* other initialization has been done.
*/
if (!nfsd_up)
return;
nfs4_state_shutdown(); nfs4_state_shutdown();
lockd_down();
nfsd_racache_shutdown();
nfsd_up = false;
}
static void nfsd_last_thread(struct svc_serv *serv)
{
/* When last nfsd thread exits we need to do some clean-up */
nfsd_serv = NULL;
nfsd_shutdown();
printk(KERN_WARNING "nfsd: last server has exited, flushing export " printk(KERN_WARNING "nfsd: last server has exited, flushing export "
"cache\n"); "cache\n");
...@@ -263,45 +328,18 @@ int nfsd_create_serv(void) ...@@ -263,45 +328,18 @@ int nfsd_create_serv(void)
nfsd_max_blksize >= 8*1024*2) nfsd_max_blksize >= 8*1024*2)
nfsd_max_blksize /= 2; nfsd_max_blksize /= 2;
} }
nfsd_reset_versions();
nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
nfsd_last_thread, nfsd, THIS_MODULE); nfsd_last_thread, nfsd, THIS_MODULE);
if (nfsd_serv == NULL) if (nfsd_serv == NULL)
err = -ENOMEM; return -ENOMEM;
else
set_max_drc();
set_max_drc();
do_gettimeofday(&nfssvc_boot); /* record boot time */ do_gettimeofday(&nfssvc_boot); /* record boot time */
return err; return err;
} }
static int nfsd_init_socks(int port)
{
int error;
if (!list_empty(&nfsd_serv->sv_permsocks))
return 0;
error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port,
SVC_SOCK_DEFAULTS);
if (error < 0)
return error;
error = lockd_up();
if (error < 0)
return error;
error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port,
SVC_SOCK_DEFAULTS);
if (error < 0)
return error;
error = lockd_up();
if (error < 0)
return error;
return 0;
}
int nfsd_nrpools(void) int nfsd_nrpools(void)
{ {
if (nfsd_serv == NULL) if (nfsd_serv == NULL)
...@@ -376,10 +414,16 @@ int nfsd_set_nrthreads(int n, int *nthreads) ...@@ -376,10 +414,16 @@ int nfsd_set_nrthreads(int n, int *nthreads)
return err; return err;
} }
/*
* Adjust the number of threads and return the new number of threads.
* This is also the function that starts the server if necessary, if
* this is the first time nrservs is nonzero.
*/
int int
nfsd_svc(unsigned short port, int nrservs) nfsd_svc(unsigned short port, int nrservs)
{ {
int error; int error;
bool nfsd_up_before;
mutex_lock(&nfsd_mutex); mutex_lock(&nfsd_mutex);
dprintk("nfsd: creating service\n"); dprintk("nfsd: creating service\n");
...@@ -391,34 +435,29 @@ nfsd_svc(unsigned short port, int nrservs) ...@@ -391,34 +435,29 @@ nfsd_svc(unsigned short port, int nrservs)
if (nrservs == 0 && nfsd_serv == NULL) if (nrservs == 0 && nfsd_serv == NULL)
goto out; goto out;
/* Readahead param cache - will no-op if it already exists */ error = nfsd_create_serv();
error = nfsd_racache_init(2*nrservs);
if (error<0)
goto out;
error = nfs4_state_start();
if (error) if (error)
goto out; goto out;
nfsd_reset_versions(); nfsd_up_before = nfsd_up;
error = nfsd_create_serv();
error = nfsd_startup(port, nrservs);
if (error) if (error)
goto out; goto out_destroy;
error = nfsd_init_socks(port);
if (error)
goto failure;
error = svc_set_num_threads(nfsd_serv, NULL, nrservs); error = svc_set_num_threads(nfsd_serv, NULL, nrservs);
if (error == 0) if (error)
goto out_shutdown;
/* We are holding a reference to nfsd_serv which /* We are holding a reference to nfsd_serv which
* we don't want to count in the return value, * we don't want to count in the return value,
* so subtract 1 * so subtract 1
*/ */
error = nfsd_serv->sv_nrthreads - 1; error = nfsd_serv->sv_nrthreads - 1;
failure: out_shutdown:
if (error < 0 && !nfsd_up_before)
nfsd_shutdown();
out_destroy:
svc_destroy(nfsd_serv); /* Release server */ svc_destroy(nfsd_serv); /* Release server */
out: out:
mutex_unlock(&nfsd_mutex); mutex_unlock(&nfsd_mutex);
return error; return error;
} }
......
...@@ -88,7 +88,6 @@ struct nfs4_delegation { ...@@ -88,7 +88,6 @@ struct nfs4_delegation {
struct nfs4_client *dl_client; struct nfs4_client *dl_client;
struct nfs4_file *dl_file; struct nfs4_file *dl_file;
struct file_lock *dl_flock; struct file_lock *dl_flock;
struct file *dl_vfs_file;
u32 dl_type; u32 dl_type;
time_t dl_time; time_t dl_time;
/* For recall: */ /* For recall: */
...@@ -342,12 +341,50 @@ struct nfs4_file { ...@@ -342,12 +341,50 @@ struct nfs4_file {
struct list_head fi_hash; /* hash by "struct inode *" */ struct list_head fi_hash; /* hash by "struct inode *" */
struct list_head fi_stateids; struct list_head fi_stateids;
struct list_head fi_delegations; struct list_head fi_delegations;
/* One each for O_RDONLY, O_WRONLY, O_RDWR: */
struct file * fi_fds[3];
/* One each for O_RDONLY, O_WRONLY: */
atomic_t fi_access[2];
/*
* Each open stateid contributes 1 to either fi_readers or
* fi_writers, or both, depending on the open mode. A
* delegation also takes an fi_readers reference. Lock
* stateid's take none.
*/
atomic_t fi_readers;
atomic_t fi_writers;
struct inode *fi_inode; struct inode *fi_inode;
u32 fi_id; /* used with stateowner->so_id u32 fi_id; /* used with stateowner->so_id
* for stateid_hashtbl hash */ * for stateid_hashtbl hash */
bool fi_had_conflict; bool fi_had_conflict;
}; };
/* XXX: for first cut may fall back on returning file that doesn't work
* at all? */
static inline struct file *find_writeable_file(struct nfs4_file *f)
{
if (f->fi_fds[O_RDWR])
return f->fi_fds[O_RDWR];
return f->fi_fds[O_WRONLY];
}
static inline struct file *find_readable_file(struct nfs4_file *f)
{
if (f->fi_fds[O_RDWR])
return f->fi_fds[O_RDWR];
return f->fi_fds[O_RDONLY];
}
static inline struct file *find_any_file(struct nfs4_file *f)
{
if (f->fi_fds[O_RDWR])
return f->fi_fds[O_RDWR];
else if (f->fi_fds[O_RDWR])
return f->fi_fds[O_WRONLY];
else
return f->fi_fds[O_RDONLY];
}
/* /*
* nfs4_stateid can either be an open stateid or (eventually) a lock stateid * nfs4_stateid can either be an open stateid or (eventually) a lock stateid
* *
...@@ -373,7 +410,6 @@ struct nfs4_stateid { ...@@ -373,7 +410,6 @@ struct nfs4_stateid {
struct nfs4_stateowner * st_stateowner; struct nfs4_stateowner * st_stateowner;
struct nfs4_file * st_file; struct nfs4_file * st_file;
stateid_t st_stateid; stateid_t st_stateid;
struct file * st_vfs_file;
unsigned long st_access_bmap; unsigned long st_access_bmap;
unsigned long st_deny_bmap; unsigned long st_deny_bmap;
struct nfs4_stateid * st_openstp; struct nfs4_stateid * st_openstp;
......
...@@ -604,7 +604,7 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_ac ...@@ -604,7 +604,7 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_ac
return error; return error;
} }
#endif /* defined(CONFIG_NFS_V4) */ #endif /* defined(CONFIG_NFSD_V4) */
#ifdef CONFIG_NFSD_V3 #ifdef CONFIG_NFSD_V3
/* /*
...@@ -903,7 +903,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, ...@@ -903,7 +903,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
loff_t offset, struct kvec *vec, int vlen, unsigned long *count) loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
{ {
struct inode *inode; struct inode *inode;
struct raparms *ra;
mm_segment_t oldfs; mm_segment_t oldfs;
__be32 err; __be32 err;
int host_err; int host_err;
...@@ -914,12 +913,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, ...@@ -914,12 +913,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count)) if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count))
goto out; goto out;
/* Get readahead parameters */
ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino);
if (ra && ra->p_set)
file->f_ra = ra->p_ra;
if (file->f_op->splice_read && rqstp->rq_splice_ok) { if (file->f_op->splice_read && rqstp->rq_splice_ok) {
struct splice_desc sd = { struct splice_desc sd = {
.len = 0, .len = 0,
...@@ -937,16 +930,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, ...@@ -937,16 +930,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
set_fs(oldfs); set_fs(oldfs);
} }
/* Write back readahead params */
if (ra) {
struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
spin_lock(&rab->pb_lock);
ra->p_ra = file->f_ra;
ra->p_set = 1;
ra->p_count--;
spin_unlock(&rab->pb_lock);
}
if (host_err >= 0) { if (host_err >= 0) {
nfsdstats.io_read += host_err; nfsdstats.io_read += host_err;
*count = host_err; *count = host_err;
...@@ -1086,8 +1069,45 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, ...@@ -1086,8 +1069,45 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
* on entry. On return, *count contains the number of bytes actually read. * on entry. On return, *count contains the number of bytes actually read.
* N.B. After this call fhp needs an fh_put * N.B. After this call fhp needs an fh_put
*/ */
__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
{
struct file *file;
struct inode *inode;
struct raparms *ra;
__be32 err;
err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
if (err)
return err;
inode = file->f_path.dentry->d_inode;
/* Get readahead parameters */
ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino);
if (ra && ra->p_set)
file->f_ra = ra->p_ra;
err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
/* Write back readahead params */
if (ra) {
struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
spin_lock(&rab->pb_lock);
ra->p_ra = file->f_ra;
ra->p_set = 1;
ra->p_count--;
spin_unlock(&rab->pb_lock);
}
nfsd_close(file);
return err;
}
/* As above, but use the provided file descriptor. */
__be32 __be32
nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, nfsd_read_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
loff_t offset, struct kvec *vec, int vlen, loff_t offset, struct kvec *vec, int vlen,
unsigned long *count) unsigned long *count)
{ {
...@@ -1099,13 +1119,8 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, ...@@ -1099,13 +1119,8 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
if (err) if (err)
goto out; goto out;
err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count); err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
} else { } else /* Note file may still be NULL in NFSv4 special stateid case: */
err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); err = nfsd_read(rqstp, fhp, offset, vec, vlen, count);
if (err)
goto out;
err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
nfsd_close(file);
}
out: out:
return err; return err;
} }
...@@ -1631,7 +1646,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, ...@@ -1631,7 +1646,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
char *name, int len, struct svc_fh *tfhp) char *name, int len, struct svc_fh *tfhp)
{ {
struct dentry *ddir, *dnew, *dold; struct dentry *ddir, *dnew, *dold;
struct inode *dirp, *dest; struct inode *dirp;
__be32 err; __be32 err;
int host_err; int host_err;
...@@ -1659,7 +1674,6 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, ...@@ -1659,7 +1674,6 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
goto out_nfserr; goto out_nfserr;
dold = tfhp->fh_dentry; dold = tfhp->fh_dentry;
dest = dold->d_inode;
host_err = mnt_want_write(tfhp->fh_export->ex_path.mnt); host_err = mnt_want_write(tfhp->fh_export->ex_path.mnt);
if (host_err) { if (host_err) {
...@@ -2038,7 +2052,6 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, ...@@ -2038,7 +2052,6 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
struct dentry *dentry, int acc) struct dentry *dentry, int acc)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
struct path path;
int err; int err;
if (acc == NFSD_MAY_NOP) if (acc == NFSD_MAY_NOP)
...@@ -2111,15 +2124,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, ...@@ -2111,15 +2124,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
if (err == -EACCES && S_ISREG(inode->i_mode) && if (err == -EACCES && S_ISREG(inode->i_mode) &&
acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)) acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE))
err = inode_permission(inode, MAY_EXEC); err = inode_permission(inode, MAY_EXEC);
if (err)
goto nfsd_out;
/* Do integrity (permission) checking now, but defer incrementing
* IMA counts to the actual file open.
*/
path.mnt = exp->ex_path.mnt;
path.dentry = dentry;
nfsd_out:
return err? nfserrno(err) : 0; return err? nfserrno(err) : 0;
} }
......
...@@ -64,7 +64,9 @@ __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, ...@@ -64,7 +64,9 @@ __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *,
__be32 nfsd_open(struct svc_rqst *, struct svc_fh *, int, __be32 nfsd_open(struct svc_rqst *, struct svc_fh *, int,
int, struct file **); int, struct file **);
void nfsd_close(struct file *); void nfsd_close(struct file *);
__be32 nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *, __be32 nfsd_read(struct svc_rqst *, struct svc_fh *,
loff_t, struct kvec *, int, unsigned long *);
__be32 nfsd_read_file(struct svc_rqst *, struct svc_fh *, struct file *,
loff_t, struct kvec *, int, unsigned long *); loff_t, struct kvec *, int, unsigned long *);
__be32 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *, __be32 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
loff_t, struct kvec *,int, unsigned long *, int *); loff_t, struct kvec *,int, unsigned long *, int *);
......
...@@ -192,6 +192,7 @@ extern int cache_check(struct cache_detail *detail, ...@@ -192,6 +192,7 @@ extern int cache_check(struct cache_detail *detail,
extern void cache_flush(void); extern void cache_flush(void);
extern void cache_purge(struct cache_detail *detail); extern void cache_purge(struct cache_detail *detail);
#define NEVER (0x7FFFFFFF) #define NEVER (0x7FFFFFFF)
extern void __init cache_initialize(void);
extern int cache_register(struct cache_detail *cd); extern int cache_register(struct cache_detail *cd);
extern void cache_unregister(struct cache_detail *cd); extern void cache_unregister(struct cache_detail *cd);
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include <linux/sunrpc/cache.h> #include <linux/sunrpc/cache.h>
#include <linux/sunrpc/stats.h> #include <linux/sunrpc/stats.h>
#include <linux/sunrpc/rpc_pipe_fs.h> #include <linux/sunrpc/rpc_pipe_fs.h>
#include <linux/smp_lock.h>
#define RPCDBG_FACILITY RPCDBG_CACHE #define RPCDBG_FACILITY RPCDBG_CACHE
...@@ -320,7 +319,7 @@ static struct cache_detail *current_detail; ...@@ -320,7 +319,7 @@ static struct cache_detail *current_detail;
static int current_index; static int current_index;
static void do_cache_clean(struct work_struct *work); static void do_cache_clean(struct work_struct *work);
static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean); static struct delayed_work cache_cleaner;
static void sunrpc_init_cache_detail(struct cache_detail *cd) static void sunrpc_init_cache_detail(struct cache_detail *cd)
{ {
...@@ -1504,6 +1503,11 @@ static int create_cache_proc_entries(struct cache_detail *cd) ...@@ -1504,6 +1503,11 @@ static int create_cache_proc_entries(struct cache_detail *cd)
} }
#endif #endif
void __init cache_initialize(void)
{
INIT_DELAYED_WORK_DEFERRABLE(&cache_cleaner, do_cache_clean);
}
int cache_register(struct cache_detail *cd) int cache_register(struct cache_detail *cd)
{ {
int ret; int ret;
......
...@@ -44,6 +44,7 @@ init_sunrpc(void) ...@@ -44,6 +44,7 @@ init_sunrpc(void)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
rpc_proc_init(); rpc_proc_init();
#endif #endif
cache_initialize();
cache_register(&ip_map_cache); cache_register(&ip_map_cache);
cache_register(&unix_gid_cache); cache_register(&unix_gid_cache);
svc_init_xprt_sock(); /* svc sock transport */ svc_init_xprt_sock(); /* svc sock transport */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment