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 ...
This commit is contained in:
@@ -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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
/* 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,
|
|||||||
|
|
||||||
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 {
|
|||||||
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)
|
|||||||
* 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,
|
|||||||
__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,
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (task->tk_status) {
|
switch (task->tk_status) {
|
||||||
case -EIO:
|
case 0:
|
||||||
/* Network partition? */
|
return;
|
||||||
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;
|
|
||||||
}
|
|
||||||
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? */
|
||||||
return;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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)
|
|||||||
.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)
|
||||||
|
@@ -51,7 +51,6 @@ static time_t boot_time;
|
|||||||
static u32 current_ownerid = 1;
|
static u32 current_ownerid = 1;
|
||||||
static u32 current_fileid = 1;
|
static u32 current_fileid = 1;
|
||||||
static u32 current_delegid = 1;
|
static u32 current_delegid = 1;
|
||||||
static u32 nfs4_init;
|
|
||||||
static stateid_t zerostateid; /* bits all 0 */
|
static stateid_t zerostateid; /* bits all 0 */
|
||||||
static stateid_t onestateid; /* bits all 1 */
|
static stateid_t onestateid; /* bits all 1 */
|
||||||
static u64 current_sessionid = 1;
|
static u64 current_sessionid = 1;
|
||||||
@@ -163,6 +162,46 @@ static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];
|
|||||||
static struct list_head file_hashtbl[FILE_HASH_SIZE];
|
static struct list_head file_hashtbl[FILE_HASH_SIZE];
|
||||||
static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
|
static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
|
||||||
|
|
||||||
|
static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag)
|
||||||
|
{
|
||||||
|
BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR]));
|
||||||
|
atomic_inc(&fp->fi_access[oflag]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs4_file_get_access(struct nfs4_file *fp, int oflag)
|
||||||
|
{
|
||||||
|
if (oflag == O_RDWR) {
|
||||||
|
__nfs4_file_get_access(fp, O_RDONLY);
|
||||||
|
__nfs4_file_get_access(fp, O_WRONLY);
|
||||||
|
} else
|
||||||
|
__nfs4_file_get_access(fp, oflag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
|
||||||
|
{
|
||||||
|
if (fp->fi_fds[oflag]) {
|
||||||
|
fput(fp->fi_fds[oflag]);
|
||||||
|
fp->fi_fds[oflag] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
|
||||||
|
{
|
||||||
|
if (atomic_dec_and_test(&fp->fi_access[oflag])) {
|
||||||
|
nfs4_file_put_fd(fp, O_RDWR);
|
||||||
|
nfs4_file_put_fd(fp, oflag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
|
||||||
|
{
|
||||||
|
if (oflag == O_RDWR) {
|
||||||
|
__nfs4_file_put_access(fp, O_RDONLY);
|
||||||
|
__nfs4_file_put_access(fp, O_WRONLY);
|
||||||
|
} else
|
||||||
|
__nfs4_file_put_access(fp, oflag);
|
||||||
|
}
|
||||||
|
|
||||||
static struct nfs4_delegation *
|
static struct nfs4_delegation *
|
||||||
alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
|
alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
|
||||||
{
|
{
|
||||||
@@ -171,6 +210,13 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
|
|||||||
struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn;
|
struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn;
|
||||||
|
|
||||||
dprintk("NFSD alloc_init_deleg\n");
|
dprintk("NFSD alloc_init_deleg\n");
|
||||||
|
/*
|
||||||
|
* Major work on the lease subsystem (for example, to support
|
||||||
|
* calbacks on stat) will be required before we can support
|
||||||
|
* write delegations properly.
|
||||||
|
*/
|
||||||
|
if (type != NFS4_OPEN_DELEGATE_READ)
|
||||||
|
return NULL;
|
||||||
if (fp->fi_had_conflict)
|
if (fp->fi_had_conflict)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (num_delegations > max_delegations)
|
if (num_delegations > max_delegations)
|
||||||
@@ -185,9 +231,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
|
|||||||
dp->dl_client = clp;
|
dp->dl_client = clp;
|
||||||
get_nfs4_file(fp);
|
get_nfs4_file(fp);
|
||||||
dp->dl_file = fp;
|
dp->dl_file = fp;
|
||||||
|
nfs4_file_get_access(fp, O_RDONLY);
|
||||||
dp->dl_flock = NULL;
|
dp->dl_flock = NULL;
|
||||||
get_file(stp->st_vfs_file);
|
|
||||||
dp->dl_vfs_file = stp->st_vfs_file;
|
|
||||||
dp->dl_type = type;
|
dp->dl_type = type;
|
||||||
dp->dl_ident = cb->cb_ident;
|
dp->dl_ident = cb->cb_ident;
|
||||||
dp->dl_stateid.si_boot = boot_time;
|
dp->dl_stateid.si_boot = boot_time;
|
||||||
@@ -222,15 +267,12 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
|
|||||||
static void
|
static void
|
||||||
nfs4_close_delegation(struct nfs4_delegation *dp)
|
nfs4_close_delegation(struct nfs4_delegation *dp)
|
||||||
{
|
{
|
||||||
struct file *filp = dp->dl_vfs_file;
|
struct file *filp = find_readable_file(dp->dl_file);
|
||||||
|
|
||||||
dprintk("NFSD: close_delegation dp %p\n",dp);
|
dprintk("NFSD: close_delegation dp %p\n",dp);
|
||||||
dp->dl_vfs_file = NULL;
|
|
||||||
/* The following nfsd_close may not actually close the file,
|
|
||||||
* but we want to remove the lease in any case. */
|
|
||||||
if (dp->dl_flock)
|
if (dp->dl_flock)
|
||||||
vfs_setlease(filp, F_UNLCK, &dp->dl_flock);
|
vfs_setlease(filp, F_UNLCK, &dp->dl_flock);
|
||||||
nfsd_close(filp);
|
nfs4_file_put_access(dp->dl_file, O_RDONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called under the state lock. */
|
/* Called under the state lock. */
|
||||||
@@ -302,8 +344,12 @@ static void free_generic_stateid(struct nfs4_stateid *stp)
|
|||||||
|
|
||||||
static void release_lock_stateid(struct nfs4_stateid *stp)
|
static void release_lock_stateid(struct nfs4_stateid *stp)
|
||||||
{
|
{
|
||||||
|
struct file *file;
|
||||||
|
|
||||||
unhash_generic_stateid(stp);
|
unhash_generic_stateid(stp);
|
||||||
locks_remove_posix(stp->st_vfs_file, (fl_owner_t)stp->st_stateowner);
|
file = find_any_file(stp->st_file);
|
||||||
|
if (file)
|
||||||
|
locks_remove_posix(file, (fl_owner_t)stp->st_stateowner);
|
||||||
free_generic_stateid(stp);
|
free_generic_stateid(stp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,11 +387,85 @@ release_stateid_lockowners(struct nfs4_stateid *open_stp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We store the NONE, READ, WRITE, and BOTH bits separately in the
|
||||||
|
* st_{access,deny}_bmap field of the stateid, in order to track not
|
||||||
|
* only what share bits are currently in force, but also what
|
||||||
|
* combinations of share bits previous opens have used. This allows us
|
||||||
|
* to enforce the recommendation of rfc 3530 14.2.19 that the server
|
||||||
|
* return an error if the client attempt to downgrade to a combination
|
||||||
|
* of share bits not explicable by closing some of its previous opens.
|
||||||
|
*
|
||||||
|
* XXX: This enforcement is actually incomplete, since we don't keep
|
||||||
|
* track of access/deny bit combinations; so, e.g., we allow:
|
||||||
|
*
|
||||||
|
* OPEN allow read, deny write
|
||||||
|
* OPEN allow both, deny none
|
||||||
|
* DOWNGRADE allow read, deny none
|
||||||
|
*
|
||||||
|
* which we should reject.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
set_access(unsigned int *access, unsigned long bmap) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
*access = 0;
|
||||||
|
for (i = 1; i < 4; i++) {
|
||||||
|
if (test_bit(i, &bmap))
|
||||||
|
*access |= i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_deny(unsigned int *deny, unsigned long bmap) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
*deny = 0;
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
if (test_bit(i, &bmap))
|
||||||
|
*deny |= i ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {
|
||||||
|
unsigned int access, deny;
|
||||||
|
|
||||||
|
set_access(&access, stp->st_access_bmap);
|
||||||
|
set_deny(&deny, stp->st_deny_bmap);
|
||||||
|
if ((access & open->op_share_deny) || (deny & open->op_share_access))
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nfs4_access_to_omode(u32 access)
|
||||||
|
{
|
||||||
|
switch (access) {
|
||||||
|
case NFS4_SHARE_ACCESS_READ:
|
||||||
|
return O_RDONLY;
|
||||||
|
case NFS4_SHARE_ACCESS_WRITE:
|
||||||
|
return O_WRONLY;
|
||||||
|
case NFS4_SHARE_ACCESS_BOTH:
|
||||||
|
return O_RDWR;
|
||||||
|
}
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp)
|
||||||
|
{
|
||||||
|
unsigned int access;
|
||||||
|
|
||||||
|
set_access(&access, stp->st_access_bmap);
|
||||||
|
return nfs4_access_to_omode(access);
|
||||||
|
}
|
||||||
|
|
||||||
static void release_open_stateid(struct nfs4_stateid *stp)
|
static void release_open_stateid(struct nfs4_stateid *stp)
|
||||||
{
|
{
|
||||||
|
int oflag = nfs4_access_bmap_to_omode(stp);
|
||||||
|
|
||||||
unhash_generic_stateid(stp);
|
unhash_generic_stateid(stp);
|
||||||
release_stateid_lockowners(stp);
|
release_stateid_lockowners(stp);
|
||||||
nfsd_close(stp->st_vfs_file);
|
nfs4_file_put_access(stp->st_file, oflag);
|
||||||
free_generic_stateid(stp);
|
free_generic_stateid(stp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,7 +577,7 @@ static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan)
|
|||||||
spin_unlock(&nfsd_drc_lock);
|
spin_unlock(&nfsd_drc_lock);
|
||||||
|
|
||||||
if (fchan->maxreqs == 0)
|
if (fchan->maxreqs == 0)
|
||||||
return nfserr_serverfault;
|
return nfserr_jukebox;
|
||||||
|
|
||||||
fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ;
|
fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -542,7 +662,7 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp,
|
|||||||
BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot)
|
BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot)
|
||||||
+ sizeof(struct nfsd4_session) > PAGE_SIZE);
|
+ sizeof(struct nfsd4_session) > PAGE_SIZE);
|
||||||
|
|
||||||
status = nfserr_serverfault;
|
status = nfserr_jukebox;
|
||||||
/* allocate struct nfsd4_session and slot table pointers in one piece */
|
/* allocate struct nfsd4_session and slot table pointers in one piece */
|
||||||
slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *);
|
slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *);
|
||||||
new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL);
|
new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL);
|
||||||
@@ -591,10 +711,8 @@ find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid)
|
|||||||
|
|
||||||
dump_sessionid(__func__, sessionid);
|
dump_sessionid(__func__, sessionid);
|
||||||
idx = hash_sessionid(sessionid);
|
idx = hash_sessionid(sessionid);
|
||||||
dprintk("%s: idx is %d\n", __func__, idx);
|
|
||||||
/* Search in the appropriate list */
|
/* Search in the appropriate list */
|
||||||
list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) {
|
list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) {
|
||||||
dump_sessionid("list traversal", &elem->se_sessionid);
|
|
||||||
if (!memcmp(elem->se_sessionid.data, sessionid->data,
|
if (!memcmp(elem->se_sessionid.data, sessionid->data,
|
||||||
NFS4_MAX_SESSIONID_LEN)) {
|
NFS4_MAX_SESSIONID_LEN)) {
|
||||||
return elem;
|
return elem;
|
||||||
@@ -714,7 +832,6 @@ release_session_client(struct nfsd4_session *session)
|
|||||||
} else
|
} else
|
||||||
renew_client_locked(clp);
|
renew_client_locked(clp);
|
||||||
spin_unlock(&client_lock);
|
spin_unlock(&client_lock);
|
||||||
nfsd4_put_session(session);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* must be called under the client_lock */
|
/* must be called under the client_lock */
|
||||||
@@ -1220,7 +1337,7 @@ out_new:
|
|||||||
/* Normal case */
|
/* Normal case */
|
||||||
new = create_client(exid->clname, dname, rqstp, &verf);
|
new = create_client(exid->clname, dname, rqstp, &verf);
|
||||||
if (new == NULL) {
|
if (new == NULL) {
|
||||||
status = nfserr_serverfault;
|
status = nfserr_jukebox;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1760,6 +1877,8 @@ alloc_init_file(struct inode *ino)
|
|||||||
fp->fi_inode = igrab(ino);
|
fp->fi_inode = igrab(ino);
|
||||||
fp->fi_id = current_fileid++;
|
fp->fi_id = current_fileid++;
|
||||||
fp->fi_had_conflict = false;
|
fp->fi_had_conflict = false;
|
||||||
|
memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
|
||||||
|
memset(fp->fi_access, 0, sizeof(fp->fi_access));
|
||||||
spin_lock(&recall_lock);
|
spin_lock(&recall_lock);
|
||||||
list_add(&fp->fi_hash, &file_hashtbl[hashval]);
|
list_add(&fp->fi_hash, &file_hashtbl[hashval]);
|
||||||
spin_unlock(&recall_lock);
|
spin_unlock(&recall_lock);
|
||||||
@@ -1970,57 +2089,6 @@ static inline int deny_valid(u32 x)
|
|||||||
return x <= NFS4_SHARE_DENY_BOTH;
|
return x <= NFS4_SHARE_DENY_BOTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* We store the NONE, READ, WRITE, and BOTH bits separately in the
|
|
||||||
* st_{access,deny}_bmap field of the stateid, in order to track not
|
|
||||||
* only what share bits are currently in force, but also what
|
|
||||||
* combinations of share bits previous opens have used. This allows us
|
|
||||||
* to enforce the recommendation of rfc 3530 14.2.19 that the server
|
|
||||||
* return an error if the client attempt to downgrade to a combination
|
|
||||||
* of share bits not explicable by closing some of its previous opens.
|
|
||||||
*
|
|
||||||
* XXX: This enforcement is actually incomplete, since we don't keep
|
|
||||||
* track of access/deny bit combinations; so, e.g., we allow:
|
|
||||||
*
|
|
||||||
* OPEN allow read, deny write
|
|
||||||
* OPEN allow both, deny none
|
|
||||||
* DOWNGRADE allow read, deny none
|
|
||||||
*
|
|
||||||
* which we should reject.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
set_access(unsigned int *access, unsigned long bmap) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
*access = 0;
|
|
||||||
for (i = 1; i < 4; i++) {
|
|
||||||
if (test_bit(i, &bmap))
|
|
||||||
*access |= i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_deny(unsigned int *deny, unsigned long bmap) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
*deny = 0;
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
if (test_bit(i, &bmap))
|
|
||||||
*deny |= i ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {
|
|
||||||
unsigned int access, deny;
|
|
||||||
|
|
||||||
set_access(&access, stp->st_access_bmap);
|
|
||||||
set_deny(&deny, stp->st_deny_bmap);
|
|
||||||
if ((access & open->op_share_deny) || (deny & open->op_share_access))
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called to check deny when READ with all zero stateid or
|
* Called to check deny when READ with all zero stateid or
|
||||||
* WRITE with all zero or all one stateid
|
* WRITE with all zero or all one stateid
|
||||||
@@ -2052,14 +2120,12 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
nfs4_file_downgrade(struct file *filp, unsigned int share_access)
|
nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access)
|
||||||
{
|
{
|
||||||
if (share_access & NFS4_SHARE_ACCESS_WRITE) {
|
if (share_access & NFS4_SHARE_ACCESS_WRITE)
|
||||||
drop_file_write_access(filp);
|
nfs4_file_put_access(fp, O_WRONLY);
|
||||||
spin_lock(&filp->f_lock);
|
if (share_access & NFS4_SHARE_ACCESS_READ)
|
||||||
filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE;
|
nfs4_file_put_access(fp, O_RDONLY);
|
||||||
spin_unlock(&filp->f_lock);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2255,6 +2321,13 @@ find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int share_access_to_flags(u32 share_access)
|
||||||
|
{
|
||||||
|
share_access &= ~NFS4_SHARE_WANT_MASK;
|
||||||
|
|
||||||
|
return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
|
nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
|
||||||
struct nfs4_delegation **dp)
|
struct nfs4_delegation **dp)
|
||||||
@@ -2265,8 +2338,7 @@ nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
|
|||||||
*dp = find_delegation_file(fp, &open->op_delegate_stateid);
|
*dp = find_delegation_file(fp, &open->op_delegate_stateid);
|
||||||
if (*dp == NULL)
|
if (*dp == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ?
|
flags = share_access_to_flags(open->op_share_access);
|
||||||
RD_STATE : WR_STATE;
|
|
||||||
status = nfs4_check_delegmode(*dp, flags);
|
status = nfs4_check_delegmode(*dp, flags);
|
||||||
if (status)
|
if (status)
|
||||||
*dp = NULL;
|
*dp = NULL;
|
||||||
@@ -2308,30 +2380,53 @@ nfs4_alloc_stateid(void)
|
|||||||
return kmem_cache_alloc(stateid_slab, GFP_KERNEL);
|
return kmem_cache_alloc(stateid_slab, GFP_KERNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int nfs4_access_to_access(u32 nfs4_access)
|
||||||
|
{
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
if (nfs4_access & NFS4_SHARE_ACCESS_READ)
|
||||||
|
flags |= NFSD_MAY_READ;
|
||||||
|
if (nfs4_access & NFS4_SHARE_ACCESS_WRITE)
|
||||||
|
flags |= NFSD_MAY_WRITE;
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file
|
||||||
|
*fp, struct svc_fh *cur_fh, u32 nfs4_access)
|
||||||
|
{
|
||||||
|
__be32 status;
|
||||||
|
int oflag = nfs4_access_to_omode(nfs4_access);
|
||||||
|
int access = nfs4_access_to_access(nfs4_access);
|
||||||
|
|
||||||
|
if (!fp->fi_fds[oflag]) {
|
||||||
|
status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
|
||||||
|
&fp->fi_fds[oflag]);
|
||||||
|
if (status == nfserr_dropit)
|
||||||
|
status = nfserr_jukebox;
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
nfs4_file_get_access(fp, oflag);
|
||||||
|
|
||||||
|
return nfs_ok;
|
||||||
|
}
|
||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
|
nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
|
||||||
struct nfs4_delegation *dp,
|
struct nfs4_file *fp, struct svc_fh *cur_fh,
|
||||||
struct svc_fh *cur_fh, int flags)
|
struct nfsd4_open *open)
|
||||||
{
|
{
|
||||||
struct nfs4_stateid *stp;
|
struct nfs4_stateid *stp;
|
||||||
|
__be32 status;
|
||||||
|
|
||||||
stp = nfs4_alloc_stateid();
|
stp = nfs4_alloc_stateid();
|
||||||
if (stp == NULL)
|
if (stp == NULL)
|
||||||
return nfserr_resource;
|
return nfserr_resource;
|
||||||
|
|
||||||
if (dp) {
|
status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open->op_share_access);
|
||||||
get_file(dp->dl_vfs_file);
|
if (status) {
|
||||||
stp->st_vfs_file = dp->dl_vfs_file;
|
kmem_cache_free(stateid_slab, stp);
|
||||||
} else {
|
return status;
|
||||||
__be32 status;
|
|
||||||
status = nfsd_open(rqstp, cur_fh, S_IFREG, flags,
|
|
||||||
&stp->st_vfs_file);
|
|
||||||
if (status) {
|
|
||||||
if (status == nfserr_dropit)
|
|
||||||
status = nfserr_jukebox;
|
|
||||||
kmem_cache_free(stateid_slab, stp);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
*stpp = stp;
|
*stpp = stp;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2353,35 +2448,30 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
|
nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
|
||||||
{
|
{
|
||||||
struct file *filp = stp->st_vfs_file;
|
u32 op_share_access, new_access;
|
||||||
struct inode *inode = filp->f_path.dentry->d_inode;
|
|
||||||
unsigned int share_access, new_writer;
|
|
||||||
__be32 status;
|
__be32 status;
|
||||||
|
|
||||||
set_access(&share_access, stp->st_access_bmap);
|
set_access(&new_access, stp->st_access_bmap);
|
||||||
new_writer = (~share_access) & open->op_share_access
|
new_access = (~new_access) & open->op_share_access & ~NFS4_SHARE_WANT_MASK;
|
||||||
& NFS4_SHARE_ACCESS_WRITE;
|
|
||||||
|
|
||||||
if (new_writer) {
|
if (new_access) {
|
||||||
int err = get_write_access(inode);
|
status = nfs4_get_vfs_file(rqstp, fp, cur_fh, new_access);
|
||||||
if (err)
|
if (status)
|
||||||
return nfserrno(err);
|
return status;
|
||||||
err = mnt_want_write(cur_fh->fh_export->ex_path.mnt);
|
|
||||||
if (err)
|
|
||||||
return nfserrno(err);
|
|
||||||
file_take_write(filp);
|
|
||||||
}
|
}
|
||||||
status = nfsd4_truncate(rqstp, cur_fh, open);
|
status = nfsd4_truncate(rqstp, cur_fh, open);
|
||||||
if (status) {
|
if (status) {
|
||||||
if (new_writer)
|
if (new_access) {
|
||||||
put_write_access(inode);
|
int oflag = nfs4_access_to_omode(new_access);
|
||||||
|
nfs4_file_put_access(fp, oflag);
|
||||||
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
/* remember the open */
|
/* remember the open */
|
||||||
filp->f_mode |= open->op_share_access;
|
op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK;
|
||||||
__set_bit(open->op_share_access, &stp->st_access_bmap);
|
__set_bit(op_share_access, &stp->st_access_bmap);
|
||||||
__set_bit(open->op_share_deny, &stp->st_deny_bmap);
|
__set_bit(open->op_share_deny, &stp->st_deny_bmap);
|
||||||
|
|
||||||
return nfs_ok;
|
return nfs_ok;
|
||||||
@@ -2444,13 +2534,14 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
|
|||||||
fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
|
fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
|
||||||
fl.fl_end = OFFSET_MAX;
|
fl.fl_end = OFFSET_MAX;
|
||||||
fl.fl_owner = (fl_owner_t)dp;
|
fl.fl_owner = (fl_owner_t)dp;
|
||||||
fl.fl_file = stp->st_vfs_file;
|
fl.fl_file = find_readable_file(stp->st_file);
|
||||||
|
BUG_ON(!fl.fl_file);
|
||||||
fl.fl_pid = current->tgid;
|
fl.fl_pid = current->tgid;
|
||||||
|
|
||||||
/* vfs_setlease checks to see if delegation should be handed out.
|
/* vfs_setlease checks to see if delegation should be handed out.
|
||||||
* the lock_manager callbacks fl_mylease and fl_change are used
|
* the lock_manager callbacks fl_mylease and fl_change are used
|
||||||
*/
|
*/
|
||||||
if ((status = vfs_setlease(stp->st_vfs_file, fl.fl_type, &flp))) {
|
if ((status = vfs_setlease(fl.fl_file, fl.fl_type, &flp))) {
|
||||||
dprintk("NFSD: setlease failed [%d], no delegation\n", status);
|
dprintk("NFSD: setlease failed [%d], no delegation\n", status);
|
||||||
unhash_delegation(dp);
|
unhash_delegation(dp);
|
||||||
flag = NFS4_OPEN_DELEGATE_NONE;
|
flag = NFS4_OPEN_DELEGATE_NONE;
|
||||||
@@ -2514,18 +2605,12 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
|
|||||||
*/
|
*/
|
||||||
if (stp) {
|
if (stp) {
|
||||||
/* Stateid was found, this is an OPEN upgrade */
|
/* Stateid was found, this is an OPEN upgrade */
|
||||||
status = nfs4_upgrade_open(rqstp, current_fh, stp, open);
|
status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
|
||||||
if (status)
|
if (status)
|
||||||
goto out;
|
goto out;
|
||||||
update_stateid(&stp->st_stateid);
|
update_stateid(&stp->st_stateid);
|
||||||
} else {
|
} else {
|
||||||
/* Stateid was not found, this is a new OPEN */
|
status = nfs4_new_open(rqstp, &stp, fp, current_fh, open);
|
||||||
int flags = 0;
|
|
||||||
if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
|
|
||||||
flags |= NFSD_MAY_READ;
|
|
||||||
if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
|
|
||||||
flags |= NFSD_MAY_WRITE;
|
|
||||||
status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags);
|
|
||||||
if (status)
|
if (status)
|
||||||
goto out;
|
goto out;
|
||||||
init_stateid(stp, fp, open);
|
init_stateid(stp, fp, open);
|
||||||
@@ -2727,7 +2812,7 @@ search_close_lru(u32 st_id, int flags)
|
|||||||
static inline int
|
static inline int
|
||||||
nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
|
nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
|
||||||
{
|
{
|
||||||
return fhp->fh_dentry->d_inode != stp->st_vfs_file->f_path.dentry->d_inode;
|
return fhp->fh_dentry->d_inode != stp->st_file->fi_inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -2760,6 +2845,9 @@ __be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags)
|
|||||||
{
|
{
|
||||||
__be32 status = nfserr_openmode;
|
__be32 status = nfserr_openmode;
|
||||||
|
|
||||||
|
/* For lock stateid's, we test the parent open, not the lock: */
|
||||||
|
if (stp->st_openstp)
|
||||||
|
stp = stp->st_openstp;
|
||||||
if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap)))
|
if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap)))
|
||||||
goto out;
|
goto out;
|
||||||
if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap)))
|
if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap)))
|
||||||
@@ -2872,7 +2960,8 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
|
|||||||
goto out;
|
goto out;
|
||||||
renew_client(dp->dl_client);
|
renew_client(dp->dl_client);
|
||||||
if (filpp)
|
if (filpp)
|
||||||
*filpp = dp->dl_vfs_file;
|
*filpp = find_readable_file(dp->dl_file);
|
||||||
|
BUG_ON(!*filpp);
|
||||||
} else { /* open or lock stateid */
|
} else { /* open or lock stateid */
|
||||||
stp = find_stateid(stateid, flags);
|
stp = find_stateid(stateid, flags);
|
||||||
if (!stp)
|
if (!stp)
|
||||||
@@ -2889,8 +2978,13 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
|
|||||||
if (status)
|
if (status)
|
||||||
goto out;
|
goto out;
|
||||||
renew_client(stp->st_stateowner->so_client);
|
renew_client(stp->st_stateowner->so_client);
|
||||||
if (filpp)
|
if (filpp) {
|
||||||
*filpp = stp->st_vfs_file;
|
if (flags & RD_STATE)
|
||||||
|
*filpp = find_readable_file(stp->st_file);
|
||||||
|
else
|
||||||
|
*filpp = find_writeable_file(stp->st_file);
|
||||||
|
BUG_ON(!*filpp); /* assured by check_openmode */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
status = nfs_ok;
|
status = nfs_ok;
|
||||||
out:
|
out:
|
||||||
@@ -3126,8 +3220,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
set_access(&share_access, stp->st_access_bmap);
|
set_access(&share_access, stp->st_access_bmap);
|
||||||
nfs4_file_downgrade(stp->st_vfs_file,
|
nfs4_file_downgrade(stp->st_file, share_access & ~od->od_share_access);
|
||||||
share_access & ~od->od_share_access);
|
|
||||||
|
|
||||||
reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap);
|
reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap);
|
||||||
reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap);
|
reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap);
|
||||||
@@ -3346,11 +3439,9 @@ static inline void
|
|||||||
nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
|
nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
|
||||||
{
|
{
|
||||||
struct nfs4_stateowner *sop;
|
struct nfs4_stateowner *sop;
|
||||||
unsigned int hval;
|
|
||||||
|
|
||||||
if (fl->fl_lmops == &nfsd_posix_mng_ops) {
|
if (fl->fl_lmops == &nfsd_posix_mng_ops) {
|
||||||
sop = (struct nfs4_stateowner *) fl->fl_owner;
|
sop = (struct nfs4_stateowner *) fl->fl_owner;
|
||||||
hval = lockownerid_hashval(sop->so_id);
|
|
||||||
kref_get(&sop->so_ref);
|
kref_get(&sop->so_ref);
|
||||||
deny->ld_sop = sop;
|
deny->ld_sop = sop;
|
||||||
deny->ld_clientid = sop->so_client->cl_clientid;
|
deny->ld_clientid = sop->so_client->cl_clientid;
|
||||||
@@ -3446,8 +3537,6 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
|
|||||||
stp->st_stateid.si_stateownerid = sop->so_id;
|
stp->st_stateid.si_stateownerid = sop->so_id;
|
||||||
stp->st_stateid.si_fileid = fp->fi_id;
|
stp->st_stateid.si_fileid = fp->fi_id;
|
||||||
stp->st_stateid.si_generation = 0;
|
stp->st_stateid.si_generation = 0;
|
||||||
stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */
|
|
||||||
stp->st_access_bmap = open_stp->st_access_bmap;
|
|
||||||
stp->st_deny_bmap = open_stp->st_deny_bmap;
|
stp->st_deny_bmap = open_stp->st_deny_bmap;
|
||||||
stp->st_openstp = open_stp;
|
stp->st_openstp = open_stp;
|
||||||
|
|
||||||
@@ -3547,7 +3636,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
lock_sop = lock->lk_replay_owner;
|
lock_sop = lock->lk_replay_owner;
|
||||||
}
|
}
|
||||||
/* lock->lk_replay_owner and lock_stp have been created or found */
|
/* lock->lk_replay_owner and lock_stp have been created or found */
|
||||||
filp = lock_stp->st_vfs_file;
|
|
||||||
|
|
||||||
status = nfserr_grace;
|
status = nfserr_grace;
|
||||||
if (locks_in_grace() && !lock->lk_reclaim)
|
if (locks_in_grace() && !lock->lk_reclaim)
|
||||||
@@ -3560,11 +3648,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
switch (lock->lk_type) {
|
switch (lock->lk_type) {
|
||||||
case NFS4_READ_LT:
|
case NFS4_READ_LT:
|
||||||
case NFS4_READW_LT:
|
case NFS4_READW_LT:
|
||||||
|
filp = find_readable_file(lock_stp->st_file);
|
||||||
file_lock.fl_type = F_RDLCK;
|
file_lock.fl_type = F_RDLCK;
|
||||||
cmd = F_SETLK;
|
cmd = F_SETLK;
|
||||||
break;
|
break;
|
||||||
case NFS4_WRITE_LT:
|
case NFS4_WRITE_LT:
|
||||||
case NFS4_WRITEW_LT:
|
case NFS4_WRITEW_LT:
|
||||||
|
filp = find_writeable_file(lock_stp->st_file);
|
||||||
file_lock.fl_type = F_WRLCK;
|
file_lock.fl_type = F_WRLCK;
|
||||||
cmd = F_SETLK;
|
cmd = F_SETLK;
|
||||||
break;
|
break;
|
||||||
@@ -3572,6 +3662,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
status = nfserr_inval;
|
status = nfserr_inval;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if (!filp) {
|
||||||
|
status = nfserr_openmode;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
file_lock.fl_owner = (fl_owner_t)lock_sop;
|
file_lock.fl_owner = (fl_owner_t)lock_sop;
|
||||||
file_lock.fl_pid = current->tgid;
|
file_lock.fl_pid = current->tgid;
|
||||||
file_lock.fl_file = filp;
|
file_lock.fl_file = filp;
|
||||||
@@ -3740,7 +3834,11 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
&locku->lu_stateowner, &stp, NULL)))
|
&locku->lu_stateowner, &stp, NULL)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
filp = stp->st_vfs_file;
|
filp = find_any_file(stp->st_file);
|
||||||
|
if (!filp) {
|
||||||
|
status = nfserr_lock_range;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
BUG_ON(!filp);
|
BUG_ON(!filp);
|
||||||
locks_init_lock(&file_lock);
|
locks_init_lock(&file_lock);
|
||||||
file_lock.fl_type = F_UNLCK;
|
file_lock.fl_type = F_UNLCK;
|
||||||
@@ -3787,10 +3885,10 @@ out_nfserr:
|
|||||||
* 0: no locks held by lockowner
|
* 0: no locks held by lockowner
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
check_for_locks(struct file *filp, struct nfs4_stateowner *lowner)
|
check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner)
|
||||||
{
|
{
|
||||||
struct file_lock **flpp;
|
struct file_lock **flpp;
|
||||||
struct inode *inode = filp->f_path.dentry->d_inode;
|
struct inode *inode = filp->fi_inode;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
lock_kernel();
|
lock_kernel();
|
||||||
@@ -3841,7 +3939,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
|
|||||||
continue;
|
continue;
|
||||||
list_for_each_entry(stp, &sop->so_stateids,
|
list_for_each_entry(stp, &sop->so_stateids,
|
||||||
st_perstateowner) {
|
st_perstateowner) {
|
||||||
if (check_for_locks(stp->st_vfs_file, sop))
|
if (check_for_locks(stp->st_file, sop))
|
||||||
goto out;
|
goto out;
|
||||||
/* Note: so_perclient unused for lockowners,
|
/* Note: so_perclient unused for lockowners,
|
||||||
* so it's OK to fool with here. */
|
* so it's OK to fool with here. */
|
||||||
@@ -4066,16 +4164,8 @@ out_free_laundry:
|
|||||||
int
|
int
|
||||||
nfs4_state_start(void)
|
nfs4_state_start(void)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (nfs4_init)
|
|
||||||
return 0;
|
|
||||||
nfsd4_load_reboot_recovery_data();
|
nfsd4_load_reboot_recovery_data();
|
||||||
ret = __nfs4_state_start();
|
return __nfs4_state_start();
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
nfs4_init = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -4110,7 +4200,6 @@ __nfs4_state_shutdown(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
nfsd4_shutdown_recdir();
|
nfsd4_shutdown_recdir();
|
||||||
nfs4_init = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@@ -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
|
|||||||
}
|
}
|
||||||
/* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 @@ out_close:
|
|||||||
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)
|
|||||||
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)
|
|||||||
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);
|
|||||||
#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,
|
|||||||
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,
|
|||||||
* 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,
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
153
fs/nfsd/nfssvc.c
153
fs/nfsd/nfssvc.c
@@ -180,15 +180,80 @@ int nfsd_nrthreads(void)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 = 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();
|
||||||
|
out_racache:
|
||||||
|
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();
|
||||||
|
lockd_down();
|
||||||
|
nfsd_racache_shutdown();
|
||||||
|
nfsd_up = false;
|
||||||
|
}
|
||||||
|
|
||||||
static void nfsd_last_thread(struct svc_serv *serv)
|
static void nfsd_last_thread(struct svc_serv *serv)
|
||||||
{
|
{
|
||||||
/* When last nfsd thread exits we need to do some clean-up */
|
/* When last nfsd thread exits we need to do some clean-up */
|
||||||
struct svc_xprt *xprt;
|
|
||||||
list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list)
|
|
||||||
lockd_down();
|
|
||||||
nfsd_serv = NULL;
|
nfsd_serv = NULL;
|
||||||
nfsd_racache_shutdown();
|
nfsd_shutdown();
|
||||||
nfs4_state_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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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_racache_init(2*nrservs);
|
|
||||||
if (error<0)
|
|
||||||
goto out;
|
|
||||||
error = nfs4_state_start();
|
|
||||||
if (error)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
nfsd_reset_versions();
|
|
||||||
|
|
||||||
error = nfsd_create_serv();
|
error = nfsd_create_serv();
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
error = nfsd_init_socks(port);
|
|
||||||
if (error)
|
|
||||||
goto failure;
|
|
||||||
|
|
||||||
|
nfsd_up_before = nfsd_up;
|
||||||
|
|
||||||
|
error = nfsd_startup(port, nrservs);
|
||||||
|
if (error)
|
||||||
|
goto out_destroy;
|
||||||
error = svc_set_num_threads(nfsd_serv, NULL, nrservs);
|
error = svc_set_num_threads(nfsd_serv, NULL, nrservs);
|
||||||
if (error == 0)
|
if (error)
|
||||||
/* We are holding a reference to nfsd_serv which
|
goto out_shutdown;
|
||||||
* we don't want to count in the return value,
|
/* We are holding a reference to nfsd_serv which
|
||||||
* so subtract 1
|
* we don't want to count in the return value,
|
||||||
*/
|
* so subtract 1
|
||||||
error = nfsd_serv->sv_nrthreads - 1;
|
*/
|
||||||
failure:
|
error = nfsd_serv->sv_nrthreads - 1;
|
||||||
|
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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 @@ out:
|
|||||||
* 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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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 *,
|
|||||||
__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,
|
|||||||
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 @@
|
|||||||
#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;
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
#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)
|
|||||||
#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 */
|
||||||
|
Reference in New Issue
Block a user