Commit 48b901e5 authored by Stephen Rothwell's avatar Stephen Rothwell

Merge commit 'nfsd/nfsd-next'

parents 1617bbad ad7a0bbf
...@@ -166,7 +166,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock) ...@@ -166,7 +166,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
*/ */
if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid) if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid)
continue; continue;
if (!nlm_cmp_addr(nlm_addr(block->b_host), addr)) if (!rpc_cmp_addr(nlm_addr(block->b_host), addr))
continue; continue;
if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0) if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
continue; continue;
......
...@@ -111,7 +111,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni) ...@@ -111,7 +111,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
*/ */
chain = &nlm_hosts[nlm_hash_address(ni->sap)]; chain = &nlm_hosts[nlm_hash_address(ni->sap)];
hlist_for_each_entry(host, pos, chain, h_hash) { hlist_for_each_entry(host, pos, chain, h_hash) {
if (!nlm_cmp_addr(nlm_addr(host), ni->sap)) if (!rpc_cmp_addr(nlm_addr(host), ni->sap))
continue; continue;
/* See if we have an NSM handle for this client */ /* See if we have an NSM handle for this client */
...@@ -125,7 +125,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni) ...@@ -125,7 +125,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
if (host->h_server != ni->server) if (host->h_server != ni->server)
continue; continue;
if (ni->server && if (ni->server &&
!nlm_cmp_addr(nlm_srcaddr(host), ni->src_sap)) !rpc_cmp_addr(nlm_srcaddr(host), ni->src_sap))
continue; continue;
/* Move to head of hash chain. */ /* Move to head of hash chain. */
......
...@@ -209,7 +209,7 @@ static struct nsm_handle *nsm_lookup_addr(const struct sockaddr *sap) ...@@ -209,7 +209,7 @@ static struct nsm_handle *nsm_lookup_addr(const struct sockaddr *sap)
struct nsm_handle *nsm; struct nsm_handle *nsm;
list_for_each_entry(nsm, &nsm_handles, sm_link) list_for_each_entry(nsm, &nsm_handles, sm_link)
if (nlm_cmp_addr(nsm_addr(nsm), sap)) if (rpc_cmp_addr(nsm_addr(nsm), sap))
return nsm; return nsm;
return NULL; return NULL;
} }
......
...@@ -417,7 +417,7 @@ EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb); ...@@ -417,7 +417,7 @@ EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb);
static int static int
nlmsvc_match_ip(void *datap, struct nlm_host *host) nlmsvc_match_ip(void *datap, struct nlm_host *host)
{ {
return nlm_cmp_addr(nlm_srcaddr(host), datap); return rpc_cmp_addr(nlm_srcaddr(host), datap);
} }
/** /**
......
...@@ -1341,6 +1341,8 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp) ...@@ -1341,6 +1341,8 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
if (rv) if (rv)
goto out; goto out;
rv = check_nfsd_access(exp, rqstp); rv = check_nfsd_access(exp, rqstp);
if (rv)
fh_put(fhp);
out: out:
exp_put(exp); exp_put(exp);
return rv; return rv;
......
...@@ -814,17 +814,6 @@ encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, ...@@ -814,17 +814,6 @@ encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name,
return p; return p;
} }
static __be32 *
encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p,
struct svc_fh *fhp)
{
p = encode_post_op_attr(cd->rqstp, p, fhp);
*p++ = xdr_one; /* yes, a file handle follows */
p = encode_fh(p, fhp);
fh_put(fhp);
return p;
}
static int static int
compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
const char *name, int namlen) const char *name, int namlen)
...@@ -836,29 +825,54 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, ...@@ -836,29 +825,54 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
dparent = cd->fh.fh_dentry; dparent = cd->fh.fh_dentry;
exp = cd->fh.fh_export; exp = cd->fh.fh_export;
fh_init(fhp, NFS3_FHSIZE);
if (isdotent(name, namlen)) { if (isdotent(name, namlen)) {
if (namlen == 2) { if (namlen == 2) {
dchild = dget_parent(dparent); dchild = dget_parent(dparent);
if (dchild == dparent) { if (dchild == dparent) {
/* filesystem root - cannot return filehandle for ".." */ /* filesystem root - cannot return filehandle for ".." */
dput(dchild); dput(dchild);
return 1; return -ENOENT;
} }
} else } else
dchild = dget(dparent); dchild = dget(dparent);
} else } else
dchild = lookup_one_len(name, dparent, namlen); dchild = lookup_one_len(name, dparent, namlen);
if (IS_ERR(dchild)) if (IS_ERR(dchild))
return 1; return -ENOENT;
if (d_mountpoint(dchild) || rv = -ENOENT;
fh_compose(fhp, exp, dchild, &cd->fh) != 0 || if (d_mountpoint(dchild))
!dchild->d_inode) goto out;
rv = 1; rv = fh_compose(fhp, exp, dchild, &cd->fh);
if (rv)
goto out;
if (!dchild->d_inode)
goto out;
rv = 0;
out:
dput(dchild); dput(dchild);
return rv; return rv;
} }
__be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen)
{
struct svc_fh fh;
int err;
fh_init(&fh, NFS3_FHSIZE);
err = compose_entry_fh(cd, &fh, name, namlen);
if (err) {
*p++ = 0;
*p++ = 0;
goto out;
}
p = encode_post_op_attr(cd->rqstp, p, &fh);
*p++ = xdr_one; /* yes, a file handle follows */
p = encode_fh(p, &fh);
out:
fh_put(&fh);
return p;
}
/* /*
* Encode a directory entry. This one works for both normal readdir * Encode a directory entry. This one works for both normal readdir
* and readdirplus. * and readdirplus.
...@@ -929,16 +943,8 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen, ...@@ -929,16 +943,8 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
p = encode_entry_baggage(cd, p, name, namlen, ino); p = encode_entry_baggage(cd, p, name, namlen, ino);
/* throw in readdirplus baggage */ if (plus)
if (plus) { p = encode_entryplus_baggage(cd, p, name, namlen);
struct svc_fh fh;
if (compose_entry_fh(cd, &fh, name, namlen) > 0) {
*p++ = 0;
*p++ = 0;
} else
p = encode_entryplus_baggage(cd, p, &fh);
}
num_entry_words = p - cd->buffer; num_entry_words = p - cd->buffer;
} else if (cd->rqstp->rq_respages[pn+1] != NULL) { } else if (cd->rqstp->rq_respages[pn+1] != NULL) {
/* temporarily encode entry into next page, then move back to /* temporarily encode entry into next page, then move back to
...@@ -951,17 +957,8 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen, ...@@ -951,17 +957,8 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
p1 = encode_entry_baggage(cd, p1, name, namlen, ino); p1 = encode_entry_baggage(cd, p1, name, namlen, ino);
/* throw in readdirplus baggage */ if (plus)
if (plus) { p = encode_entryplus_baggage(cd, p1, name, namlen);
struct svc_fh fh;
if (compose_entry_fh(cd, &fh, name, namlen) > 0) {
/* zero out the filehandle */
*p1++ = 0;
*p1++ = 0;
} else
p1 = encode_entryplus_baggage(cd, p1, &fh);
}
/* determine entry word length and lengths to go in pages */ /* determine entry word length and lengths to go in pages */
num_entry_words = p1 - tmp; num_entry_words = p1 - tmp;
......
...@@ -321,7 +321,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, ...@@ -321,7 +321,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
deny = ~pas.group & pas.other; deny = ~pas.group & pas.other;
if (deny) { if (deny) {
ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; ace->flag = eflag;
ace->access_mask = deny_mask_from_posix(deny, flags); ace->access_mask = deny_mask_from_posix(deny, flags);
ace->whotype = NFS4_ACL_WHO_GROUP; ace->whotype = NFS4_ACL_WHO_GROUP;
ace++; ace++;
...@@ -335,7 +335,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, ...@@ -335,7 +335,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
if (deny) { if (deny) {
ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;
ace->access_mask = mask_from_posix(deny, flags); ace->access_mask = deny_mask_from_posix(deny, flags);
ace->whotype = NFS4_ACL_WHO_NAMED; ace->whotype = NFS4_ACL_WHO_NAMED;
ace->who = pa->e_id; ace->who = pa->e_id;
ace++; ace++;
......
This diff is collapsed.
...@@ -68,7 +68,6 @@ check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -68,7 +68,6 @@ check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
u32 *bmval, u32 *writable) u32 *bmval, u32 *writable)
{ {
struct dentry *dentry = cstate->current_fh.fh_dentry; struct dentry *dentry = cstate->current_fh.fh_dentry;
struct svc_export *exp = cstate->current_fh.fh_export;
/* /*
* Check about attributes are supported by the NFSv4 server or not. * Check about attributes are supported by the NFSv4 server or not.
...@@ -80,17 +79,13 @@ check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -80,17 +79,13 @@ check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
return nfserr_attrnotsupp; return nfserr_attrnotsupp;
/* /*
* Check FATTR4_WORD0_ACL & FATTR4_WORD0_FS_LOCATIONS can be supported * Check FATTR4_WORD0_ACL can be supported
* in current environment or not. * in current environment or not.
*/ */
if (bmval[0] & FATTR4_WORD0_ACL) { if (bmval[0] & FATTR4_WORD0_ACL) {
if (!IS_POSIXACL(dentry->d_inode)) if (!IS_POSIXACL(dentry->d_inode))
return nfserr_attrnotsupp; return nfserr_attrnotsupp;
} }
if (bmval[0] & FATTR4_WORD0_FS_LOCATIONS) {
if (exp->ex_fslocs.locations == NULL)
return nfserr_attrnotsupp;
}
/* /*
* According to spec, read-only attributes return ERR_INVAL. * According to spec, read-only attributes return ERR_INVAL.
...@@ -123,6 +118,35 @@ nfsd4_check_open_attributes(struct svc_rqst *rqstp, ...@@ -123,6 +118,35 @@ nfsd4_check_open_attributes(struct svc_rqst *rqstp,
return status; return status;
} }
static int
is_create_with_attrs(struct nfsd4_open *open)
{
return open->op_create == NFS4_OPEN_CREATE
&& (open->op_createmode == NFS4_CREATE_UNCHECKED
|| open->op_createmode == NFS4_CREATE_GUARDED
|| open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1);
}
/*
* if error occurs when setting the acl, just clear the acl bit
* in the returned attr bitmap.
*/
static void
do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct nfs4_acl *acl, u32 *bmval)
{
__be32 status;
status = nfsd4_set_nfs4_acl(rqstp, fhp, acl);
if (status)
/*
* We should probably fail the whole open at this point,
* but we've already created the file, so it's too late;
* So this seems the least of evils:
*/
bmval[0] &= ~FATTR4_WORD0_ACL;
}
static inline void static inline void
fh_dup2(struct svc_fh *dst, struct svc_fh *src) fh_dup2(struct svc_fh *dst, struct svc_fh *src)
{ {
...@@ -206,6 +230,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o ...@@ -206,6 +230,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
if (status) if (status)
goto out; goto out;
if (is_create_with_attrs(open) && open->op_acl != NULL)
do_set_nfs4_acl(rqstp, &resfh, open->op_acl, open->op_bmval);
set_change_info(&open->op_cinfo, current_fh); set_change_info(&open->op_cinfo, current_fh);
fh_dup2(current_fh, &resfh); fh_dup2(current_fh, &resfh);
...@@ -536,12 +563,17 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -536,12 +563,17 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfserr_badtype; status = nfserr_badtype;
} }
if (!status) { if (status)
fh_unlock(&cstate->current_fh); goto out;
set_change_info(&create->cr_cinfo, &cstate->current_fh);
fh_dup2(&cstate->current_fh, &resfh); if (create->cr_acl != NULL)
} do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
create->cr_bmval);
fh_unlock(&cstate->current_fh);
set_change_info(&create->cr_cinfo, &cstate->current_fh);
fh_dup2(&cstate->current_fh, &resfh);
out:
fh_put(&resfh); fh_put(&resfh);
return status; return status;
} }
...@@ -946,34 +978,6 @@ static struct nfsd4_operation nfsd4_ops[]; ...@@ -946,34 +978,6 @@ static struct nfsd4_operation nfsd4_ops[];
static const char *nfsd4_op_name(unsigned opnum); static const char *nfsd4_op_name(unsigned opnum);
/*
* This is a replay of a compound for which no cache entry pages
* were used. Encode the sequence operation, and if cachethis is FALSE
* encode the uncache rep error on the next operation.
*/
static __be32
nfsd4_enc_uncached_replay(struct nfsd4_compoundargs *args,
struct nfsd4_compoundres *resp)
{
struct nfsd4_op *op;
dprintk("--> %s resp->opcnt %d ce_cachethis %u \n", __func__,
resp->opcnt, resp->cstate.slot->sl_cache_entry.ce_cachethis);
/* Encode the replayed sequence operation */
BUG_ON(resp->opcnt != 1);
op = &args->ops[resp->opcnt - 1];
nfsd4_encode_operation(resp, op);
/*return nfserr_retry_uncached_rep in next operation. */
if (resp->cstate.slot->sl_cache_entry.ce_cachethis == 0) {
op = &args->ops[resp->opcnt++];
op->status = nfserr_retry_uncached_rep;
nfsd4_encode_operation(resp, op);
}
return op->status;
}
/* /*
* Enforce NFSv4.1 COMPOUND ordering rules. * Enforce NFSv4.1 COMPOUND ordering rules.
* *
...@@ -1083,13 +1087,10 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, ...@@ -1083,13 +1087,10 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
BUG_ON(op->status == nfs_ok); BUG_ON(op->status == nfs_ok);
encode_op: encode_op:
/* Only from SEQUENCE or CREATE_SESSION */ /* Only from SEQUENCE */
if (resp->cstate.status == nfserr_replay_cache) { if (resp->cstate.status == nfserr_replay_cache) {
dprintk("%s NFS4.1 replay from cache\n", __func__); dprintk("%s NFS4.1 replay from cache\n", __func__);
if (nfsd4_not_cached(resp)) status = op->status;
status = nfsd4_enc_uncached_replay(args, resp);
else
status = op->status;
goto out; goto out;
} }
if (op->status == nfserr_replay_me) { if (op->status == nfserr_replay_me) {
......
This diff is collapsed.
...@@ -1599,7 +1599,8 @@ static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, ...@@ -1599,7 +1599,8 @@ static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location,
static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat) static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat)
{ {
struct svc_fh tmp_fh; struct svc_fh tmp_fh;
char *path, *rootpath; char *path = NULL, *rootpath;
size_t rootlen;
fh_init(&tmp_fh, NFS4_FHSIZE); fh_init(&tmp_fh, NFS4_FHSIZE);
*stat = exp_pseudoroot(rqstp, &tmp_fh); *stat = exp_pseudoroot(rqstp, &tmp_fh);
...@@ -1609,14 +1610,18 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 * ...@@ -1609,14 +1610,18 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *
path = exp->ex_pathname; path = exp->ex_pathname;
if (strncmp(path, rootpath, strlen(rootpath))) { rootlen = strlen(rootpath);
if (strncmp(path, rootpath, rootlen)) {
dprintk("nfsd: fs_locations failed;" dprintk("nfsd: fs_locations failed;"
"%s is not contained in %s\n", path, rootpath); "%s is not contained in %s\n", path, rootpath);
*stat = nfserr_notsupp; *stat = nfserr_notsupp;
return NULL; path = NULL;
goto out;
} }
path += rootlen;
return path + strlen(rootpath); out:
fh_put(&tmp_fh);
return path;
} }
/* /*
...@@ -1793,11 +1798,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, ...@@ -1793,11 +1798,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
goto out_nfserr; goto out_nfserr;
} }
} }
if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
if (exp->ex_fslocs.locations == NULL) {
bmval0 &= ~FATTR4_WORD0_FS_LOCATIONS;
}
}
if ((buflen -= 16) < 0) if ((buflen -= 16) < 0)
goto out_resource; goto out_resource;
...@@ -1825,8 +1825,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, ...@@ -1825,8 +1825,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
goto out_resource; goto out_resource;
if (!aclsupport) if (!aclsupport)
word0 &= ~FATTR4_WORD0_ACL; word0 &= ~FATTR4_WORD0_ACL;
if (!exp->ex_fslocs.locations)
word0 &= ~FATTR4_WORD0_FS_LOCATIONS;
if (!word2) { if (!word2) {
WRITE32(2); WRITE32(2);
WRITE32(word0); WRITE32(word0);
...@@ -3064,6 +3062,7 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, ...@@ -3064,6 +3062,7 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
WRITE32(0); WRITE32(0);
ADJUST_ARGS(); ADJUST_ARGS();
resp->cstate.datap = p; /* DRC cache data pointer */
return 0; return 0;
} }
...@@ -3166,7 +3165,7 @@ static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp) ...@@ -3166,7 +3165,7 @@ static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp)
return status; return status;
session = resp->cstate.session; session = resp->cstate.session;
if (session == NULL || slot->sl_cache_entry.ce_cachethis == 0) if (session == NULL || slot->sl_cachethis == 0)
return status; return status;
if (resp->opcnt >= args->opcnt) if (resp->opcnt >= args->opcnt)
...@@ -3291,6 +3290,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo ...@@ -3291,6 +3290,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
/* /*
* All that remains is to write the tag and operation count... * All that remains is to write the tag and operation count...
*/ */
struct nfsd4_compound_state *cs = &resp->cstate;
struct kvec *iov; struct kvec *iov;
p = resp->tagp; p = resp->tagp;
*p++ = htonl(resp->taglen); *p++ = htonl(resp->taglen);
...@@ -3304,17 +3304,11 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo ...@@ -3304,17 +3304,11 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
iov = &rqstp->rq_res.head[0]; iov = &rqstp->rq_res.head[0];
iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base; iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base;
BUG_ON(iov->iov_len > PAGE_SIZE); BUG_ON(iov->iov_len > PAGE_SIZE);
if (nfsd4_has_session(&resp->cstate)) { if (nfsd4_has_session(cs) && cs->status != nfserr_replay_cache) {
if (resp->cstate.status == nfserr_replay_cache && nfsd4_store_cache_entry(resp);
!nfsd4_not_cached(resp)) { dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__);
iov->iov_len = resp->cstate.iovlen; resp->cstate.slot->sl_inuse = false;
} else { nfsd4_put_session(resp->cstate.session);
nfsd4_store_cache_entry(resp);
dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__);
resp->cstate.slot->sl_inuse = 0;
}
if (resp->cstate.session)
nfsd4_put_session(resp->cstate.session);
} }
return 1; return 1;
} }
......
...@@ -174,12 +174,13 @@ static const struct file_operations exports_operations = { ...@@ -174,12 +174,13 @@ static const struct file_operations exports_operations = {
}; };
extern int nfsd_pool_stats_open(struct inode *inode, struct file *file); extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
extern int nfsd_pool_stats_release(struct inode *inode, struct file *file);
static struct file_operations pool_stats_operations = { static struct file_operations pool_stats_operations = {
.open = nfsd_pool_stats_open, .open = nfsd_pool_stats_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
.release = seq_release, .release = nfsd_pool_stats_release,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
...@@ -776,10 +777,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) ...@@ -776,10 +777,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
size -= len; size -= len;
mesg += len; mesg += len;
} }
rv = mesg - buf;
mutex_unlock(&nfsd_mutex);
return (mesg-buf);
out_free: out_free:
kfree(nthreads); kfree(nthreads);
mutex_unlock(&nfsd_mutex); mutex_unlock(&nfsd_mutex);
......
...@@ -397,44 +397,51 @@ static inline void _fh_update_old(struct dentry *dentry, ...@@ -397,44 +397,51 @@ static inline void _fh_update_old(struct dentry *dentry,
fh->ofh_dirino = 0; fh->ofh_dirino = 0;
} }
__be32 static bool is_root_export(struct svc_export *exp)
fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
struct svc_fh *ref_fh)
{ {
/* ref_fh is a reference file handle. return exp->ex_path.dentry == exp->ex_path.dentry->d_sb->s_root;
* if it is non-null and for the same filesystem, then we should compose }
* a filehandle which is of the same version, where possible.
* Currently, that means that if ref_fh->fh_handle.fh_version == 0xca
* Then create a 32byte filehandle using nfs_fhbase_old
*
*/
u8 version; static struct super_block *exp_sb(struct svc_export *exp)
u8 fsid_type = 0; {
struct inode * inode = dentry->d_inode; return exp->ex_path.dentry->d_inode->i_sb;
struct dentry *parent = dentry->d_parent; }
__u32 *datap;
dev_t ex_dev = exp->ex_path.dentry->d_inode->i_sb->s_dev;
int root_export = (exp->ex_path.dentry == exp->ex_path.dentry->d_sb->s_root);
dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n", static bool fsid_type_ok_for_exp(u8 fsid_type, struct svc_export *exp)
MAJOR(ex_dev), MINOR(ex_dev), {
(long) exp->ex_path.dentry->d_inode->i_ino, switch (fsid_type) {
parent->d_name.name, dentry->d_name.name, case FSID_DEV:
(inode ? inode->i_ino : 0)); if (!old_valid_dev(exp_sb(exp)->s_dev))
return 0;
/* FALL THROUGH */
case FSID_MAJOR_MINOR:
case FSID_ENCODE_DEV:
return exp_sb(exp)->s_type->fs_flags & FS_REQUIRES_DEV;
case FSID_NUM:
return exp->ex_flags & NFSEXP_FSID;
case FSID_UUID8:
case FSID_UUID16:
if (!is_root_export(exp))
return 0;
/* fall through */
case FSID_UUID4_INUM:
case FSID_UUID16_INUM:
return exp->ex_uuid != NULL;
}
return 1;
}
/* Choose filehandle version and fsid type based on
* the reference filehandle (if it is in the same export) static void set_version_and_fsid_type(struct svc_fh *fhp, struct svc_export *exp, struct svc_fh *ref_fh)
* or the export options. {
*/ u8 version;
retry: u8 fsid_type;
retry:
version = 1; version = 1;
if (ref_fh && ref_fh->fh_export == exp) { if (ref_fh && ref_fh->fh_export == exp) {
version = ref_fh->fh_handle.fh_version; version = ref_fh->fh_handle.fh_version;
fsid_type = ref_fh->fh_handle.fh_fsid_type; fsid_type = ref_fh->fh_handle.fh_fsid_type;
if (ref_fh == fhp)
fh_put(ref_fh);
ref_fh = NULL; ref_fh = NULL;
switch (version) { switch (version) {
...@@ -447,58 +454,66 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, ...@@ -447,58 +454,66 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
goto retry; goto retry;
} }
/* Need to check that this type works for this /*
* export point. As the fsid -> filesystem mapping * As the fsid -> filesystem mapping was guided by
* was guided by user-space, there is no guarantee * user-space, there is no guarantee that the filesystem
* that the filesystem actually supports that fsid * actually supports that fsid type. If it doesn't we
* type. If it doesn't we loop around again without * loop around again without ref_fh set.
* ref_fh set.
*/ */
switch(fsid_type) { if (!fsid_type_ok_for_exp(fsid_type, exp))
case FSID_DEV: goto retry;
if (!old_valid_dev(ex_dev))
goto retry;
/* FALL THROUGH */
case FSID_MAJOR_MINOR:
case FSID_ENCODE_DEV:
if (!(exp->ex_path.dentry->d_inode->i_sb->s_type->fs_flags
& FS_REQUIRES_DEV))
goto retry;
break;
case FSID_NUM:
if (! (exp->ex_flags & NFSEXP_FSID))
goto retry;
break;
case FSID_UUID8:
case FSID_UUID16:
if (!root_export)
goto retry;
/* fall through */
case FSID_UUID4_INUM:
case FSID_UUID16_INUM:
if (exp->ex_uuid == NULL)
goto retry;
break;
}
} else if (exp->ex_flags & NFSEXP_FSID) { } else if (exp->ex_flags & NFSEXP_FSID) {
fsid_type = FSID_NUM; fsid_type = FSID_NUM;
} else if (exp->ex_uuid) { } else if (exp->ex_uuid) {
if (fhp->fh_maxsize >= 64) { if (fhp->fh_maxsize >= 64) {
if (root_export) if (is_root_export(exp))
fsid_type = FSID_UUID16; fsid_type = FSID_UUID16;
else else
fsid_type = FSID_UUID16_INUM; fsid_type = FSID_UUID16_INUM;
} else { } else {
if (root_export) if (is_root_export(exp))
fsid_type = FSID_UUID8; fsid_type = FSID_UUID8;
else else
fsid_type = FSID_UUID4_INUM; fsid_type = FSID_UUID4_INUM;
} }
} else if (!old_valid_dev(ex_dev)) } else if (!old_valid_dev(exp_sb(exp)->s_dev))
/* for newer device numbers, we must use a newer fsid format */ /* for newer device numbers, we must use a newer fsid format */
fsid_type = FSID_ENCODE_DEV; fsid_type = FSID_ENCODE_DEV;
else else
fsid_type = FSID_DEV; fsid_type = FSID_DEV;
fhp->fh_handle.fh_version = version;
if (version)
fhp->fh_handle.fh_fsid_type = fsid_type;
}
__be32
fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
struct svc_fh *ref_fh)
{
/* ref_fh is a reference file handle.
* if it is non-null and for the same filesystem, then we should compose
* a filehandle which is of the same version, where possible.
* Currently, that means that if ref_fh->fh_handle.fh_version == 0xca
* Then create a 32byte filehandle using nfs_fhbase_old
*
*/
struct inode * inode = dentry->d_inode;
struct dentry *parent = dentry->d_parent;
__u32 *datap;
dev_t ex_dev = exp_sb(exp)->s_dev;
dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n",
MAJOR(ex_dev), MINOR(ex_dev),
(long) exp->ex_path.dentry->d_inode->i_ino,
parent->d_name.name, dentry->d_name.name,
(inode ? inode->i_ino : 0));
/* Choose filehandle version and fsid type based on
* the reference filehandle (if it is in the same export)
* or the export options.
*/
set_version_and_fsid_type(fhp, exp, ref_fh);
if (ref_fh == fhp) if (ref_fh == fhp)
fh_put(ref_fh); fh_put(ref_fh);
...@@ -516,7 +531,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, ...@@ -516,7 +531,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
fhp->fh_export = exp; fhp->fh_export = exp;
cache_get(&exp->h); cache_get(&exp->h);
if (version == 0xca) { if (fhp->fh_handle.fh_version == 0xca) {
/* old style filehandle please */ /* old style filehandle please */
memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE); memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE);
fhp->fh_handle.fh_size = NFS_FHSIZE; fhp->fh_handle.fh_size = NFS_FHSIZE;
...@@ -530,22 +545,22 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, ...@@ -530,22 +545,22 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
_fh_update_old(dentry, exp, &fhp->fh_handle); _fh_update_old(dentry, exp, &fhp->fh_handle);
} else { } else {
int len; int len;
fhp->fh_handle.fh_version = 1;
fhp->fh_handle.fh_auth_type = 0; fhp->fh_handle.fh_auth_type = 0;
datap = fhp->fh_handle.fh_auth+0; datap = fhp->fh_handle.fh_auth+0;
fhp->fh_handle.fh_fsid_type = fsid_type; mk_fsid(fhp->fh_handle.fh_fsid_type, datap, ex_dev,
mk_fsid(fsid_type, datap, ex_dev,
exp->ex_path.dentry->d_inode->i_ino, exp->ex_path.dentry->d_inode->i_ino,
exp->ex_fsid, exp->ex_uuid); exp->ex_fsid, exp->ex_uuid);
len = key_len(fsid_type); len = key_len(fhp->fh_handle.fh_fsid_type);
datap += len/4; datap += len/4;
fhp->fh_handle.fh_size = 4 + len; fhp->fh_handle.fh_size = 4 + len;
if (inode) if (inode)
_fh_update(fhp, exp, dentry); _fh_update(fhp, exp, dentry);
if (fhp->fh_handle.fh_fileid_type == 255) if (fhp->fh_handle.fh_fileid_type == 255) {
fh_put(fhp);
return nfserr_opnotsupp; return nfserr_opnotsupp;
}
} }
return 0; return 0;
...@@ -639,8 +654,7 @@ enum fsid_source fsid_source(struct svc_fh *fhp) ...@@ -639,8 +654,7 @@ enum fsid_source fsid_source(struct svc_fh *fhp)
case FSID_DEV: case FSID_DEV:
case FSID_ENCODE_DEV: case FSID_ENCODE_DEV:
case FSID_MAJOR_MINOR: case FSID_MAJOR_MINOR:
if (fhp->fh_export->ex_path.dentry->d_inode->i_sb->s_type->fs_flags if (exp_sb(fhp->fh_export)->s_type->fs_flags & FS_REQUIRES_DEV)
& FS_REQUIRES_DEV)
return FSIDSOURCE_DEV; return FSIDSOURCE_DEV;
break; break;
case FSID_NUM: case FSID_NUM:
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/nfsd/syscall.h> #include <linux/nfsd/syscall.h>
#include <linux/lockd/bind.h> #include <linux/lockd/bind.h>
#include <linux/nfsacl.h> #include <linux/nfsacl.h>
#include <linux/seq_file.h>
#define NFSDDBG_FACILITY NFSDDBG_SVC #define NFSDDBG_FACILITY NFSDDBG_SVC
...@@ -66,6 +67,16 @@ struct timeval nfssvc_boot; ...@@ -66,6 +67,16 @@ struct timeval nfssvc_boot;
DEFINE_MUTEX(nfsd_mutex); DEFINE_MUTEX(nfsd_mutex);
struct svc_serv *nfsd_serv; struct svc_serv *nfsd_serv;
/*
* nfsd_drc_lock protects nfsd_drc_max_pages and nfsd_drc_pages_used.
* nfsd_drc_max_pages limits the total amount of memory available for
* version 4.1 DRC caches.
* nfsd_drc_pages_used tracks the current version 4.1 DRC memory usage.
*/
spinlock_t nfsd_drc_lock;
unsigned int nfsd_drc_max_mem;
unsigned int nfsd_drc_mem_used;
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
static struct svc_stat nfsd_acl_svcstats; static struct svc_stat nfsd_acl_svcstats;
static struct svc_version * nfsd_acl_version[] = { static struct svc_version * nfsd_acl_version[] = {
...@@ -235,13 +246,12 @@ void nfsd_reset_versions(void) ...@@ -235,13 +246,12 @@ void nfsd_reset_versions(void)
*/ */
static void set_max_drc(void) static void set_max_drc(void)
{ {
/* The percent of nr_free_buffer_pages used by the V4.1 server DRC */ #define NFSD_DRC_SIZE_SHIFT 10
#define NFSD_DRC_SIZE_SHIFT 7 nfsd_drc_max_mem = (nr_free_buffer_pages()
nfsd_serv->sv_drc_max_pages = nr_free_buffer_pages() >> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE;
>> NFSD_DRC_SIZE_SHIFT; nfsd_drc_mem_used = 0;
nfsd_serv->sv_drc_pages_used = 0; spin_lock_init(&nfsd_drc_lock);
dprintk("%s svc_drc_max_pages %u\n", __func__, dprintk("%s nfsd_drc_max_mem %u \n", __func__, nfsd_drc_max_mem);
nfsd_serv->sv_drc_max_pages);
} }
int nfsd_create_serv(void) int nfsd_create_serv(void)
...@@ -569,10 +579,6 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) ...@@ -569,10 +579,6 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
+ rqstp->rq_res.head[0].iov_len; + rqstp->rq_res.head[0].iov_len;
rqstp->rq_res.head[0].iov_len += sizeof(__be32); rqstp->rq_res.head[0].iov_len += sizeof(__be32);
/* NFSv4.1 DRC requires statp */
if (rqstp->rq_vers == 4)
nfsd4_set_statp(rqstp, statp);
/* Now call the procedure handler, and encode NFS status. */ /* Now call the procedure handler, and encode NFS status. */
nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
nfserr = map_new_errors(rqstp->rq_vers, nfserr); nfserr = map_new_errors(rqstp->rq_vers, nfserr);
...@@ -607,7 +613,25 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) ...@@ -607,7 +613,25 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
int nfsd_pool_stats_open(struct inode *inode, struct file *file) int nfsd_pool_stats_open(struct inode *inode, struct file *file)
{ {
if (nfsd_serv == NULL) int ret;
mutex_lock(&nfsd_mutex);
if (nfsd_serv == NULL) {
mutex_unlock(&nfsd_mutex);
return -ENODEV; return -ENODEV;
return svc_pool_stats_open(nfsd_serv, file); }
/* bump up the psudo refcount while traversing */
svc_get(nfsd_serv);
ret = svc_pool_stats_open(nfsd_serv, file);
mutex_unlock(&nfsd_mutex);
return ret;
}
int nfsd_pool_stats_release(struct inode *inode, struct file *file)
{
int ret = seq_release(inode, file);
mutex_lock(&nfsd_mutex);
/* this function really, really should have been called svc_put() */
svc_destroy(nfsd_serv);
mutex_unlock(&nfsd_mutex);
return ret;
} }
...@@ -338,49 +338,6 @@ static inline int nlm_privileged_requester(const struct svc_rqst *rqstp) ...@@ -338,49 +338,6 @@ static inline int nlm_privileged_requester(const struct svc_rqst *rqstp)
} }
} }
static inline int __nlm_cmp_addr4(const struct sockaddr *sap1,
const struct sockaddr *sap2)
{
const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sap1;
const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sap2;
return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static inline int __nlm_cmp_addr6(const struct sockaddr *sap1,
const struct sockaddr *sap2)
{
const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sap1;
const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sap2;
return ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr);
}
#else /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
static inline int __nlm_cmp_addr6(const struct sockaddr *sap1,
const struct sockaddr *sap2)
{
return 0;
}
#endif /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
/*
* Compare two host addresses
*
* Return TRUE if the addresses are the same; otherwise FALSE.
*/
static inline int nlm_cmp_addr(const struct sockaddr *sap1,
const struct sockaddr *sap2)
{
if (sap1->sa_family == sap2->sa_family) {
switch (sap1->sa_family) {
case AF_INET:
return __nlm_cmp_addr4(sap1, sap2);
case AF_INET6:
return __nlm_cmp_addr6(sap1, sap2);
}
}
return 0;
}
/* /*
* Compare two NLM locks. * Compare two NLM locks.
* When the second lock is of type F_UNLCK, this acts like a wildcard. * When the second lock is of type F_UNLCK, this acts like a wildcard.
......
...@@ -234,7 +234,7 @@ enum nfs_opnum4 { ...@@ -234,7 +234,7 @@ enum nfs_opnum4 {
Needs to be updated if more operations are defined in future.*/ Needs to be updated if more operations are defined in future.*/
#define FIRST_NFS4_OP OP_ACCESS #define FIRST_NFS4_OP OP_ACCESS
#define LAST_NFS4_OP OP_RELEASE_LOCKOWNER #define LAST_NFS4_OP OP_RECLAIM_COMPLETE
enum nfsstat4 { enum nfsstat4 {
NFS4_OK = 0, NFS4_OK = 0,
......
...@@ -56,6 +56,9 @@ extern struct svc_version nfsd_version2, nfsd_version3, ...@@ -56,6 +56,9 @@ extern struct svc_version nfsd_version2, nfsd_version3,
extern u32 nfsd_supported_minorversion; extern u32 nfsd_supported_minorversion;
extern struct mutex nfsd_mutex; extern struct mutex nfsd_mutex;
extern struct svc_serv *nfsd_serv; extern struct svc_serv *nfsd_serv;
extern spinlock_t nfsd_drc_lock;
extern unsigned int nfsd_drc_max_mem;
extern unsigned int nfsd_drc_mem_used;
extern struct seq_operations nfs_exports_op; extern struct seq_operations nfs_exports_op;
......
...@@ -60,6 +60,12 @@ typedef struct { ...@@ -60,6 +60,12 @@ typedef struct {
#define si_stateownerid si_opaque.so_stateownerid #define si_stateownerid si_opaque.so_stateownerid
#define si_fileid si_opaque.so_fileid #define si_fileid si_opaque.so_fileid
struct nfsd4_cb_sequence {
/* args/res */
u32 cbs_minorversion;
struct nfs4_client *cbs_clp;
};
struct nfs4_delegation { struct nfs4_delegation {
struct list_head dl_perfile; struct list_head dl_perfile;
struct list_head dl_perclnt; struct list_head dl_perclnt;
...@@ -81,8 +87,8 @@ struct nfs4_delegation { ...@@ -81,8 +87,8 @@ struct nfs4_delegation {
/* client delegation callback info */ /* client delegation callback info */
struct nfs4_cb_conn { struct nfs4_cb_conn {
/* SETCLIENTID info */ /* SETCLIENTID info */
u32 cb_addr; struct sockaddr_storage cb_addr;
unsigned short cb_port; size_t cb_addrlen;
u32 cb_prog; u32 cb_prog;
u32 cb_minorversion; u32 cb_minorversion;
u32 cb_ident; /* minorversion 0 only */ u32 cb_ident; /* minorversion 0 only */
...@@ -92,27 +98,25 @@ struct nfs4_cb_conn { ...@@ -92,27 +98,25 @@ struct nfs4_cb_conn {
struct rpc_cred * cb_cred; struct rpc_cred * cb_cred;
}; };
/* Maximum number of slots per session. 128 is useful for long haul TCP */ /* Maximum number of slots per session. 160 is useful for long haul TCP */
#define NFSD_MAX_SLOTS_PER_SESSION 128 #define NFSD_MAX_SLOTS_PER_SESSION 160
/* Maximum number of pages per slot cache entry */
#define NFSD_PAGES_PER_SLOT 1
/* Maximum number of operations per session compound */ /* Maximum number of operations per session compound */
#define NFSD_MAX_OPS_PER_COMPOUND 16 #define NFSD_MAX_OPS_PER_COMPOUND 16
/* Maximum session per slot cache size */
struct nfsd4_cache_entry { #define NFSD_SLOT_CACHE_SIZE 1024
__be32 ce_status; /* Maximum number of NFSD_SLOT_CACHE_SIZE slots per session */
struct kvec ce_datav; /* encoded NFSv4.1 data in rq_res.head[0] */ #define NFSD_CACHE_SIZE_SLOTS_PER_SESSION 32
struct page *ce_respages[NFSD_PAGES_PER_SLOT + 1]; #define NFSD_MAX_MEM_PER_SESSION \
int ce_cachethis; (NFSD_CACHE_SIZE_SLOTS_PER_SESSION * NFSD_SLOT_CACHE_SIZE)
short ce_resused;
int ce_opcnt;
int ce_rpchdrlen;
};
struct nfsd4_slot { struct nfsd4_slot {
bool sl_inuse; bool sl_inuse;
u32 sl_seqid; bool sl_cachethis;
struct nfsd4_cache_entry sl_cache_entry; u16 sl_opcnt;
u32 sl_seqid;
__be32 sl_status;
u32 sl_datalen;
char sl_data[];
}; };
struct nfsd4_channel_attrs { struct nfsd4_channel_attrs {
...@@ -126,6 +130,25 @@ struct nfsd4_channel_attrs { ...@@ -126,6 +130,25 @@ struct nfsd4_channel_attrs {
u32 rdma_attrs; u32 rdma_attrs;
}; };
struct nfsd4_create_session {
clientid_t clientid;
struct nfs4_sessionid sessionid;
u32 seqid;
u32 flags;
struct nfsd4_channel_attrs fore_channel;
struct nfsd4_channel_attrs back_channel;
u32 callback_prog;
u32 uid;
u32 gid;
};
/* The single slot clientid cache structure */
struct nfsd4_clid_slot {
u32 sl_seqid;
__be32 sl_status;
struct nfsd4_create_session sl_cr_ses;
};
struct nfsd4_session { struct nfsd4_session {
struct kref se_ref; struct kref se_ref;
struct list_head se_hash; /* hash by sessionid */ struct list_head se_hash; /* hash by sessionid */
...@@ -135,7 +158,7 @@ struct nfsd4_session { ...@@ -135,7 +158,7 @@ struct nfsd4_session {
struct nfs4_sessionid se_sessionid; struct nfs4_sessionid se_sessionid;
struct nfsd4_channel_attrs se_fchannel; struct nfsd4_channel_attrs se_fchannel;
struct nfsd4_channel_attrs se_bchannel; struct nfsd4_channel_attrs se_bchannel;
struct nfsd4_slot se_slots[]; /* forward channel slots */ struct nfsd4_slot *se_slots[]; /* forward channel slots */
}; };
static inline void static inline void
...@@ -180,7 +203,7 @@ struct nfs4_client { ...@@ -180,7 +203,7 @@ struct nfs4_client {
char cl_recdir[HEXDIR_LEN]; /* recovery dir */ char cl_recdir[HEXDIR_LEN]; /* recovery dir */
nfs4_verifier cl_verifier; /* generated by client */ nfs4_verifier cl_verifier; /* generated by client */
time_t cl_time; /* time of last lease renewal */ time_t cl_time; /* time of last lease renewal */
__be32 cl_addr; /* client ipaddress */ struct sockaddr_storage cl_addr; /* client ipaddress */
u32 cl_flavor; /* setclientid pseudoflavor */ u32 cl_flavor; /* setclientid pseudoflavor */
char *cl_principal; /* setclientid principal name */ char *cl_principal; /* setclientid principal name */
struct svc_cred cl_cred; /* setclientid principal */ struct svc_cred cl_cred; /* setclientid principal */
...@@ -192,9 +215,17 @@ struct nfs4_client { ...@@ -192,9 +215,17 @@ struct nfs4_client {
/* for nfs41 */ /* for nfs41 */
struct list_head cl_sessions; struct list_head cl_sessions;
struct nfsd4_slot cl_slot; /* create_session slot */ struct nfsd4_clid_slot cl_cs_slot; /* create_session slot */
u32 cl_exchange_flags; u32 cl_exchange_flags;
struct nfs4_sessionid cl_sessionid; struct nfs4_sessionid cl_sessionid;
/* for nfs41 callbacks */
/* We currently support a single back channel with a single slot */
unsigned long cl_cb_slot_busy;
u32 cl_cb_seq_nr;
struct svc_xprt *cl_cb_xprt; /* 4.1 callback transport */
struct rpc_wait_queue cl_cb_waitq; /* backchannel callers may */
/* wait here for slots */
}; };
/* struct nfs4_client_reset /* struct nfs4_client_reset
......
...@@ -51,7 +51,7 @@ struct nfsd4_compound_state { ...@@ -51,7 +51,7 @@ struct nfsd4_compound_state {
/* For sessions DRC */ /* For sessions DRC */
struct nfsd4_session *session; struct nfsd4_session *session;
struct nfsd4_slot *slot; struct nfsd4_slot *slot;
__be32 *statp; __be32 *datap;
size_t iovlen; size_t iovlen;
u32 minorversion; u32 minorversion;
u32 status; u32 status;
...@@ -366,18 +366,6 @@ struct nfsd4_exchange_id { ...@@ -366,18 +366,6 @@ struct nfsd4_exchange_id {
int spa_how; int spa_how;
}; };
struct nfsd4_create_session {
clientid_t clientid;
struct nfs4_sessionid sessionid;
u32 seqid;
u32 flags;
struct nfsd4_channel_attrs fore_channel;
struct nfsd4_channel_attrs back_channel;
u32 callback_prog;
u32 uid;
u32 gid;
};
struct nfsd4_sequence { struct nfsd4_sequence {
struct nfs4_sessionid sessionid; /* request/response */ struct nfs4_sessionid sessionid; /* request/response */
u32 seqid; /* request/response */ u32 seqid; /* request/response */
...@@ -479,13 +467,12 @@ struct nfsd4_compoundres { ...@@ -479,13 +467,12 @@ struct nfsd4_compoundres {
static inline bool nfsd4_is_solo_sequence(struct nfsd4_compoundres *resp) static inline bool nfsd4_is_solo_sequence(struct nfsd4_compoundres *resp)
{ {
struct nfsd4_compoundargs *args = resp->rqstp->rq_argp; struct nfsd4_compoundargs *args = resp->rqstp->rq_argp;
return args->opcnt == 1; return resp->opcnt == 1 && args->ops[0].opnum == OP_SEQUENCE;
} }
static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp) static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp)
{ {
return !resp->cstate.slot->sl_cache_entry.ce_cachethis || return !resp->cstate.slot->sl_cachethis || nfsd4_is_solo_sequence(resp);
nfsd4_is_solo_sequence(resp);
} }
#define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs) #define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs)
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/sunrpc/timer.h> #include <linux/sunrpc/timer.h>
#include <asm/signal.h> #include <asm/signal.h>
#include <linux/path.h> #include <linux/path.h>
#include <net/ipv6.h>
struct rpc_inode; struct rpc_inode;
...@@ -113,6 +114,7 @@ struct rpc_create_args { ...@@ -113,6 +114,7 @@ struct rpc_create_args {
rpc_authflavor_t authflavor; rpc_authflavor_t authflavor;
unsigned long flags; unsigned long flags;
char *client_name; char *client_name;
struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */
}; };
/* Values for "flags" field */ /* Values for "flags" field */
...@@ -188,5 +190,117 @@ static inline void rpc_set_port(struct sockaddr *sap, ...@@ -188,5 +190,117 @@ static inline void rpc_set_port(struct sockaddr *sap,
#define IPV6_SCOPE_DELIMITER '%' #define IPV6_SCOPE_DELIMITER '%'
#define IPV6_SCOPE_ID_LEN sizeof("%nnnnnnnnnn") #define IPV6_SCOPE_ID_LEN sizeof("%nnnnnnnnnn")
static inline bool __rpc_cmp_addr4(const struct sockaddr *sap1,
const struct sockaddr *sap2)
{
const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sap1;
const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sap2;
return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
}
static inline bool __rpc_copy_addr4(struct sockaddr *dst,
const struct sockaddr *src)
{
const struct sockaddr_in *ssin = (struct sockaddr_in *) src;
struct sockaddr_in *dsin = (struct sockaddr_in *) dst;
dsin->sin_family = ssin->sin_family;
dsin->sin_addr.s_addr = ssin->sin_addr.s_addr;
return true;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static inline bool __rpc_cmp_addr6(const struct sockaddr *sap1,
const struct sockaddr *sap2)
{
const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sap1;
const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sap2;
return ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr);
}
static inline bool __rpc_copy_addr6(struct sockaddr *dst,
const struct sockaddr *src)
{
const struct sockaddr_in6 *ssin6 = (const struct sockaddr_in6 *) src;
struct sockaddr_in6 *dsin6 = (struct sockaddr_in6 *) dst;
dsin6->sin6_family = ssin6->sin6_family;
ipv6_addr_copy(&dsin6->sin6_addr, &ssin6->sin6_addr);
return true;
}
#else /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
static inline bool __rpc_cmp_addr6(const struct sockaddr *sap1,
const struct sockaddr *sap2)
{
return false;
}
static inline bool __rpc_copy_addr6(struct sockaddr *dst,
const struct sockaddr *src)
{
return false;
}
#endif /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
/**
* rpc_cmp_addr - compare the address portion of two sockaddrs.
* @sap1: first sockaddr
* @sap2: second sockaddr
*
* Just compares the family and address portion. Ignores port, scope, etc.
* Returns true if the addrs are equal, false if they aren't.
*/
static inline bool rpc_cmp_addr(const struct sockaddr *sap1,
const struct sockaddr *sap2)
{
if (sap1->sa_family == sap2->sa_family) {
switch (sap1->sa_family) {
case AF_INET:
return __rpc_cmp_addr4(sap1, sap2);
case AF_INET6:
return __rpc_cmp_addr6(sap1, sap2);
}
}
return false;
}
/**
* rpc_copy_addr - copy the address portion of one sockaddr to another
* @dst: destination sockaddr
* @src: source sockaddr
*
* Just copies the address portion and family. Ignores port, scope, etc.
* Caller is responsible for making certain that dst is large enough to hold
* the address in src. Returns true if address family is supported. Returns
* false otherwise.
*/
static inline bool rpc_copy_addr(struct sockaddr *dst,
const struct sockaddr *src)
{
switch (src->sa_family) {
case AF_INET:
return __rpc_copy_addr4(dst, src);
case AF_INET6:
return __rpc_copy_addr6(dst, src);
}
return false;
}
/**
* rpc_get_scope_id - return scopeid for a given sockaddr
* @sa: sockaddr to get scopeid from
*
* Returns the value of the sin6_scope_id for AF_INET6 addrs, or 0 if
* not an AF_INET6 address.
*/
static inline u32 rpc_get_scope_id(const struct sockaddr *sa)
{
if (sa->sa_family != AF_INET6)
return 0;
return ((struct sockaddr_in6 *) sa)->sin6_scope_id;
}
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_CLNT_H */ #endif /* _LINUX_SUNRPC_CLNT_H */
...@@ -94,8 +94,6 @@ struct svc_serv { ...@@ -94,8 +94,6 @@ struct svc_serv {
struct module * sv_module; /* optional module to count when struct module * sv_module; /* optional module to count when
* adding threads */ * adding threads */
svc_thread_fn sv_function; /* main function for threads */ svc_thread_fn sv_function; /* main function for threads */
unsigned int sv_drc_max_pages; /* Total pages for DRC */
unsigned int sv_drc_pages_used;/* DRC pages used */
#if defined(CONFIG_NFS_V4_1) #if defined(CONFIG_NFS_V4_1)
struct list_head sv_cb_list; /* queue for callback requests struct list_head sv_cb_list; /* queue for callback requests
* that arrive over the same * that arrive over the same
......
...@@ -65,6 +65,7 @@ struct svc_xprt { ...@@ -65,6 +65,7 @@ struct svc_xprt {
size_t xpt_locallen; /* length of address */ size_t xpt_locallen; /* length of address */
struct sockaddr_storage xpt_remote; /* remote peer's address */ struct sockaddr_storage xpt_remote; /* remote peer's address */
size_t xpt_remotelen; /* length of address */ size_t xpt_remotelen; /* length of address */
struct rpc_wait_queue xpt_bc_pending; /* backchannel wait queue */
}; };
int svc_reg_xprt_class(struct svc_xprt_class *); int svc_reg_xprt_class(struct svc_xprt_class *);
......
...@@ -28,6 +28,7 @@ struct svc_sock { ...@@ -28,6 +28,7 @@ struct svc_sock {
/* private TCP part */ /* private TCP part */
u32 sk_reclen; /* length of record */ u32 sk_reclen; /* length of record */
u32 sk_tcplen; /* current read length */ u32 sk_tcplen; /* current read length */
struct rpc_xprt *sk_bc_xprt; /* NFSv4.1 backchannel xprt */
}; };
/* /*
......
...@@ -124,6 +124,23 @@ struct rpc_xprt_ops { ...@@ -124,6 +124,23 @@ struct rpc_xprt_ops {
void (*print_stats)(struct rpc_xprt *xprt, struct seq_file *seq); void (*print_stats)(struct rpc_xprt *xprt, struct seq_file *seq);
}; };
/*
* RPC transport identifiers
*
* To preserve compatibility with the historical use of raw IP protocol
* id's for transport selection, UDP and TCP identifiers are specified
* with the previous values. No such restriction exists for new transports,
* except that they may not collide with these values (17 and 6,
* respectively).
*/
#define XPRT_TRANSPORT_BC (1 << 31)
enum xprt_transports {
XPRT_TRANSPORT_UDP = IPPROTO_UDP,
XPRT_TRANSPORT_TCP = IPPROTO_TCP,
XPRT_TRANSPORT_BC_TCP = IPPROTO_TCP | XPRT_TRANSPORT_BC,
XPRT_TRANSPORT_RDMA = 256
};
struct rpc_xprt { struct rpc_xprt {
struct kref kref; /* Reference count */ struct kref kref; /* Reference count */
struct rpc_xprt_ops * ops; /* transport methods */ struct rpc_xprt_ops * ops; /* transport methods */
...@@ -179,6 +196,7 @@ struct rpc_xprt { ...@@ -179,6 +196,7 @@ struct rpc_xprt {
spinlock_t reserve_lock; /* lock slot table */ spinlock_t reserve_lock; /* lock slot table */
u32 xid; /* Next XID value to use */ u32 xid; /* Next XID value to use */
struct rpc_task * snd_task; /* Task blocked in send */ struct rpc_task * snd_task; /* Task blocked in send */
struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */
#if defined(CONFIG_NFS_V4_1) #if defined(CONFIG_NFS_V4_1)
struct svc_serv *bc_serv; /* The RPC service which will */ struct svc_serv *bc_serv; /* The RPC service which will */
/* process the callback */ /* process the callback */
...@@ -231,6 +249,7 @@ struct xprt_create { ...@@ -231,6 +249,7 @@ struct xprt_create {
struct sockaddr * srcaddr; /* optional local address */ struct sockaddr * srcaddr; /* optional local address */
struct sockaddr * dstaddr; /* remote peer address */ struct sockaddr * dstaddr; /* remote peer address */
size_t addrlen; size_t addrlen;
struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */
}; };
struct xprt_class { struct xprt_class {
......
...@@ -40,11 +40,6 @@ ...@@ -40,11 +40,6 @@
#ifndef _LINUX_SUNRPC_XPRTRDMA_H #ifndef _LINUX_SUNRPC_XPRTRDMA_H
#define _LINUX_SUNRPC_XPRTRDMA_H #define _LINUX_SUNRPC_XPRTRDMA_H
/*
* RPC transport identifier for RDMA
*/
#define XPRT_TRANSPORT_RDMA 256
/* /*
* rpcbind (v3+) RDMA netid. * rpcbind (v3+) RDMA netid.
*/ */
......
...@@ -12,17 +12,6 @@ ...@@ -12,17 +12,6 @@
int init_socket_xprt(void); int init_socket_xprt(void);
void cleanup_socket_xprt(void); void cleanup_socket_xprt(void);
/*
* RPC transport identifiers for UDP, TCP
*
* To preserve compatibility with the historical use of raw IP protocol
* id's for transport selection, these are specified with the previous
* values. No such restriction exists for new transports, except that
* they may not collide with these values (17 and 6, respectively).
*/
#define XPRT_TRANSPORT_UDP IPPROTO_UDP
#define XPRT_TRANSPORT_TCP IPPROTO_TCP
/* /*
* RPC slot table sizes for UDP, TCP transports * RPC slot table sizes for UDP, TCP transports
*/ */
......
...@@ -1374,8 +1374,10 @@ svcauth_gss_release(struct svc_rqst *rqstp) ...@@ -1374,8 +1374,10 @@ svcauth_gss_release(struct svc_rqst *rqstp)
if (stat) if (stat)
goto out_err; goto out_err;
break; break;
default: /*
goto out_err; * For any other gc_svc value, svcauth_gss_accept() already set
* the auth_error appropriately; just fall through:
*/
} }
out: out:
......
...@@ -103,23 +103,21 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, ...@@ -103,23 +103,21 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
EXPORT_SYMBOL_GPL(sunrpc_cache_lookup); EXPORT_SYMBOL_GPL(sunrpc_cache_lookup);
static void queue_loose(struct cache_detail *detail, struct cache_head *ch); static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch);
static int cache_fresh_locked(struct cache_head *head, time_t expiry) static void cache_fresh_locked(struct cache_head *head, time_t expiry)
{ {
head->expiry_time = expiry; head->expiry_time = expiry;
head->last_refresh = get_seconds(); head->last_refresh = get_seconds();
return !test_and_set_bit(CACHE_VALID, &head->flags); set_bit(CACHE_VALID, &head->flags);
} }
static void cache_fresh_unlocked(struct cache_head *head, static void cache_fresh_unlocked(struct cache_head *head,
struct cache_detail *detail, int new) struct cache_detail *detail)
{ {
if (new)
cache_revisit_request(head);
if (test_and_clear_bit(CACHE_PENDING, &head->flags)) { if (test_and_clear_bit(CACHE_PENDING, &head->flags)) {
cache_revisit_request(head); cache_revisit_request(head);
queue_loose(detail, head); cache_dequeue(detail, head);
} }
} }
...@@ -132,7 +130,6 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, ...@@ -132,7 +130,6 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
*/ */
struct cache_head **head; struct cache_head **head;
struct cache_head *tmp; struct cache_head *tmp;
int is_new;
if (!test_bit(CACHE_VALID, &old->flags)) { if (!test_bit(CACHE_VALID, &old->flags)) {
write_lock(&detail->hash_lock); write_lock(&detail->hash_lock);
...@@ -141,9 +138,9 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, ...@@ -141,9 +138,9 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
set_bit(CACHE_NEGATIVE, &old->flags); set_bit(CACHE_NEGATIVE, &old->flags);
else else
detail->update(old, new); detail->update(old, new);
is_new = cache_fresh_locked(old, new->expiry_time); cache_fresh_locked(old, new->expiry_time);
write_unlock(&detail->hash_lock); write_unlock(&detail->hash_lock);
cache_fresh_unlocked(old, detail, is_new); cache_fresh_unlocked(old, detail);
return old; return old;
} }
write_unlock(&detail->hash_lock); write_unlock(&detail->hash_lock);
...@@ -167,11 +164,11 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, ...@@ -167,11 +164,11 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
*head = tmp; *head = tmp;
detail->entries++; detail->entries++;
cache_get(tmp); cache_get(tmp);
is_new = cache_fresh_locked(tmp, new->expiry_time); cache_fresh_locked(tmp, new->expiry_time);
cache_fresh_locked(old, 0); cache_fresh_locked(old, 0);
write_unlock(&detail->hash_lock); write_unlock(&detail->hash_lock);
cache_fresh_unlocked(tmp, detail, is_new); cache_fresh_unlocked(tmp, detail);
cache_fresh_unlocked(old, detail, 0); cache_fresh_unlocked(old, detail);
cache_put(old, detail); cache_put(old, detail);
return tmp; return tmp;
} }
...@@ -184,6 +181,22 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h) ...@@ -184,6 +181,22 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h)
return cd->cache_upcall(cd, h); return cd->cache_upcall(cd, h);
} }
static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h)
{
if (!test_bit(CACHE_VALID, &h->flags) ||
h->expiry_time < get_seconds())
return -EAGAIN;
else if (detail->flush_time > h->last_refresh)
return -EAGAIN;
else {
/* entry is valid */
if (test_bit(CACHE_NEGATIVE, &h->flags))
return -ENOENT;
else
return 0;
}
}
/* /*
* This is the generic cache management routine for all * This is the generic cache management routine for all
* the authentication caches. * the authentication caches.
...@@ -192,8 +205,10 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h) ...@@ -192,8 +205,10 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h)
* *
* *
* Returns 0 if the cache_head can be used, or cache_puts it and returns * Returns 0 if the cache_head can be used, or cache_puts it and returns
* -EAGAIN if upcall is pending, * -EAGAIN if upcall is pending and request has been queued
* -ETIMEDOUT if upcall failed and should be retried, * -ETIMEDOUT if upcall failed or request could not be queue or
* upcall completed but item is still invalid (implying that
* the cache item has been replaced with a newer one).
* -ENOENT if cache entry was negative * -ENOENT if cache entry was negative
*/ */
int cache_check(struct cache_detail *detail, int cache_check(struct cache_detail *detail,
...@@ -203,17 +218,7 @@ int cache_check(struct cache_detail *detail, ...@@ -203,17 +218,7 @@ int cache_check(struct cache_detail *detail,
long refresh_age, age; long refresh_age, age;
/* First decide return status as best we can */ /* First decide return status as best we can */
if (!test_bit(CACHE_VALID, &h->flags) || rv = cache_is_valid(detail, h);
h->expiry_time < get_seconds())
rv = -EAGAIN;
else if (detail->flush_time > h->last_refresh)
rv = -EAGAIN;
else {
/* entry is valid */
if (test_bit(CACHE_NEGATIVE, &h->flags))
rv = -ENOENT;
else rv = 0;
}
/* now see if we want to start an upcall */ /* now see if we want to start an upcall */
refresh_age = (h->expiry_time - h->last_refresh); refresh_age = (h->expiry_time - h->last_refresh);
...@@ -229,10 +234,11 @@ int cache_check(struct cache_detail *detail, ...@@ -229,10 +234,11 @@ int cache_check(struct cache_detail *detail,
switch (cache_make_upcall(detail, h)) { switch (cache_make_upcall(detail, h)) {
case -EINVAL: case -EINVAL:
clear_bit(CACHE_PENDING, &h->flags); clear_bit(CACHE_PENDING, &h->flags);
cache_revisit_request(h);
if (rv == -EAGAIN) { if (rv == -EAGAIN) {
set_bit(CACHE_NEGATIVE, &h->flags); set_bit(CACHE_NEGATIVE, &h->flags);
cache_fresh_unlocked(h, detail, cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY);
cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY)); cache_fresh_unlocked(h, detail);
rv = -ENOENT; rv = -ENOENT;
} }
break; break;
...@@ -245,10 +251,14 @@ int cache_check(struct cache_detail *detail, ...@@ -245,10 +251,14 @@ int cache_check(struct cache_detail *detail,
} }
} }
if (rv == -EAGAIN) if (rv == -EAGAIN) {
if (cache_defer_req(rqstp, h) != 0) if (cache_defer_req(rqstp, h) < 0) {
rv = -ETIMEDOUT; /* Request is not deferred */
rv = cache_is_valid(detail, h);
if (rv == -EAGAIN)
rv = -ETIMEDOUT;
}
}
if (rv) if (rv)
cache_put(h, detail); cache_put(h, detail);
return rv; return rv;
...@@ -396,7 +406,7 @@ static int cache_clean(void) ...@@ -396,7 +406,7 @@ static int cache_clean(void)
) )
continue; continue;
if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) if (test_and_clear_bit(CACHE_PENDING, &ch->flags))
queue_loose(current_detail, ch); cache_dequeue(current_detail, ch);
if (atomic_read(&ch->ref.refcount) == 1) if (atomic_read(&ch->ref.refcount) == 1)
break; break;
...@@ -412,8 +422,10 @@ static int cache_clean(void) ...@@ -412,8 +422,10 @@ static int cache_clean(void)
if (!ch) if (!ch)
current_index ++; current_index ++;
spin_unlock(&cache_list_lock); spin_unlock(&cache_list_lock);
if (ch) if (ch) {
cache_revisit_request(ch);
cache_put(ch, d); cache_put(ch, d);
}
} else } else
spin_unlock(&cache_list_lock); spin_unlock(&cache_list_lock);
...@@ -496,11 +508,11 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item) ...@@ -496,11 +508,11 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item)
* or continue and drop the oldest below * or continue and drop the oldest below
*/ */
if (net_random()&1) if (net_random()&1)
return -ETIMEDOUT; return -ENOMEM;
} }
dreq = req->defer(req); dreq = req->defer(req);
if (dreq == NULL) if (dreq == NULL)
return -ETIMEDOUT; return -ENOMEM;
dreq->item = item; dreq->item = item;
...@@ -530,6 +542,7 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item) ...@@ -530,6 +542,7 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item)
if (!test_bit(CACHE_PENDING, &item->flags)) { if (!test_bit(CACHE_PENDING, &item->flags)) {
/* must have just been validated... */ /* must have just been validated... */
cache_revisit_request(item); cache_revisit_request(item);
return -EAGAIN;
} }
return 0; return 0;
} }
...@@ -887,7 +900,7 @@ static int cache_release(struct inode *inode, struct file *filp, ...@@ -887,7 +900,7 @@ static int cache_release(struct inode *inode, struct file *filp,
static void queue_loose(struct cache_detail *detail, struct cache_head *ch) static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch)
{ {
struct cache_queue *cq; struct cache_queue *cq;
spin_lock(&queue_lock); spin_lock(&queue_lock);
......
...@@ -288,6 +288,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) ...@@ -288,6 +288,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
.srcaddr = args->saddress, .srcaddr = args->saddress,
.dstaddr = args->address, .dstaddr = args->address,
.addrlen = args->addrsize, .addrlen = args->addrsize,
.bc_xprt = args->bc_xprt,
}; };
char servername[48]; char servername[48];
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include "sunrpc.h"
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
#define RPCDBG_FACILITY RPCDBG_SCHED #define RPCDBG_FACILITY RPCDBG_SCHED
#define RPC_TASK_MAGIC_ID 0xf00baa #define RPC_TASK_MAGIC_ID 0xf00baa
...@@ -711,11 +713,6 @@ static void rpc_async_schedule(struct work_struct *work) ...@@ -711,11 +713,6 @@ static void rpc_async_schedule(struct work_struct *work)
__rpc_execute(container_of(work, struct rpc_task, u.tk_work)); __rpc_execute(container_of(work, struct rpc_task, u.tk_work));
} }
struct rpc_buffer {
size_t len;
char data[];
};
/** /**
* rpc_malloc - allocate an RPC buffer * rpc_malloc - allocate an RPC buffer
* @task: RPC task that will use this buffer * @task: RPC task that will use this buffer
......
...@@ -27,11 +27,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -27,11 +27,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef _NET_SUNRPC_SUNRPC_H #ifndef _NET_SUNRPC_SUNRPC_H
#define _NET_SUNRPC_SUNRPC_H #define _NET_SUNRPC_SUNRPC_H
#include <linux/net.h>
/*
* Header for dynamically allocated rpc buffers.
*/
struct rpc_buffer {
size_t len;
char data[];
};
static inline int rpc_reply_expected(struct rpc_task *task) static inline int rpc_reply_expected(struct rpc_task *task)
{ {
return (task->tk_msg.rpc_proc != NULL) && return (task->tk_msg.rpc_proc != NULL) &&
(task->tk_msg.rpc_proc->p_decode != NULL); (task->tk_msg.rpc_proc->p_decode != NULL);
} }
int svc_send_common(struct socket *sock, struct xdr_buf *xdr,
struct page *headpage, unsigned long headoffset,
struct page *tailpage, unsigned long tailoffset);
#endif /* _NET_SUNRPC_SUNRPC_H */ #endif /* _NET_SUNRPC_SUNRPC_H */
...@@ -160,6 +160,7 @@ void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt, ...@@ -160,6 +160,7 @@ void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
mutex_init(&xprt->xpt_mutex); mutex_init(&xprt->xpt_mutex);
spin_lock_init(&xprt->xpt_lock); spin_lock_init(&xprt->xpt_lock);
set_bit(XPT_BUSY, &xprt->xpt_flags); set_bit(XPT_BUSY, &xprt->xpt_flags);
rpc_init_wait_queue(&xprt->xpt_bc_pending, "xpt_bc_pending");
} }
EXPORT_SYMBOL_GPL(svc_xprt_init); EXPORT_SYMBOL_GPL(svc_xprt_init);
...@@ -710,10 +711,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) ...@@ -710,10 +711,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
spin_unlock_bh(&pool->sp_lock); spin_unlock_bh(&pool->sp_lock);
len = 0; len = 0;
if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) { if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
dprintk("svc_recv: found XPT_CLOSE\n");
svc_delete_xprt(xprt);
} else if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
struct svc_xprt *newxpt; struct svc_xprt *newxpt;
newxpt = xprt->xpt_ops->xpo_accept(xprt); newxpt = xprt->xpt_ops->xpo_accept(xprt);
if (newxpt) { if (newxpt) {
...@@ -739,7 +737,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) ...@@ -739,7 +737,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
svc_xprt_received(newxpt); svc_xprt_received(newxpt);
} }
svc_xprt_received(xprt); svc_xprt_received(xprt);
} else { } else if (!test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n", dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n",
rqstp, pool->sp_id, xprt, rqstp, pool->sp_id, xprt,
atomic_read(&xprt->xpt_ref.refcount)); atomic_read(&xprt->xpt_ref.refcount));
...@@ -752,6 +750,11 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) ...@@ -752,6 +750,11 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
dprintk("svc: got len=%d\n", len); dprintk("svc: got len=%d\n", len);
} }
if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
dprintk("svc_recv: found XPT_CLOSE\n");
svc_delete_xprt(xprt);
}
/* No data, incomplete (TCP) read, or accept() */ /* No data, incomplete (TCP) read, or accept() */
if (len == 0 || len == -EAGAIN) { if (len == 0 || len == -EAGAIN) {
rqstp->rq_res.len = 0; rqstp->rq_res.len = 0;
...@@ -808,6 +811,7 @@ int svc_send(struct svc_rqst *rqstp) ...@@ -808,6 +811,7 @@ int svc_send(struct svc_rqst *rqstp)
else else
len = xprt->xpt_ops->xpo_sendto(rqstp); len = xprt->xpt_ops->xpo_sendto(rqstp);
mutex_unlock(&xprt->xpt_mutex); mutex_unlock(&xprt->xpt_mutex);
rpc_wake_up(&xprt->xpt_bc_pending);
svc_xprt_release(rqstp); svc_xprt_release(rqstp);
if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN) if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN)
...@@ -1166,11 +1170,6 @@ static void *svc_pool_stats_start(struct seq_file *m, loff_t *pos) ...@@ -1166,11 +1170,6 @@ static void *svc_pool_stats_start(struct seq_file *m, loff_t *pos)
dprintk("svc_pool_stats_start, *pidx=%u\n", pidx); dprintk("svc_pool_stats_start, *pidx=%u\n", pidx);
lock_kernel();
/* bump up the pseudo refcount while traversing */
svc_get(serv);
unlock_kernel();
if (!pidx) if (!pidx)
return SEQ_START_TOKEN; return SEQ_START_TOKEN;
return (pidx > serv->sv_nrpools ? NULL : &serv->sv_pools[pidx-1]); return (pidx > serv->sv_nrpools ? NULL : &serv->sv_pools[pidx-1]);
...@@ -1198,12 +1197,6 @@ static void *svc_pool_stats_next(struct seq_file *m, void *p, loff_t *pos) ...@@ -1198,12 +1197,6 @@ static void *svc_pool_stats_next(struct seq_file *m, void *p, loff_t *pos)
static void svc_pool_stats_stop(struct seq_file *m, void *p) static void svc_pool_stats_stop(struct seq_file *m, void *p)
{ {
struct svc_serv *serv = m->private;
lock_kernel();
/* this function really, really should have been called svc_put() */
svc_destroy(serv);
unlock_kernel();
} }
static int svc_pool_stats_show(struct seq_file *m, void *p) static int svc_pool_stats_show(struct seq_file *m, void *p)
......
...@@ -668,6 +668,7 @@ static int unix_gid_find(uid_t uid, struct group_info **gip, ...@@ -668,6 +668,7 @@ static int unix_gid_find(uid_t uid, struct group_info **gip,
case 0: case 0:
*gip = ug->gi; *gip = ug->gi;
get_group_info(*gip); get_group_info(*gip);
cache_put(&ug->h, &unix_gid_cache);
return 0; return 0;
default: default:
return -EAGAIN; return -EAGAIN;
......
This diff is collapsed.
...@@ -832,6 +832,11 @@ static void xprt_timer(struct rpc_task *task) ...@@ -832,6 +832,11 @@ static void xprt_timer(struct rpc_task *task)
spin_unlock_bh(&xprt->transport_lock); spin_unlock_bh(&xprt->transport_lock);
} }
static inline int xprt_has_timer(struct rpc_xprt *xprt)
{
return xprt->idle_timeout != 0;
}
/** /**
* xprt_prepare_transmit - reserve the transport before sending a request * xprt_prepare_transmit - reserve the transport before sending a request
* @task: RPC task about to send a request * @task: RPC task about to send a request
...@@ -1013,7 +1018,7 @@ void xprt_release(struct rpc_task *task) ...@@ -1013,7 +1018,7 @@ void xprt_release(struct rpc_task *task)
if (!list_empty(&req->rq_list)) if (!list_empty(&req->rq_list))
list_del(&req->rq_list); list_del(&req->rq_list);
xprt->last_used = jiffies; xprt->last_used = jiffies;
if (list_empty(&xprt->recv)) if (list_empty(&xprt->recv) && xprt_has_timer(xprt))
mod_timer(&xprt->timer, mod_timer(&xprt->timer,
xprt->last_used + xprt->idle_timeout); xprt->last_used + xprt->idle_timeout);
spin_unlock_bh(&xprt->transport_lock); spin_unlock_bh(&xprt->transport_lock);
...@@ -1082,8 +1087,11 @@ found: ...@@ -1082,8 +1087,11 @@ found:
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
INIT_WORK(&xprt->task_cleanup, xprt_autoclose); INIT_WORK(&xprt->task_cleanup, xprt_autoclose);
setup_timer(&xprt->timer, xprt_init_autodisconnect, if (xprt_has_timer(xprt))
(unsigned long)xprt); setup_timer(&xprt->timer, xprt_init_autodisconnect,
(unsigned long)xprt);
else
init_timer(&xprt->timer);
xprt->last_used = jiffies; xprt->last_used = jiffies;
xprt->cwnd = RPC_INITCWND; xprt->cwnd = RPC_INITCWND;
xprt->bind_index = 0; xprt->bind_index = 0;
...@@ -1102,7 +1110,6 @@ found: ...@@ -1102,7 +1110,6 @@ found:
dprintk("RPC: created transport %p with %u slots\n", xprt, dprintk("RPC: created transport %p with %u slots\n", xprt,
xprt->max_reqs); xprt->max_reqs);
return xprt; return xprt;
} }
......
...@@ -730,12 +730,12 @@ static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt) ...@@ -730,12 +730,12 @@ static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt)
goto err; goto err;
mr = ib_alloc_fast_reg_mr(xprt->sc_pd, RPCSVC_MAXPAGES); mr = ib_alloc_fast_reg_mr(xprt->sc_pd, RPCSVC_MAXPAGES);
if (!mr) if (IS_ERR(mr))
goto err_free_frmr; goto err_free_frmr;
pl = ib_alloc_fast_reg_page_list(xprt->sc_cm_id->device, pl = ib_alloc_fast_reg_page_list(xprt->sc_cm_id->device,
RPCSVC_MAXPAGES); RPCSVC_MAXPAGES);
if (!pl) if (IS_ERR(pl))
goto err_free_mr; goto err_free_mr;
frmr->mr = mr; frmr->mr = mr;
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/tcp.h> #include <linux/tcp.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/sched.h> #include <linux/sunrpc/sched.h>
#include <linux/sunrpc/svcsock.h>
#include <linux/sunrpc/xprtsock.h> #include <linux/sunrpc/xprtsock.h>
#include <linux/file.h> #include <linux/file.h>
#ifdef CONFIG_NFS_V4_1 #ifdef CONFIG_NFS_V4_1
...@@ -43,6 +44,7 @@ ...@@ -43,6 +44,7 @@
#include <net/udp.h> #include <net/udp.h>
#include <net/tcp.h> #include <net/tcp.h>
#include "sunrpc.h"
/* /*
* xprtsock tunables * xprtsock tunables
*/ */
...@@ -2098,6 +2100,134 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) ...@@ -2098,6 +2100,134 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
xprt->stat.bklog_u); xprt->stat.bklog_u);
} }
/*
* Allocate a bunch of pages for a scratch buffer for the rpc code. The reason
* we allocate pages instead doing a kmalloc like rpc_malloc is because we want
* to use the server side send routines.
*/
void *bc_malloc(struct rpc_task *task, size_t size)
{
struct page *page;
struct rpc_buffer *buf;
BUG_ON(size > PAGE_SIZE - sizeof(struct rpc_buffer));
page = alloc_page(GFP_KERNEL);
if (!page)
return NULL;
buf = page_address(page);
buf->len = PAGE_SIZE;
return buf->data;
}
/*
* Free the space allocated in the bc_alloc routine
*/
void bc_free(void *buffer)
{
struct rpc_buffer *buf;
if (!buffer)
return;
buf = container_of(buffer, struct rpc_buffer, data);
free_page((unsigned long)buf);
}
/*
* Use the svc_sock to send the callback. Must be called with svsk->sk_mutex
* held. Borrows heavily from svc_tcp_sendto and xs_tcp_send_request.
*/
static int bc_sendto(struct rpc_rqst *req)
{
int len;
struct xdr_buf *xbufp = &req->rq_snd_buf;
struct rpc_xprt *xprt = req->rq_xprt;
struct sock_xprt *transport =
container_of(xprt, struct sock_xprt, xprt);
struct socket *sock = transport->sock;
unsigned long headoff;
unsigned long tailoff;
/*
* Set up the rpc header and record marker stuff
*/
xs_encode_tcp_record_marker(xbufp);
tailoff = (unsigned long)xbufp->tail[0].iov_base & ~PAGE_MASK;
headoff = (unsigned long)xbufp->head[0].iov_base & ~PAGE_MASK;
len = svc_send_common(sock, xbufp,
virt_to_page(xbufp->head[0].iov_base), headoff,
xbufp->tail[0].iov_base, tailoff);
if (len != xbufp->len) {
printk(KERN_NOTICE "Error sending entire callback!\n");
len = -EAGAIN;
}
return len;
}
/*
* The send routine. Borrows from svc_send
*/
static int bc_send_request(struct rpc_task *task)
{
struct rpc_rqst *req = task->tk_rqstp;
struct svc_xprt *xprt;
struct svc_sock *svsk;
u32 len;
dprintk("sending request with xid: %08x\n", ntohl(req->rq_xid));
/*
* Get the server socket associated with this callback xprt
*/
xprt = req->rq_xprt->bc_xprt;
svsk = container_of(xprt, struct svc_sock, sk_xprt);
/*
* Grab the mutex to serialize data as the connection is shared
* with the fore channel
*/
if (!mutex_trylock(&xprt->xpt_mutex)) {
rpc_sleep_on(&xprt->xpt_bc_pending, task, NULL);
if (!mutex_trylock(&xprt->xpt_mutex))
return -EAGAIN;
rpc_wake_up_queued_task(&xprt->xpt_bc_pending, task);
}
if (test_bit(XPT_DEAD, &xprt->xpt_flags))
len = -ENOTCONN;
else
len = bc_sendto(req);
mutex_unlock(&xprt->xpt_mutex);
if (len > 0)
len = 0;
return len;
}
/*
* The close routine. Since this is client initiated, we do nothing
*/
static void bc_close(struct rpc_xprt *xprt)
{
return;
}
/*
* The xprt destroy routine. Again, because this connection is client
* initiated, we do nothing
*/
static void bc_destroy(struct rpc_xprt *xprt)
{
return;
}
static struct rpc_xprt_ops xs_udp_ops = { static struct rpc_xprt_ops xs_udp_ops = {
.set_buffer_size = xs_udp_set_buffer_size, .set_buffer_size = xs_udp_set_buffer_size,
.reserve_xprt = xprt_reserve_xprt_cong, .reserve_xprt = xprt_reserve_xprt_cong,
...@@ -2134,6 +2264,22 @@ static struct rpc_xprt_ops xs_tcp_ops = { ...@@ -2134,6 +2264,22 @@ static struct rpc_xprt_ops xs_tcp_ops = {
.print_stats = xs_tcp_print_stats, .print_stats = xs_tcp_print_stats,
}; };
/*
* The rpc_xprt_ops for the server backchannel
*/
static struct rpc_xprt_ops bc_tcp_ops = {
.reserve_xprt = xprt_reserve_xprt,
.release_xprt = xprt_release_xprt,
.buf_alloc = bc_malloc,
.buf_free = bc_free,
.send_request = bc_send_request,
.set_retrans_timeout = xprt_set_retrans_timeout_def,
.close = bc_close,
.destroy = bc_destroy,
.print_stats = xs_tcp_print_stats,
};
static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args, static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
unsigned int slot_table_size) unsigned int slot_table_size)
{ {
...@@ -2322,11 +2468,93 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args) ...@@ -2322,11 +2468,93 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
/**
* xs_setup_bc_tcp - Set up transport to use a TCP backchannel socket
* @args: rpc transport creation arguments
*
*/
static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
{
struct sockaddr *addr = args->dstaddr;
struct rpc_xprt *xprt;
struct sock_xprt *transport;
struct svc_sock *bc_sock;
if (!args->bc_xprt)
ERR_PTR(-EINVAL);
xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries);
if (IS_ERR(xprt))
return xprt;
transport = container_of(xprt, struct sock_xprt, xprt);
xprt->prot = IPPROTO_TCP;
xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32);
xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
xprt->timeout = &xs_tcp_default_timeout;
/* backchannel */
xprt_set_bound(xprt);
xprt->bind_timeout = 0;
xprt->connect_timeout = 0;
xprt->reestablish_timeout = 0;
xprt->idle_timeout = 0;
/*
* The backchannel uses the same socket connection as the
* forechannel
*/
xprt->bc_xprt = args->bc_xprt;
bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt);
bc_sock->sk_bc_xprt = xprt;
transport->sock = bc_sock->sk_sock;
transport->inet = bc_sock->sk_sk;
xprt->ops = &bc_tcp_ops;
switch (addr->sa_family) {
case AF_INET:
xs_format_peer_addresses(xprt, "tcp",
RPCBIND_NETID_TCP);
break;
case AF_INET6:
xs_format_peer_addresses(xprt, "tcp",
RPCBIND_NETID_TCP6);
break;
default:
kfree(xprt);
return ERR_PTR(-EAFNOSUPPORT);
}
if (xprt_bound(xprt))
dprintk("RPC: set up xprt to %s (port %s) via %s\n",
xprt->address_strings[RPC_DISPLAY_ADDR],
xprt->address_strings[RPC_DISPLAY_PORT],
xprt->address_strings[RPC_DISPLAY_PROTO]);
else
dprintk("RPC: set up xprt to %s (autobind) via %s\n",
xprt->address_strings[RPC_DISPLAY_ADDR],
xprt->address_strings[RPC_DISPLAY_PROTO]);
/*
* Since we don't want connections for the backchannel, we set
* the xprt status to connected
*/
xprt_set_connected(xprt);
if (try_module_get(THIS_MODULE))
return xprt;
kfree(xprt->slot);
kfree(xprt);
return ERR_PTR(-EINVAL);
}
static struct xprt_class xs_udp_transport = { static struct xprt_class xs_udp_transport = {
.list = LIST_HEAD_INIT(xs_udp_transport.list), .list = LIST_HEAD_INIT(xs_udp_transport.list),
.name = "udp", .name = "udp",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ident = IPPROTO_UDP, .ident = XPRT_TRANSPORT_UDP,
.setup = xs_setup_udp, .setup = xs_setup_udp,
}; };
...@@ -2334,10 +2562,18 @@ static struct xprt_class xs_tcp_transport = { ...@@ -2334,10 +2562,18 @@ static struct xprt_class xs_tcp_transport = {
.list = LIST_HEAD_INIT(xs_tcp_transport.list), .list = LIST_HEAD_INIT(xs_tcp_transport.list),
.name = "tcp", .name = "tcp",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ident = IPPROTO_TCP, .ident = XPRT_TRANSPORT_TCP,
.setup = xs_setup_tcp, .setup = xs_setup_tcp,
}; };
static struct xprt_class xs_bc_tcp_transport = {
.list = LIST_HEAD_INIT(xs_bc_tcp_transport.list),
.name = "tcp NFSv4.1 backchannel",
.owner = THIS_MODULE,
.ident = XPRT_TRANSPORT_BC_TCP,
.setup = xs_setup_bc_tcp,
};
/** /**
* init_socket_xprt - set up xprtsock's sysctls, register with RPC client * init_socket_xprt - set up xprtsock's sysctls, register with RPC client
* *
...@@ -2351,6 +2587,7 @@ int init_socket_xprt(void) ...@@ -2351,6 +2587,7 @@ int init_socket_xprt(void)
xprt_register_transport(&xs_udp_transport); xprt_register_transport(&xs_udp_transport);
xprt_register_transport(&xs_tcp_transport); xprt_register_transport(&xs_tcp_transport);
xprt_register_transport(&xs_bc_tcp_transport);
return 0; return 0;
} }
...@@ -2370,6 +2607,7 @@ void cleanup_socket_xprt(void) ...@@ -2370,6 +2607,7 @@ void cleanup_socket_xprt(void)
xprt_unregister_transport(&xs_udp_transport); xprt_unregister_transport(&xs_udp_transport);
xprt_unregister_transport(&xs_tcp_transport); xprt_unregister_transport(&xs_tcp_transport);
xprt_unregister_transport(&xs_bc_tcp_transport);
} }
static int param_set_uint_minmax(const char *val, struct kernel_param *kp, static int param_set_uint_minmax(const char *val, struct kernel_param *kp,
......
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