forked from Minki/linux
Merge branch 'for-3.7' of git://linux-nfs.org/~bfields/linux
Pull nfsd update from J Bruce Fields: "Another relatively quiet cycle. There was some progress on my remaining 4.1 todo's, but a couple of them were just of the form "check that we do X correctly", so didn't have much affect on the code. Other than that, a bunch of cleanup and some bugfixes (including an annoying NFSv4.0 state leak and a busy-loop in the server that could cause it to peg the CPU without making progress)." * 'for-3.7' of git://linux-nfs.org/~bfields/linux: (46 commits) UAPI: (Scripted) Disintegrate include/linux/sunrpc UAPI: (Scripted) Disintegrate include/linux/nfsd nfsd4: don't allow reclaims of expired clients nfsd4: remove redundant callback probe nfsd4: expire old client earlier nfsd4: separate session allocation and initialization nfsd4: clean up session allocation nfsd4: minor free_session cleanup nfsd4: new_conn_from_crses should only allocate nfsd4: separate connection allocation and initialization nfsd4: reject bad forechannel attrs earlier nfsd4: enforce per-client sessions/no-sessions distinction nfsd4: set cl_minorversion at create time nfsd4: don't pin clientids to pseudoflavors nfsd4: fix bind_conn_to_session xdr comment nfsd4: cast readlink() bug argument NFSD: pass null terminated buf to kstrtouint() nfsd: remove duplicate init in nfsd4_cb_recall nfsd4: eliminate redundant nfs4_free_stateid fs/nfsd/nfs4idmap.c: adjust inconsistent IS_ERR and PTR_ERR ...
This commit is contained in:
commit
bd81ccea85
41
Documentation/filesystems/nfs/nfsd-admin-interfaces.txt
Normal file
41
Documentation/filesystems/nfs/nfsd-admin-interfaces.txt
Normal file
@ -0,0 +1,41 @@
|
||||
Administrative interfaces for nfsd
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Note that normally these interfaces are used only by the utilities in
|
||||
nfs-utils.
|
||||
|
||||
nfsd is controlled mainly by pseudofiles under the "nfsd" filesystem,
|
||||
which is normally mounted at /proc/fs/nfsd/.
|
||||
|
||||
The server is always started by the first write of a nonzero value to
|
||||
nfsd/threads.
|
||||
|
||||
Before doing that, NFSD can be told which sockets to listen on by
|
||||
writing to nfsd/portlist; that write may be:
|
||||
|
||||
- an ascii-encoded file descriptor, which should refer to a
|
||||
bound (and listening, for tcp) socket, or
|
||||
- "transportname port", where transportname is currently either
|
||||
"udp", "tcp", or "rdma".
|
||||
|
||||
If nfsd is started without doing any of these, then it will create one
|
||||
udp and one tcp listener at port 2049 (see nfsd_init_socks).
|
||||
|
||||
On startup, nfsd and lockd grace periods start.
|
||||
|
||||
nfsd is shut down by a write of 0 to nfsd/threads. All locks and state
|
||||
are thrown away at that point.
|
||||
|
||||
Between startup and shutdown, the number of threads may be adjusted up
|
||||
or down by additional writes to nfsd/threads or by writes to
|
||||
nfsd/pool_threads.
|
||||
|
||||
For more detail about files under nfsd/ and what they control, see
|
||||
fs/nfsd/nfsctl.c; most of them have detailed comments.
|
||||
|
||||
Implementation notes
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Note that the rpc server requires the caller to serialize addition and
|
||||
removal of listening sockets, and startup and shutdown of the server.
|
||||
For nfsd this is done using nfsd_mutex.
|
@ -126,7 +126,7 @@ static void restart_grace(void)
|
||||
static int
|
||||
lockd(void *vrqstp)
|
||||
{
|
||||
int err = 0, preverr = 0;
|
||||
int err = 0;
|
||||
struct svc_rqst *rqstp = vrqstp;
|
||||
|
||||
/* try_to_freeze() is called from svc_recv() */
|
||||
@ -165,21 +165,8 @@ lockd(void *vrqstp)
|
||||
* recvfrom routine.
|
||||
*/
|
||||
err = svc_recv(rqstp, timeout);
|
||||
if (err == -EAGAIN || err == -EINTR) {
|
||||
preverr = err;
|
||||
if (err == -EAGAIN || err == -EINTR)
|
||||
continue;
|
||||
}
|
||||
if (err < 0) {
|
||||
if (err != preverr) {
|
||||
printk(KERN_WARNING "%s: unexpected error "
|
||||
"from svc_recv (%d)\n", __func__, err);
|
||||
preverr = err;
|
||||
}
|
||||
schedule_timeout_interruptible(HZ);
|
||||
continue;
|
||||
}
|
||||
preverr = err;
|
||||
|
||||
dprintk("lockd: request from %s\n",
|
||||
svc_print_addr(rqstp, buf, sizeof(buf)));
|
||||
|
||||
|
@ -1289,7 +1289,7 @@ EXPORT_SYMBOL(__break_lease);
|
||||
void lease_get_mtime(struct inode *inode, struct timespec *time)
|
||||
{
|
||||
struct file_lock *flock = inode->i_flock;
|
||||
if (flock && IS_LEASE(flock) && (flock->fl_type & F_WRLCK))
|
||||
if (flock && IS_LEASE(flock) && (flock->fl_type == F_WRLCK))
|
||||
*time = current_fs_time(inode->i_sb);
|
||||
else
|
||||
*time = inode->i_mtime;
|
||||
@ -2185,8 +2185,8 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
|
||||
} else {
|
||||
seq_printf(f, "%s ",
|
||||
(lease_breaking(fl))
|
||||
? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
|
||||
: (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
|
||||
? (fl->fl_type == F_UNLCK) ? "UNLCK" : "READ "
|
||||
: (fl->fl_type == F_WRLCK) ? "WRITE" : "READ ");
|
||||
}
|
||||
if (inode) {
|
||||
#ifdef WE_CAN_BREAK_LSLK_NOW
|
||||
|
@ -72,7 +72,7 @@ out_err:
|
||||
static int
|
||||
nfs4_callback_svc(void *vrqstp)
|
||||
{
|
||||
int err, preverr = 0;
|
||||
int err;
|
||||
struct svc_rqst *rqstp = vrqstp;
|
||||
|
||||
set_freezable();
|
||||
@ -82,20 +82,8 @@ nfs4_callback_svc(void *vrqstp)
|
||||
* Listen for a request on the socket
|
||||
*/
|
||||
err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
|
||||
if (err == -EAGAIN || err == -EINTR) {
|
||||
preverr = err;
|
||||
if (err == -EAGAIN || err == -EINTR)
|
||||
continue;
|
||||
}
|
||||
if (err < 0) {
|
||||
if (err != preverr) {
|
||||
printk(KERN_WARNING "NFS: %s: unexpected error "
|
||||
"from svc_recv (%d)\n", __func__, err);
|
||||
preverr = err;
|
||||
}
|
||||
schedule_timeout_uninterruptible(HZ);
|
||||
continue;
|
||||
}
|
||||
preverr = err;
|
||||
svc_process(rqstp);
|
||||
}
|
||||
return 0;
|
||||
|
@ -218,8 +218,7 @@ static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
|
||||
* There must be an encoding function for void results so svc_process
|
||||
* will work properly.
|
||||
*/
|
||||
int
|
||||
nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
|
||||
static int nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
|
||||
{
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
|
||||
/* Now create the file and set attributes */
|
||||
nfserr = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len,
|
||||
attr, newfhp,
|
||||
argp->createmode, argp->verf, NULL, NULL);
|
||||
argp->createmode, (u32 *)argp->verf, NULL, NULL);
|
||||
|
||||
RETURN_STATUS(nfserr);
|
||||
}
|
||||
|
@ -1028,7 +1028,6 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
|
||||
cb->cb_msg.rpc_cred = callback_cred;
|
||||
|
||||
cb->cb_ops = &nfsd4_cb_recall_ops;
|
||||
dp->dl_retries = 1;
|
||||
|
||||
INIT_LIST_HEAD(&cb->cb_per_client);
|
||||
cb->cb_done = true;
|
||||
|
@ -478,7 +478,7 @@ nfsd_idmap_init(struct net *net)
|
||||
goto destroy_idtoname_cache;
|
||||
nn->nametoid_cache = cache_create_net(&nametoid_cache_template, net);
|
||||
if (IS_ERR(nn->nametoid_cache)) {
|
||||
rv = PTR_ERR(nn->idtoname_cache);
|
||||
rv = PTR_ERR(nn->nametoid_cache);
|
||||
goto unregister_idtoname_cache;
|
||||
}
|
||||
rv = cache_register_net(nn->nametoid_cache, net);
|
||||
@ -598,7 +598,7 @@ numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namel
|
||||
/* Just to make sure it's null-terminated: */
|
||||
memcpy(buf, name, namelen);
|
||||
buf[namelen] = '\0';
|
||||
ret = kstrtouint(name, 10, id);
|
||||
ret = kstrtouint(buf, 10, id);
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
|
@ -370,7 +370,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
break;
|
||||
case NFS4_OPEN_CLAIM_PREVIOUS:
|
||||
open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
|
||||
status = nfs4_check_open_reclaim(&open->op_clientid);
|
||||
status = nfs4_check_open_reclaim(&open->op_clientid, cstate->minorversion);
|
||||
if (status)
|
||||
goto out;
|
||||
case NFS4_OPEN_CLAIM_FH:
|
||||
@ -1054,8 +1054,8 @@ struct nfsd4_operation {
|
||||
char *op_name;
|
||||
/* Try to get response size before operation */
|
||||
nfsd4op_rsize op_rsize_bop;
|
||||
stateid_setter op_get_currentstateid;
|
||||
stateid_getter op_set_currentstateid;
|
||||
stateid_getter op_get_currentstateid;
|
||||
stateid_setter op_set_currentstateid;
|
||||
};
|
||||
|
||||
static struct nfsd4_operation nfsd4_ops[];
|
||||
|
@ -758,7 +758,7 @@ static void nfsd4_put_drc_mem(int slotsize, int num)
|
||||
spin_unlock(&nfsd_drc_lock);
|
||||
}
|
||||
|
||||
static struct nfsd4_session *alloc_session(int slotsize, int numslots)
|
||||
static struct nfsd4_session *__alloc_session(int slotsize, int numslots)
|
||||
{
|
||||
struct nfsd4_session *new;
|
||||
int mem, i;
|
||||
@ -852,35 +852,28 @@ static int nfsd4_register_conn(struct nfsd4_conn *conn)
|
||||
return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
|
||||
}
|
||||
|
||||
static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir)
|
||||
static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses)
|
||||
{
|
||||
struct nfsd4_conn *conn;
|
||||
int ret;
|
||||
|
||||
conn = alloc_conn(rqstp, dir);
|
||||
if (!conn)
|
||||
return nfserr_jukebox;
|
||||
nfsd4_hash_conn(conn, ses);
|
||||
ret = nfsd4_register_conn(conn);
|
||||
if (ret)
|
||||
/* oops; xprt is already down: */
|
||||
nfsd4_conn_lost(&conn->cn_xpt_user);
|
||||
if (ses->se_client->cl_cb_state == NFSD4_CB_DOWN &&
|
||||
dir & NFS4_CDFC4_BACK) {
|
||||
if (conn->cn_flags & NFS4_CDFC4_BACK) {
|
||||
/* callback channel may be back up */
|
||||
nfsd4_probe_callback(ses->se_client);
|
||||
}
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses)
|
||||
static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses)
|
||||
{
|
||||
u32 dir = NFS4_CDFC4_FORE;
|
||||
|
||||
if (ses->se_flags & SESSION4_BACK_CHAN)
|
||||
if (cses->flags & SESSION4_BACK_CHAN)
|
||||
dir |= NFS4_CDFC4_BACK;
|
||||
|
||||
return nfsd4_new_conn(rqstp, ses, dir);
|
||||
return alloc_conn(rqstp, dir);
|
||||
}
|
||||
|
||||
/* must be called under client_lock */
|
||||
@ -903,20 +896,21 @@ static void nfsd4_del_conns(struct nfsd4_session *s)
|
||||
spin_unlock(&clp->cl_lock);
|
||||
}
|
||||
|
||||
static void __free_session(struct nfsd4_session *ses)
|
||||
{
|
||||
nfsd4_put_drc_mem(slot_bytes(&ses->se_fchannel), ses->se_fchannel.maxreqs);
|
||||
free_session_slots(ses);
|
||||
kfree(ses);
|
||||
}
|
||||
|
||||
static void free_session(struct kref *kref)
|
||||
{
|
||||
struct nfsd4_session *ses;
|
||||
int mem;
|
||||
|
||||
lockdep_assert_held(&client_lock);
|
||||
ses = container_of(kref, struct nfsd4_session, se_ref);
|
||||
nfsd4_del_conns(ses);
|
||||
spin_lock(&nfsd_drc_lock);
|
||||
mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel);
|
||||
nfsd_drc_mem_used -= mem;
|
||||
spin_unlock(&nfsd_drc_lock);
|
||||
free_session_slots(ses);
|
||||
kfree(ses);
|
||||
__free_session(ses);
|
||||
}
|
||||
|
||||
void nfsd4_put_session(struct nfsd4_session *ses)
|
||||
@ -926,14 +920,10 @@ void nfsd4_put_session(struct nfsd4_session *ses)
|
||||
spin_unlock(&client_lock);
|
||||
}
|
||||
|
||||
static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses)
|
||||
static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan)
|
||||
{
|
||||
struct nfsd4_session *new;
|
||||
struct nfsd4_channel_attrs *fchan = &cses->fore_channel;
|
||||
int numslots, slotsize;
|
||||
__be32 status;
|
||||
int idx;
|
||||
|
||||
/*
|
||||
* Note decreasing slot size below client's request may
|
||||
* make it difficult for client to function correctly, whereas
|
||||
@ -946,12 +936,18 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n
|
||||
if (numslots < 1)
|
||||
return NULL;
|
||||
|
||||
new = alloc_session(slotsize, numslots);
|
||||
new = __alloc_session(slotsize, numslots);
|
||||
if (!new) {
|
||||
nfsd4_put_drc_mem(slotsize, fchan->maxreqs);
|
||||
return NULL;
|
||||
}
|
||||
init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize);
|
||||
return new;
|
||||
}
|
||||
|
||||
static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses)
|
||||
{
|
||||
int idx;
|
||||
|
||||
new->se_client = clp;
|
||||
gen_sessionid(new);
|
||||
@ -970,14 +966,6 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n
|
||||
spin_unlock(&clp->cl_lock);
|
||||
spin_unlock(&client_lock);
|
||||
|
||||
status = nfsd4_new_conn_from_crses(rqstp, new);
|
||||
/* whoops: benny points out, status is ignored! (err, or bogus) */
|
||||
if (status) {
|
||||
spin_lock(&client_lock);
|
||||
free_session(&new->se_ref);
|
||||
spin_unlock(&client_lock);
|
||||
return NULL;
|
||||
}
|
||||
if (cses->flags & SESSION4_BACK_CHAN) {
|
||||
struct sockaddr *sa = svc_addr(rqstp);
|
||||
/*
|
||||
@ -990,7 +978,6 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n
|
||||
rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
|
||||
clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
|
||||
}
|
||||
nfsd4_probe_callback(clp);
|
||||
return new;
|
||||
}
|
||||
|
||||
@ -1131,7 +1118,7 @@ unhash_client_locked(struct nfs4_client *clp)
|
||||
}
|
||||
|
||||
static void
|
||||
expire_client(struct nfs4_client *clp)
|
||||
destroy_client(struct nfs4_client *clp)
|
||||
{
|
||||
struct nfs4_openowner *oo;
|
||||
struct nfs4_delegation *dp;
|
||||
@ -1165,6 +1152,12 @@ expire_client(struct nfs4_client *clp)
|
||||
spin_unlock(&client_lock);
|
||||
}
|
||||
|
||||
static void expire_client(struct nfs4_client *clp)
|
||||
{
|
||||
nfsd4_client_record_remove(clp);
|
||||
destroy_client(clp);
|
||||
}
|
||||
|
||||
static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
|
||||
{
|
||||
memcpy(target->cl_verifier.data, source->data,
|
||||
@ -1223,10 +1216,26 @@ static bool groups_equal(struct group_info *g1, struct group_info *g2)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* RFC 3530 language requires clid_inuse be returned when the
|
||||
* "principal" associated with a requests differs from that previously
|
||||
* used. We use uid, gid's, and gss principal string as our best
|
||||
* approximation. We also don't want to allow non-gss use of a client
|
||||
* established using gss: in theory cr_principal should catch that
|
||||
* change, but in practice cr_principal can be null even in the gss case
|
||||
* since gssd doesn't always pass down a principal string.
|
||||
*/
|
||||
static bool is_gss_cred(struct svc_cred *cr)
|
||||
{
|
||||
/* Is cr_flavor one of the gss "pseudoflavors"?: */
|
||||
return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR);
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
|
||||
{
|
||||
if ((cr1->cr_flavor != cr2->cr_flavor)
|
||||
if ((is_gss_cred(cr1) != is_gss_cred(cr2))
|
||||
|| (cr1->cr_uid != cr2->cr_uid)
|
||||
|| (cr1->cr_gid != cr2->cr_gid)
|
||||
|| !groups_equal(cr1->cr_group_info, cr2->cr_group_info))
|
||||
@ -1340,13 +1349,15 @@ move_to_confirmed(struct nfs4_client *clp)
|
||||
}
|
||||
|
||||
static struct nfs4_client *
|
||||
find_confirmed_client(clientid_t *clid)
|
||||
find_confirmed_client(clientid_t *clid, bool sessions)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
unsigned int idhashval = clientid_hashval(clid->cl_id);
|
||||
|
||||
list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
|
||||
if (same_clid(&clp->cl_clientid, clid)) {
|
||||
if ((bool)clp->cl_minorversion != sessions)
|
||||
return NULL;
|
||||
renew_client(clp);
|
||||
return clp;
|
||||
}
|
||||
@ -1355,14 +1366,17 @@ find_confirmed_client(clientid_t *clid)
|
||||
}
|
||||
|
||||
static struct nfs4_client *
|
||||
find_unconfirmed_client(clientid_t *clid)
|
||||
find_unconfirmed_client(clientid_t *clid, bool sessions)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
unsigned int idhashval = clientid_hashval(clid->cl_id);
|
||||
|
||||
list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
|
||||
if (same_clid(&clp->cl_clientid, clid))
|
||||
if (same_clid(&clp->cl_clientid, clid)) {
|
||||
if ((bool)clp->cl_minorversion != sessions)
|
||||
return NULL;
|
||||
return clp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -1651,6 +1665,7 @@ out_new:
|
||||
status = nfserr_jukebox;
|
||||
goto out;
|
||||
}
|
||||
new->cl_minorversion = 1;
|
||||
|
||||
gen_clid(new);
|
||||
add_to_unconfirmed(new, strhashval);
|
||||
@ -1743,67 +1758,71 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||
struct sockaddr *sa = svc_addr(rqstp);
|
||||
struct nfs4_client *conf, *unconf;
|
||||
struct nfsd4_session *new;
|
||||
struct nfsd4_conn *conn;
|
||||
struct nfsd4_clid_slot *cs_slot = NULL;
|
||||
bool confirm_me = false;
|
||||
__be32 status = 0;
|
||||
|
||||
if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
|
||||
return nfserr_inval;
|
||||
if (check_forechannel_attrs(cr_ses->fore_channel))
|
||||
return nfserr_toosmall;
|
||||
new = alloc_session(&cr_ses->fore_channel);
|
||||
if (!new)
|
||||
return nfserr_jukebox;
|
||||
status = nfserr_jukebox;
|
||||
conn = alloc_conn_from_crses(rqstp, cr_ses);
|
||||
if (!conn)
|
||||
goto out_free_session;
|
||||
|
||||
nfs4_lock_state();
|
||||
unconf = find_unconfirmed_client(&cr_ses->clientid);
|
||||
conf = find_confirmed_client(&cr_ses->clientid);
|
||||
unconf = find_unconfirmed_client(&cr_ses->clientid, true);
|
||||
conf = find_confirmed_client(&cr_ses->clientid, true);
|
||||
|
||||
if (conf) {
|
||||
cs_slot = &conf->cl_cs_slot;
|
||||
status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
|
||||
if (status == nfserr_replay_cache) {
|
||||
status = nfsd4_replay_create_session(cr_ses, cs_slot);
|
||||
goto out;
|
||||
goto out_free_conn;
|
||||
} else if (cr_ses->seqid != cs_slot->sl_seqid + 1) {
|
||||
status = nfserr_seq_misordered;
|
||||
goto out;
|
||||
goto out_free_conn;
|
||||
}
|
||||
} else if (unconf) {
|
||||
unsigned int hash;
|
||||
struct nfs4_client *old;
|
||||
if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
|
||||
!rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
|
||||
status = nfserr_clid_inuse;
|
||||
goto out;
|
||||
goto out_free_conn;
|
||||
}
|
||||
cs_slot = &unconf->cl_cs_slot;
|
||||
status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
|
||||
if (status) {
|
||||
/* an unconfirmed replay returns misordered */
|
||||
status = nfserr_seq_misordered;
|
||||
goto out;
|
||||
goto out_free_conn;
|
||||
}
|
||||
confirm_me = true;
|
||||
hash = clientstr_hashval(unconf->cl_recdir);
|
||||
old = find_confirmed_client_by_str(unconf->cl_recdir, hash);
|
||||
if (old)
|
||||
expire_client(old);
|
||||
move_to_confirmed(unconf);
|
||||
conf = unconf;
|
||||
} else {
|
||||
status = nfserr_stale_clientid;
|
||||
goto out;
|
||||
goto out_free_conn;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: we should probably set this at creation time, and check
|
||||
* for consistent minorversion use throughout:
|
||||
*/
|
||||
conf->cl_minorversion = 1;
|
||||
status = nfs_ok;
|
||||
/*
|
||||
* We do not support RDMA or persistent sessions
|
||||
*/
|
||||
cr_ses->flags &= ~SESSION4_PERSIST;
|
||||
cr_ses->flags &= ~SESSION4_RDMA;
|
||||
|
||||
status = nfserr_toosmall;
|
||||
if (check_forechannel_attrs(cr_ses->fore_channel))
|
||||
goto out;
|
||||
init_session(rqstp, new, conf, cr_ses);
|
||||
nfsd4_init_conn(rqstp, conn, new);
|
||||
|
||||
status = nfserr_jukebox;
|
||||
new = alloc_init_session(rqstp, conf, cr_ses);
|
||||
if (!new)
|
||||
goto out;
|
||||
status = nfs_ok;
|
||||
memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
|
||||
NFS4_MAX_SESSIONID_LEN);
|
||||
memcpy(&cr_ses->fore_channel, &new->se_fchannel,
|
||||
@ -1813,18 +1832,15 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||
|
||||
/* cache solo and embedded create sessions under the state lock */
|
||||
nfsd4_cache_create_session(cr_ses, cs_slot, status);
|
||||
if (confirm_me) {
|
||||
unsigned int hash = clientstr_hashval(unconf->cl_recdir);
|
||||
struct nfs4_client *old =
|
||||
find_confirmed_client_by_str(conf->cl_recdir, hash);
|
||||
if (old)
|
||||
expire_client(old);
|
||||
move_to_confirmed(conf);
|
||||
}
|
||||
out:
|
||||
nfs4_unlock_state();
|
||||
dprintk("%s returns %d\n", __func__, ntohl(status));
|
||||
return status;
|
||||
out_free_conn:
|
||||
free_conn(conn);
|
||||
out_free_session:
|
||||
__free_session(new);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static bool nfsd4_last_compound_op(struct svc_rqst *rqstp)
|
||||
@ -1854,6 +1870,7 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
|
||||
struct nfsd4_bind_conn_to_session *bcts)
|
||||
{
|
||||
__be32 status;
|
||||
struct nfsd4_conn *conn;
|
||||
|
||||
if (!nfsd4_last_compound_op(rqstp))
|
||||
return nfserr_not_only_op;
|
||||
@ -1870,9 +1887,13 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
|
||||
return nfserr_badsession;
|
||||
|
||||
status = nfsd4_map_bcts_dir(&bcts->dir);
|
||||
if (!status)
|
||||
nfsd4_new_conn(rqstp, cstate->session, bcts->dir);
|
||||
return status;
|
||||
if (status)
|
||||
return status;
|
||||
conn = alloc_conn(rqstp, bcts->dir);
|
||||
if (!conn)
|
||||
return nfserr_jukebox;
|
||||
nfsd4_init_conn(rqstp, conn, cstate->session);
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
|
||||
@ -2085,8 +2106,8 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
|
||||
__be32 status = 0;
|
||||
|
||||
nfs4_lock_state();
|
||||
unconf = find_unconfirmed_client(&dc->clientid);
|
||||
conf = find_confirmed_client(&dc->clientid);
|
||||
unconf = find_unconfirmed_client(&dc->clientid, true);
|
||||
conf = find_confirmed_client(&dc->clientid, true);
|
||||
|
||||
if (conf) {
|
||||
clp = conf;
|
||||
@ -2200,10 +2221,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
copy_clid(new, conf);
|
||||
else /* case 4 (new client) or cases 2, 3 (client reboot): */
|
||||
gen_clid(new);
|
||||
/*
|
||||
* XXX: we should probably set this at creation time, and check
|
||||
* for consistent minorversion use throughout:
|
||||
*/
|
||||
new->cl_minorversion = 0;
|
||||
gen_callback(new, setclid, rqstp);
|
||||
add_to_unconfirmed(new, strhashval);
|
||||
@ -2232,8 +2249,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
|
||||
return nfserr_stale_clientid;
|
||||
nfs4_lock_state();
|
||||
|
||||
conf = find_confirmed_client(clid);
|
||||
unconf = find_unconfirmed_client(clid);
|
||||
conf = find_confirmed_client(clid, false);
|
||||
unconf = find_unconfirmed_client(clid, false);
|
||||
/*
|
||||
* We try hard to give out unique clientid's, so if we get an
|
||||
* attempt to confirm the same clientid with a different cred,
|
||||
@ -2262,10 +2279,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
|
||||
unsigned int hash = clientstr_hashval(unconf->cl_recdir);
|
||||
|
||||
conf = find_confirmed_client_by_str(unconf->cl_recdir, hash);
|
||||
if (conf) {
|
||||
nfsd4_client_record_remove(conf);
|
||||
if (conf)
|
||||
expire_client(conf);
|
||||
}
|
||||
move_to_confirmed(unconf);
|
||||
nfsd4_probe_callback(unconf);
|
||||
}
|
||||
@ -2447,16 +2462,20 @@ same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,
|
||||
}
|
||||
|
||||
static struct nfs4_openowner *
|
||||
find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open)
|
||||
find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, bool sessions)
|
||||
{
|
||||
struct nfs4_stateowner *so;
|
||||
struct nfs4_openowner *oo;
|
||||
struct nfs4_client *clp;
|
||||
|
||||
list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {
|
||||
if (!so->so_is_open_owner)
|
||||
continue;
|
||||
if (same_owner_str(so, &open->op_owner, &open->op_clientid)) {
|
||||
oo = openowner(so);
|
||||
clp = oo->oo_owner.so_client;
|
||||
if ((bool)clp->cl_minorversion != sessions)
|
||||
return NULL;
|
||||
renew_client(oo->oo_owner.so_client);
|
||||
return oo;
|
||||
}
|
||||
@ -2600,10 +2619,10 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
|
||||
return nfserr_jukebox;
|
||||
|
||||
strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner);
|
||||
oo = find_openstateowner_str(strhashval, open);
|
||||
oo = find_openstateowner_str(strhashval, open, cstate->minorversion);
|
||||
open->op_openowner = oo;
|
||||
if (!oo) {
|
||||
clp = find_confirmed_client(clientid);
|
||||
clp = find_confirmed_client(clientid, cstate->minorversion);
|
||||
if (clp == NULL)
|
||||
return nfserr_expired;
|
||||
goto new_owner;
|
||||
@ -2705,11 +2724,6 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_st
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static void nfs4_free_stateid(struct nfs4_ol_stateid *s)
|
||||
{
|
||||
kmem_cache_free(stateid_slab, s);
|
||||
}
|
||||
|
||||
static inline int nfs4_access_to_access(u32 nfs4_access)
|
||||
{
|
||||
int flags = 0;
|
||||
@ -3087,7 +3101,7 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
|
||||
if (open->op_file)
|
||||
nfsd4_free_file(open->op_file);
|
||||
if (open->op_stp)
|
||||
nfs4_free_stateid(open->op_stp);
|
||||
free_generic_stateid(open->op_stp);
|
||||
}
|
||||
|
||||
__be32
|
||||
@ -3104,7 +3118,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
status = nfserr_stale_clientid;
|
||||
if (STALE_CLIENTID(clid, nn))
|
||||
goto out;
|
||||
clp = find_confirmed_client(clid);
|
||||
clp = find_confirmed_client(clid, cstate->minorversion);
|
||||
status = nfserr_expired;
|
||||
if (clp == NULL) {
|
||||
/* We assume the client took too long to RENEW. */
|
||||
@ -3180,7 +3194,6 @@ nfs4_laundromat(void)
|
||||
clp = list_entry(pos, struct nfs4_client, cl_lru);
|
||||
dprintk("NFSD: purging unused client (clientid %08x)\n",
|
||||
clp->cl_clientid.cl_id);
|
||||
nfsd4_client_record_remove(clp);
|
||||
expire_client(clp);
|
||||
}
|
||||
spin_lock(&recall_lock);
|
||||
@ -3372,7 +3385,7 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s)
|
||||
static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s, bool sessions)
|
||||
{
|
||||
struct nfs4_client *cl;
|
||||
struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
|
||||
@ -3381,7 +3394,7 @@ static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, s
|
||||
return nfserr_bad_stateid;
|
||||
if (STALE_STATEID(stateid, nn))
|
||||
return nfserr_stale_stateid;
|
||||
cl = find_confirmed_client(&stateid->si_opaque.so_clid);
|
||||
cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions);
|
||||
if (!cl)
|
||||
return nfserr_expired;
|
||||
*s = find_stateid_by_type(cl, stateid, typemask);
|
||||
@ -3414,7 +3427,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
|
||||
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
|
||||
return check_special_stateids(net, current_fh, stateid, flags);
|
||||
|
||||
status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s);
|
||||
status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s, cstate->minorversion);
|
||||
if (status)
|
||||
return status;
|
||||
status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
|
||||
@ -3564,7 +3577,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
|
||||
seqid, STATEID_VAL(stateid));
|
||||
|
||||
*stpp = NULL;
|
||||
status = nfsd4_lookup_stateid(stateid, typemask, &s);
|
||||
status = nfsd4_lookup_stateid(stateid, typemask, &s, cstate->minorversion);
|
||||
if (status)
|
||||
return status;
|
||||
*stpp = openlockstateid(s);
|
||||
@ -3765,6 +3778,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
|
||||
|
||||
nfsd4_close_open_stateid(stp);
|
||||
release_last_closed_stateid(oo);
|
||||
oo->oo_last_closed_stid = stp;
|
||||
|
||||
if (list_empty(&oo->oo_owner.so_stateids)) {
|
||||
@ -3801,7 +3815,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
inode = cstate->current_fh.fh_dentry->d_inode;
|
||||
|
||||
nfs4_lock_state();
|
||||
status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s);
|
||||
status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, cstate->minorversion);
|
||||
if (status)
|
||||
goto out;
|
||||
dp = delegstateid(s);
|
||||
@ -4045,8 +4059,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct nfs4_lockowner *lock_sop = NULL;
|
||||
struct nfs4_ol_stateid *lock_stp;
|
||||
struct file *filp = NULL;
|
||||
struct file_lock file_lock;
|
||||
struct file_lock conflock;
|
||||
struct file_lock *file_lock = NULL;
|
||||
struct file_lock *conflock = NULL;
|
||||
__be32 status = 0;
|
||||
bool new_state = false;
|
||||
int lkflg;
|
||||
@ -4116,21 +4130,28 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
if (!locks_in_grace(SVC_NET(rqstp)) && lock->lk_reclaim)
|
||||
goto out;
|
||||
|
||||
locks_init_lock(&file_lock);
|
||||
file_lock = locks_alloc_lock();
|
||||
if (!file_lock) {
|
||||
dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
|
||||
status = nfserr_jukebox;
|
||||
goto out;
|
||||
}
|
||||
|
||||
locks_init_lock(file_lock);
|
||||
switch (lock->lk_type) {
|
||||
case NFS4_READ_LT:
|
||||
case NFS4_READW_LT:
|
||||
filp = find_readable_file(lock_stp->st_file);
|
||||
if (filp)
|
||||
get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
|
||||
file_lock.fl_type = F_RDLCK;
|
||||
file_lock->fl_type = F_RDLCK;
|
||||
break;
|
||||
case NFS4_WRITE_LT:
|
||||
case NFS4_WRITEW_LT:
|
||||
filp = find_writeable_file(lock_stp->st_file);
|
||||
if (filp)
|
||||
get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
|
||||
file_lock.fl_type = F_WRLCK;
|
||||
file_lock->fl_type = F_WRLCK;
|
||||
break;
|
||||
default:
|
||||
status = nfserr_inval;
|
||||
@ -4140,22 +4161,23 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
status = nfserr_openmode;
|
||||
goto out;
|
||||
}
|
||||
file_lock.fl_owner = (fl_owner_t)lock_sop;
|
||||
file_lock.fl_pid = current->tgid;
|
||||
file_lock.fl_file = filp;
|
||||
file_lock.fl_flags = FL_POSIX;
|
||||
file_lock.fl_lmops = &nfsd_posix_mng_ops;
|
||||
file_lock->fl_owner = (fl_owner_t)lock_sop;
|
||||
file_lock->fl_pid = current->tgid;
|
||||
file_lock->fl_file = filp;
|
||||
file_lock->fl_flags = FL_POSIX;
|
||||
file_lock->fl_lmops = &nfsd_posix_mng_ops;
|
||||
file_lock->fl_start = lock->lk_offset;
|
||||
file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
|
||||
nfs4_transform_lock_offset(file_lock);
|
||||
|
||||
file_lock.fl_start = lock->lk_offset;
|
||||
file_lock.fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
|
||||
nfs4_transform_lock_offset(&file_lock);
|
||||
conflock = locks_alloc_lock();
|
||||
if (!conflock) {
|
||||
dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
|
||||
status = nfserr_jukebox;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to lock the file in the VFS.
|
||||
* Note: locks.c uses the BKL to protect the inode's lock list.
|
||||
*/
|
||||
|
||||
err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock);
|
||||
err = vfs_lock_file(filp, F_SETLK, file_lock, conflock);
|
||||
switch (-err) {
|
||||
case 0: /* success! */
|
||||
update_stateid(&lock_stp->st_stid.sc_stateid);
|
||||
@ -4166,7 +4188,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
case (EAGAIN): /* conflock holds conflicting lock */
|
||||
status = nfserr_denied;
|
||||
dprintk("NFSD: nfsd4_lock: conflicting lock found!\n");
|
||||
nfs4_set_lock_denied(&conflock, &lock->lk_denied);
|
||||
nfs4_set_lock_denied(conflock, &lock->lk_denied);
|
||||
break;
|
||||
case (EDEADLK):
|
||||
status = nfserr_deadlock;
|
||||
@ -4181,6 +4203,10 @@ out:
|
||||
release_lockowner(lock_sop);
|
||||
if (!cstate->replay_owner)
|
||||
nfs4_unlock_state();
|
||||
if (file_lock)
|
||||
locks_free_lock(file_lock);
|
||||
if (conflock)
|
||||
locks_free_lock(conflock);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -4209,7 +4235,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct nfsd4_lockt *lockt)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct file_lock file_lock;
|
||||
struct file_lock *file_lock = NULL;
|
||||
struct nfs4_lockowner *lo;
|
||||
__be32 status;
|
||||
struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
|
||||
@ -4230,15 +4256,21 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
goto out;
|
||||
|
||||
inode = cstate->current_fh.fh_dentry->d_inode;
|
||||
locks_init_lock(&file_lock);
|
||||
file_lock = locks_alloc_lock();
|
||||
if (!file_lock) {
|
||||
dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
|
||||
status = nfserr_jukebox;
|
||||
goto out;
|
||||
}
|
||||
locks_init_lock(file_lock);
|
||||
switch (lockt->lt_type) {
|
||||
case NFS4_READ_LT:
|
||||
case NFS4_READW_LT:
|
||||
file_lock.fl_type = F_RDLCK;
|
||||
file_lock->fl_type = F_RDLCK;
|
||||
break;
|
||||
case NFS4_WRITE_LT:
|
||||
case NFS4_WRITEW_LT:
|
||||
file_lock.fl_type = F_WRLCK;
|
||||
file_lock->fl_type = F_WRLCK;
|
||||
break;
|
||||
default:
|
||||
dprintk("NFSD: nfs4_lockt: bad lock type!\n");
|
||||
@ -4248,25 +4280,27 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
|
||||
lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner);
|
||||
if (lo)
|
||||
file_lock.fl_owner = (fl_owner_t)lo;
|
||||
file_lock.fl_pid = current->tgid;
|
||||
file_lock.fl_flags = FL_POSIX;
|
||||
file_lock->fl_owner = (fl_owner_t)lo;
|
||||
file_lock->fl_pid = current->tgid;
|
||||
file_lock->fl_flags = FL_POSIX;
|
||||
|
||||
file_lock.fl_start = lockt->lt_offset;
|
||||
file_lock.fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
|
||||
file_lock->fl_start = lockt->lt_offset;
|
||||
file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
|
||||
|
||||
nfs4_transform_lock_offset(&file_lock);
|
||||
nfs4_transform_lock_offset(file_lock);
|
||||
|
||||
status = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock);
|
||||
status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
if (file_lock.fl_type != F_UNLCK) {
|
||||
if (file_lock->fl_type != F_UNLCK) {
|
||||
status = nfserr_denied;
|
||||
nfs4_set_lock_denied(&file_lock, &lockt->lt_denied);
|
||||
nfs4_set_lock_denied(file_lock, &lockt->lt_denied);
|
||||
}
|
||||
out:
|
||||
nfs4_unlock_state();
|
||||
if (file_lock)
|
||||
locks_free_lock(file_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -4276,7 +4310,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
{
|
||||
struct nfs4_ol_stateid *stp;
|
||||
struct file *filp = NULL;
|
||||
struct file_lock file_lock;
|
||||
struct file_lock *file_lock = NULL;
|
||||
__be32 status;
|
||||
int err;
|
||||
|
||||
@ -4298,23 +4332,29 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
status = nfserr_lock_range;
|
||||
goto out;
|
||||
}
|
||||
BUG_ON(!filp);
|
||||
locks_init_lock(&file_lock);
|
||||
file_lock.fl_type = F_UNLCK;
|
||||
file_lock.fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
|
||||
file_lock.fl_pid = current->tgid;
|
||||
file_lock.fl_file = filp;
|
||||
file_lock.fl_flags = FL_POSIX;
|
||||
file_lock.fl_lmops = &nfsd_posix_mng_ops;
|
||||
file_lock.fl_start = locku->lu_offset;
|
||||
file_lock = locks_alloc_lock();
|
||||
if (!file_lock) {
|
||||
dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
|
||||
status = nfserr_jukebox;
|
||||
goto out;
|
||||
}
|
||||
locks_init_lock(file_lock);
|
||||
file_lock->fl_type = F_UNLCK;
|
||||
file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
|
||||
file_lock->fl_pid = current->tgid;
|
||||
file_lock->fl_file = filp;
|
||||
file_lock->fl_flags = FL_POSIX;
|
||||
file_lock->fl_lmops = &nfsd_posix_mng_ops;
|
||||
file_lock->fl_start = locku->lu_offset;
|
||||
|
||||
file_lock.fl_end = last_byte_offset(locku->lu_offset, locku->lu_length);
|
||||
nfs4_transform_lock_offset(&file_lock);
|
||||
file_lock->fl_end = last_byte_offset(locku->lu_offset,
|
||||
locku->lu_length);
|
||||
nfs4_transform_lock_offset(file_lock);
|
||||
|
||||
/*
|
||||
* Try to unlock the file in the VFS.
|
||||
*/
|
||||
err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL);
|
||||
err = vfs_lock_file(filp, F_SETLK, file_lock, NULL);
|
||||
if (err) {
|
||||
dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
|
||||
goto out_nfserr;
|
||||
@ -4328,6 +4368,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
out:
|
||||
if (!cstate->replay_owner)
|
||||
nfs4_unlock_state();
|
||||
if (file_lock)
|
||||
locks_free_lock(file_lock);
|
||||
return status;
|
||||
|
||||
out_nfserr:
|
||||
@ -4501,12 +4543,12 @@ nfsd4_find_reclaim_client(struct nfs4_client *clp)
|
||||
* Called from OPEN. Look for clientid in reclaim list.
|
||||
*/
|
||||
__be32
|
||||
nfs4_check_open_reclaim(clientid_t *clid)
|
||||
nfs4_check_open_reclaim(clientid_t *clid, bool sessions)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
|
||||
/* find clientid in conf_id_hashtbl */
|
||||
clp = find_confirmed_client(clid);
|
||||
clp = find_confirmed_client(clid, sessions);
|
||||
if (clp == NULL)
|
||||
return nfserr_reclaim_bad;
|
||||
|
||||
@ -4522,7 +4564,6 @@ void nfsd_forget_clients(u64 num)
|
||||
|
||||
nfs4_lock_state();
|
||||
list_for_each_entry_safe(clp, next, &client_lru, cl_lru) {
|
||||
nfsd4_client_record_remove(clp);
|
||||
expire_client(clp);
|
||||
if (++count == num)
|
||||
break;
|
||||
@ -4582,7 +4623,7 @@ void nfsd_forget_openowners(u64 num)
|
||||
printk(KERN_INFO "NFSD: Forgot %d open owners", count);
|
||||
}
|
||||
|
||||
int nfsd_process_n_delegations(u64 num, struct list_head *list)
|
||||
static int nfsd_process_n_delegations(u64 num, struct list_head *list)
|
||||
{
|
||||
int i, count = 0;
|
||||
struct nfs4_file *fp, *fnext;
|
||||
@ -4747,11 +4788,11 @@ __nfs4_state_shutdown(void)
|
||||
for (i = 0; i < CLIENT_HASH_SIZE; i++) {
|
||||
while (!list_empty(&conf_id_hashtbl[i])) {
|
||||
clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
|
||||
expire_client(clp);
|
||||
destroy_client(clp);
|
||||
}
|
||||
while (!list_empty(&unconf_str_hashtbl[i])) {
|
||||
clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash);
|
||||
expire_client(clp);
|
||||
destroy_client(clp);
|
||||
}
|
||||
}
|
||||
INIT_LIST_HEAD(&reaplist);
|
||||
|
@ -2659,7 +2659,7 @@ static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp,
|
||||
RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 8);
|
||||
WRITEMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);
|
||||
WRITE32(bcts->dir);
|
||||
/* XXX: ? */
|
||||
/* Sorry, we do not yet support RDMA over 4.1: */
|
||||
WRITE32(0);
|
||||
ADJUST_ARGS();
|
||||
}
|
||||
|
@ -406,7 +406,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
|
||||
return rv;
|
||||
if (newthreads < 0)
|
||||
return -EINVAL;
|
||||
rv = nfsd_svc(NFS_PORT, newthreads);
|
||||
rv = nfsd_svc(newthreads);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
} else
|
||||
@ -682,25 +682,6 @@ static ssize_t __write_ports_addfd(char *buf)
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* A '-' followed by the 'name' of a socket means we close the socket.
|
||||
*/
|
||||
static ssize_t __write_ports_delfd(char *buf)
|
||||
{
|
||||
char *toclose;
|
||||
int len = 0;
|
||||
|
||||
toclose = kstrdup(buf + 1, GFP_KERNEL);
|
||||
if (toclose == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (nfsd_serv != NULL)
|
||||
len = svc_sock_names(nfsd_serv, buf,
|
||||
SIMPLE_TRANSACTION_LIMIT, toclose);
|
||||
kfree(toclose);
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* A transport listener is added by writing it's transport name and
|
||||
* a port number.
|
||||
@ -712,7 +693,7 @@ static ssize_t __write_ports_addxprt(char *buf)
|
||||
int port, err;
|
||||
struct net *net = &init_net;
|
||||
|
||||
if (sscanf(buf, "%15s %4u", transport, &port) != 2)
|
||||
if (sscanf(buf, "%15s %5u", transport, &port) != 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (port < 1 || port > USHRT_MAX)
|
||||
@ -746,31 +727,6 @@ out_err:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* A transport listener is removed by writing a "-", it's transport
|
||||
* name, and it's port number.
|
||||
*/
|
||||
static ssize_t __write_ports_delxprt(char *buf)
|
||||
{
|
||||
struct svc_xprt *xprt;
|
||||
char transport[16];
|
||||
int port;
|
||||
|
||||
if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
xprt = svc_find_xprt(nfsd_serv, transport, &init_net, AF_UNSPEC, port);
|
||||
if (xprt == NULL)
|
||||
return -ENOTCONN;
|
||||
|
||||
svc_close_xprt(xprt);
|
||||
svc_xprt_put(xprt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t __write_ports(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
@ -779,15 +735,9 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
|
||||
if (isdigit(buf[0]))
|
||||
return __write_ports_addfd(buf);
|
||||
|
||||
if (buf[0] == '-' && isdigit(buf[1]))
|
||||
return __write_ports_delfd(buf);
|
||||
|
||||
if (isalpha(buf[0]))
|
||||
return __write_ports_addxprt(buf);
|
||||
|
||||
if (buf[0] == '-' && isalpha(buf[1]))
|
||||
return __write_ports_delxprt(buf);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -825,21 +775,6 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
|
||||
* OR
|
||||
*
|
||||
* Input:
|
||||
* buf: C string containing a "-" followed
|
||||
* by an integer value representing a
|
||||
* previously passed in socket file
|
||||
* descriptor
|
||||
* size: non-zero length of C string in @buf
|
||||
* Output:
|
||||
* On success: NFS service no longer listens on that socket;
|
||||
* passed-in buffer filled with a '\n'-terminated C
|
||||
* string containing a unique name of the listener;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is a negative errno value
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* Input:
|
||||
* buf: C string containing a transport
|
||||
* name and an unsigned integer value
|
||||
* representing the port to listen on,
|
||||
@ -848,19 +783,6 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
|
||||
* Output:
|
||||
* On success: returns zero; NFS service is started
|
||||
* On error: return code is a negative errno value
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* Input:
|
||||
* buf: C string containing a "-" followed
|
||||
* by a transport name and an unsigned
|
||||
* integer value representing the port
|
||||
* to listen on, separated by whitespace
|
||||
* size: non-zero length of C string in @buf
|
||||
* Output:
|
||||
* On success: returns zero; NFS service no longer listens
|
||||
* on that transport
|
||||
* On error: return code is a negative errno value
|
||||
*/
|
||||
static ssize_t write_ports(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
@ -1008,8 +930,6 @@ static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
|
||||
return nfsd4_write_time(file, buf, size, &nfsd4_grace);
|
||||
}
|
||||
|
||||
extern char *nfs4_recoverydir(void);
|
||||
|
||||
static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
char *mesg = buf;
|
||||
|
@ -65,7 +65,7 @@ extern const struct seq_operations nfs_exports_op;
|
||||
/*
|
||||
* Function prototypes.
|
||||
*/
|
||||
int nfsd_svc(unsigned short port, int nrservs);
|
||||
int nfsd_svc(int nrservs);
|
||||
int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);
|
||||
|
||||
int nfsd_nrthreads(void);
|
||||
@ -124,6 +124,7 @@ int nfs4_state_start(void);
|
||||
void nfs4_state_shutdown(void);
|
||||
void nfs4_reset_lease(time_t leasetime);
|
||||
int nfs4_reset_recoverydir(char *recdir);
|
||||
char * nfs4_recoverydir(void);
|
||||
#else
|
||||
static inline void nfs4_state_init(void) { }
|
||||
static inline int nfsd4_init_slabs(void) { return 0; }
|
||||
@ -132,6 +133,7 @@ static inline int nfs4_state_start(void) { return 0; }
|
||||
static inline void nfs4_state_shutdown(void) { }
|
||||
static inline void nfs4_reset_lease(time_t leasetime) { }
|
||||
static inline int nfs4_reset_recoverydir(char *recdir) { return 0; }
|
||||
static inline char * nfs4_recoverydir(void) {return NULL; }
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -183,18 +183,18 @@ int nfsd_nrthreads(void)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int nfsd_init_socks(int port)
|
||||
static int nfsd_init_socks(void)
|
||||
{
|
||||
int error;
|
||||
if (!list_empty(&nfsd_serv->sv_permsocks))
|
||||
return 0;
|
||||
|
||||
error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, port,
|
||||
error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, NFS_PORT,
|
||||
SVC_SOCK_DEFAULTS);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, port,
|
||||
error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, NFS_PORT,
|
||||
SVC_SOCK_DEFAULTS);
|
||||
if (error < 0)
|
||||
return error;
|
||||
@ -204,7 +204,7 @@ static int nfsd_init_socks(int port)
|
||||
|
||||
static bool nfsd_up = false;
|
||||
|
||||
static int nfsd_startup(unsigned short port, int nrservs)
|
||||
static int nfsd_startup(int nrservs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -218,7 +218,7 @@ static int nfsd_startup(unsigned short port, int nrservs)
|
||||
ret = nfsd_racache_init(2*nrservs);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nfsd_init_socks(port);
|
||||
ret = nfsd_init_socks();
|
||||
if (ret)
|
||||
goto out_racache;
|
||||
ret = lockd_up(&init_net);
|
||||
@ -436,7 +436,7 @@ int nfsd_set_nrthreads(int n, int *nthreads)
|
||||
* this is the first time nrservs is nonzero.
|
||||
*/
|
||||
int
|
||||
nfsd_svc(unsigned short port, int nrservs)
|
||||
nfsd_svc(int nrservs)
|
||||
{
|
||||
int error;
|
||||
bool nfsd_up_before;
|
||||
@ -458,7 +458,7 @@ nfsd_svc(unsigned short port, int nrservs)
|
||||
|
||||
nfsd_up_before = nfsd_up;
|
||||
|
||||
error = nfsd_startup(port, nrservs);
|
||||
error = nfsd_startup(nrservs);
|
||||
if (error)
|
||||
goto out_destroy;
|
||||
error = svc_set_num_threads(nfsd_serv, NULL, nrservs);
|
||||
@ -487,7 +487,7 @@ static int
|
||||
nfsd(void *vrqstp)
|
||||
{
|
||||
struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
|
||||
int err, preverr = 0;
|
||||
int err;
|
||||
|
||||
/* Lock module and set up kernel thread */
|
||||
mutex_lock(&nfsd_mutex);
|
||||
@ -534,16 +534,6 @@ nfsd(void *vrqstp)
|
||||
;
|
||||
if (err == -EINTR)
|
||||
break;
|
||||
else if (err < 0) {
|
||||
if (err != preverr) {
|
||||
printk(KERN_WARNING "%s: unexpected error "
|
||||
"from svc_recv (%d)\n", __func__, -err);
|
||||
preverr = err;
|
||||
}
|
||||
schedule_timeout_uninterruptible(HZ);
|
||||
continue;
|
||||
}
|
||||
|
||||
validate_process_creds();
|
||||
svc_process(rqstp);
|
||||
validate_process_creds();
|
||||
|
@ -373,11 +373,7 @@ static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so)
|
||||
return container_of(so, struct nfs4_lockowner, lo_owner);
|
||||
}
|
||||
|
||||
/*
|
||||
* nfs4_file: a file opened by some number of (open) nfs4_stateowners.
|
||||
* o fi_perfile list is used to search for conflicting
|
||||
* share_acces, share_deny on the file.
|
||||
*/
|
||||
/* nfs4_file: a file opened by some number of (open) nfs4_stateowners. */
|
||||
struct nfs4_file {
|
||||
atomic_t fi_ref;
|
||||
struct list_head fi_hash; /* hash by "struct inode *" */
|
||||
@ -459,7 +455,7 @@ extern void nfs4_unlock_state(void);
|
||||
extern int nfs4_in_grace(void);
|
||||
extern void nfs4_release_reclaim(void);
|
||||
extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct nfs4_client *crp);
|
||||
extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
|
||||
extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions);
|
||||
extern void nfs4_free_openowner(struct nfs4_openowner *);
|
||||
extern void nfs4_free_lockowner(struct nfs4_lockowner *);
|
||||
extern int set_callback_cred(void);
|
||||
|
@ -1581,7 +1581,7 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
|
||||
*/
|
||||
|
||||
oldfs = get_fs(); set_fs(KERNEL_DS);
|
||||
host_err = inode->i_op->readlink(path.dentry, buf, *lenp);
|
||||
host_err = inode->i_op->readlink(path.dentry, (char __user *)buf, *lenp);
|
||||
set_fs(oldfs);
|
||||
|
||||
if (host_err < 0)
|
||||
|
@ -1,5 +0,0 @@
|
||||
header-y += cld.h
|
||||
header-y += debug.h
|
||||
header-y += export.h
|
||||
header-y += nfsfh.h
|
||||
header-y += stats.h
|
@ -5,44 +5,15 @@
|
||||
*
|
||||
* Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef LINUX_NFSD_DEBUG_H
|
||||
#define LINUX_NFSD_DEBUG_H
|
||||
|
||||
#include <linux/sunrpc/debug.h>
|
||||
#include <uapi/linux/nfsd/debug.h>
|
||||
|
||||
/*
|
||||
* Enable debugging for nfsd.
|
||||
* Requires RPC_DEBUG.
|
||||
*/
|
||||
#ifdef RPC_DEBUG
|
||||
# define NFSD_DEBUG 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* knfsd debug flags
|
||||
*/
|
||||
#define NFSDDBG_SOCK 0x0001
|
||||
#define NFSDDBG_FH 0x0002
|
||||
#define NFSDDBG_EXPORT 0x0004
|
||||
#define NFSDDBG_SVC 0x0008
|
||||
#define NFSDDBG_PROC 0x0010
|
||||
#define NFSDDBG_FILEOP 0x0020
|
||||
#define NFSDDBG_AUTH 0x0040
|
||||
#define NFSDDBG_REPCACHE 0x0080
|
||||
#define NFSDDBG_XDR 0x0100
|
||||
#define NFSDDBG_LOCKD 0x0200
|
||||
#define NFSDDBG_ALL 0x7FFF
|
||||
#define NFSDDBG_NOCHANGE 0xFFFF
|
||||
|
||||
|
||||
#ifdef __KERNEL__
|
||||
# undef ifdebug
|
||||
# ifdef NFSD_DEBUG
|
||||
# define ifdebug(flag) if (nfsd_debug & NFSDDBG_##flag)
|
||||
# else
|
||||
# define ifdebug(flag) if (0)
|
||||
# endif
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* LINUX_NFSD_DEBUG_H */
|
||||
|
@ -6,58 +6,11 @@
|
||||
*
|
||||
* Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef NFSD_EXPORT_H
|
||||
#define NFSD_EXPORT_H
|
||||
|
||||
# include <linux/types.h>
|
||||
#ifdef __KERNEL__
|
||||
# include <linux/nfsd/nfsfh.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Important limits for the exports stuff.
|
||||
*/
|
||||
#define NFSCLNT_IDMAX 1024
|
||||
#define NFSCLNT_ADDRMAX 16
|
||||
#define NFSCLNT_KEYMAX 32
|
||||
|
||||
/*
|
||||
* Export flags.
|
||||
*/
|
||||
#define NFSEXP_READONLY 0x0001
|
||||
#define NFSEXP_INSECURE_PORT 0x0002
|
||||
#define NFSEXP_ROOTSQUASH 0x0004
|
||||
#define NFSEXP_ALLSQUASH 0x0008
|
||||
#define NFSEXP_ASYNC 0x0010
|
||||
#define NFSEXP_GATHERED_WRITES 0x0020
|
||||
/* 40 80 100 currently unused */
|
||||
#define NFSEXP_NOHIDE 0x0200
|
||||
#define NFSEXP_NOSUBTREECHECK 0x0400
|
||||
#define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */
|
||||
#define NFSEXP_MSNFS 0x1000 /* do silly things that MS clients expect; no longer supported */
|
||||
#define NFSEXP_FSID 0x2000
|
||||
#define NFSEXP_CROSSMOUNT 0x4000
|
||||
#define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */
|
||||
/*
|
||||
* The NFSEXP_V4ROOT flag causes the kernel to give access only to NFSv4
|
||||
* clients, and only to the single directory that is the root of the
|
||||
* export; further lookup and readdir operations are treated as if every
|
||||
* subdirectory was a mountpoint, and ignored if they are not themselves
|
||||
* exported. This is used by nfsd and mountd to construct the NFSv4
|
||||
* pseudofilesystem, which provides access only to paths leading to each
|
||||
* exported filesystem.
|
||||
*/
|
||||
#define NFSEXP_V4ROOT 0x10000
|
||||
/* All flags that we claim to support. (Note we don't support NOACL.) */
|
||||
#define NFSEXP_ALLFLAGS 0x17E3F
|
||||
|
||||
/* The flags that may vary depending on security flavor: */
|
||||
#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
|
||||
| NFSEXP_ALLSQUASH \
|
||||
| NFSEXP_INSECURE_PORT)
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <uapi/linux/nfsd/export.h>
|
||||
|
||||
/*
|
||||
* FS Locations
|
||||
@ -154,7 +107,4 @@ static inline void exp_get(struct svc_export *exp)
|
||||
}
|
||||
struct svc_export * rqst_exp_find(struct svc_rqst *, int, u32 *);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* NFSD_EXPORT_H */
|
||||
|
||||
|
@ -10,117 +10,11 @@
|
||||
*
|
||||
* Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NFSD_FH_H
|
||||
#define _LINUX_NFSD_FH_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/nfs.h>
|
||||
#include <linux/nfs2.h>
|
||||
#include <linux/nfs3.h>
|
||||
#include <linux/nfs4.h>
|
||||
#ifdef __KERNEL__
|
||||
# include <linux/sunrpc/svc.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is the old "dentry style" Linux NFSv2 file handle.
|
||||
*
|
||||
* The xino and xdev fields are currently used to transport the
|
||||
* ino/dev of the exported inode.
|
||||
*/
|
||||
struct nfs_fhbase_old {
|
||||
__u32 fb_dcookie; /* dentry cookie - always 0xfeebbaca */
|
||||
__u32 fb_ino; /* our inode number */
|
||||
__u32 fb_dirino; /* dir inode number, 0 for directories */
|
||||
__u32 fb_dev; /* our device */
|
||||
__u32 fb_xdev;
|
||||
__u32 fb_xino;
|
||||
__u32 fb_generation;
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the new flexible, extensible style NFSv2/v3 file handle.
|
||||
* by Neil Brown <neilb@cse.unsw.edu.au> - March 2000
|
||||
*
|
||||
* The file handle starts with a sequence of four-byte words.
|
||||
* The first word contains a version number (1) and three descriptor bytes
|
||||
* that tell how the remaining 3 variable length fields should be handled.
|
||||
* These three bytes are auth_type, fsid_type and fileid_type.
|
||||
*
|
||||
* All four-byte values are in host-byte-order.
|
||||
*
|
||||
* The auth_type field specifies how the filehandle can be authenticated
|
||||
* This might allow a file to be confirmed to be in a writable part of a
|
||||
* filetree without checking the path from it up to the root.
|
||||
* Current values:
|
||||
* 0 - No authentication. fb_auth is 0 bytes long
|
||||
* Possible future values:
|
||||
* 1 - 4 bytes taken from MD5 hash of the remainer of the file handle
|
||||
* prefixed by a secret and with the important export flags.
|
||||
*
|
||||
* The fsid_type identifies how the filesystem (or export point) is
|
||||
* encoded.
|
||||
* Current values:
|
||||
* 0 - 4 byte device id (ms-2-bytes major, ls-2-bytes minor), 4byte inode number
|
||||
* NOTE: we cannot use the kdev_t device id value, because kdev_t.h
|
||||
* says we mustn't. We must break it up and reassemble.
|
||||
* 1 - 4 byte user specified identifier
|
||||
* 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED
|
||||
* 3 - 4 byte device id, encoded for user-space, 4 byte inode number
|
||||
* 4 - 4 byte inode number and 4 byte uuid
|
||||
* 5 - 8 byte uuid
|
||||
* 6 - 16 byte uuid
|
||||
* 7 - 8 byte inode number and 16 byte uuid
|
||||
*
|
||||
* The fileid_type identified how the file within the filesystem is encoded.
|
||||
* This is (will be) passed to, and set by, the underlying filesystem if it supports
|
||||
* filehandle operations. The filesystem must not use the value '0' or '0xff' and may
|
||||
* only use the values 1 and 2 as defined below:
|
||||
* Current values:
|
||||
* 0 - The root, or export point, of the filesystem. fb_fileid is 0 bytes.
|
||||
* 1 - 32bit inode number, 32 bit generation number.
|
||||
* 2 - 32bit inode number, 32 bit generation number, 32 bit parent directory inode number.
|
||||
*
|
||||
*/
|
||||
struct nfs_fhbase_new {
|
||||
__u8 fb_version; /* == 1, even => nfs_fhbase_old */
|
||||
__u8 fb_auth_type;
|
||||
__u8 fb_fsid_type;
|
||||
__u8 fb_fileid_type;
|
||||
__u32 fb_auth[1];
|
||||
/* __u32 fb_fsid[0]; floating */
|
||||
/* __u32 fb_fileid[0]; floating */
|
||||
};
|
||||
|
||||
struct knfsd_fh {
|
||||
unsigned int fh_size; /* significant for NFSv3.
|
||||
* Points to the current size while building
|
||||
* a new file handle
|
||||
*/
|
||||
union {
|
||||
struct nfs_fhbase_old fh_old;
|
||||
__u32 fh_pad[NFS4_FHSIZE/4];
|
||||
struct nfs_fhbase_new fh_new;
|
||||
} fh_base;
|
||||
};
|
||||
|
||||
#define ofh_dcookie fh_base.fh_old.fb_dcookie
|
||||
#define ofh_ino fh_base.fh_old.fb_ino
|
||||
#define ofh_dirino fh_base.fh_old.fb_dirino
|
||||
#define ofh_dev fh_base.fh_old.fb_dev
|
||||
#define ofh_xdev fh_base.fh_old.fb_xdev
|
||||
#define ofh_xino fh_base.fh_old.fb_xino
|
||||
#define ofh_generation fh_base.fh_old.fb_generation
|
||||
|
||||
#define fh_version fh_base.fh_new.fb_version
|
||||
#define fh_fsid_type fh_base.fh_new.fb_fsid_type
|
||||
#define fh_auth_type fh_base.fh_new.fb_auth_type
|
||||
#define fh_fileid_type fh_base.fh_new.fb_fileid_type
|
||||
#define fh_auth fh_base.fh_new.fb_auth
|
||||
#define fh_fsid fh_base.fh_new.fb_auth
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <uapi/linux/nfsd/nfsfh.h>
|
||||
|
||||
static inline __u32 ino_t_to_u32(ino_t ino)
|
||||
{
|
||||
@ -166,7 +60,4 @@ typedef struct svc_fh {
|
||||
|
||||
} svc_fh;
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
|
||||
#endif /* _LINUX_NFSD_FH_H */
|
||||
|
@ -5,16 +5,11 @@
|
||||
*
|
||||
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef LINUX_NFSD_STATS_H
|
||||
#define LINUX_NFSD_STATS_H
|
||||
|
||||
#include <linux/nfs4.h>
|
||||
#include <uapi/linux/nfsd/stats.h>
|
||||
|
||||
/* thread usage wraps very million seconds (approx one fortnight) */
|
||||
#define NFSD_USAGE_WRAP (HZ*1000000)
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
struct nfsd_stats {
|
||||
unsigned int rchits; /* repcache hits */
|
||||
@ -47,5 +42,4 @@ extern struct svc_stat nfsd_svcstats;
|
||||
void nfsd_stat_init(void);
|
||||
void nfsd_stat_shutdown(void);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* LINUX_NFSD_STATS_H */
|
||||
|
@ -1 +0,0 @@
|
||||
header-y += debug.h
|
@ -5,28 +5,11 @@
|
||||
*
|
||||
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SUNRPC_DEBUG_H_
|
||||
#define _LINUX_SUNRPC_DEBUG_H_
|
||||
|
||||
/*
|
||||
* RPC debug facilities
|
||||
*/
|
||||
#define RPCDBG_XPRT 0x0001
|
||||
#define RPCDBG_CALL 0x0002
|
||||
#define RPCDBG_DEBUG 0x0004
|
||||
#define RPCDBG_NFS 0x0008
|
||||
#define RPCDBG_AUTH 0x0010
|
||||
#define RPCDBG_BIND 0x0020
|
||||
#define RPCDBG_SCHED 0x0040
|
||||
#define RPCDBG_TRANS 0x0080
|
||||
#define RPCDBG_SVCXPRT 0x0100
|
||||
#define RPCDBG_SVCDSP 0x0200
|
||||
#define RPCDBG_MISC 0x0400
|
||||
#define RPCDBG_CACHE 0x0800
|
||||
#define RPCDBG_ALL 0x7fff
|
||||
#include <uapi/linux/sunrpc/debug.h>
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/*
|
||||
* Enable RPC debugging/profiling.
|
||||
@ -87,24 +70,4 @@ void rpc_register_sysctl(void);
|
||||
void rpc_unregister_sysctl(void);
|
||||
#endif
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
/*
|
||||
* Declarations for the sysctl debug interface, which allows to read or
|
||||
* change the debug flags for rpc, nfs, nfsd, and lockd. Since the sunrpc
|
||||
* module currently registers its sysctl table dynamically, the sysctl path
|
||||
* for module FOO is <CTL_SUNRPC, CTL_FOODEBUG>.
|
||||
*/
|
||||
|
||||
enum {
|
||||
CTL_RPCDEBUG = 1,
|
||||
CTL_NFSDEBUG,
|
||||
CTL_NFSDDEBUG,
|
||||
CTL_NLMDEBUG,
|
||||
CTL_SLOTTABLE_UDP,
|
||||
CTL_SLOTTABLE_TCP,
|
||||
CTL_MIN_RESVPORT,
|
||||
CTL_MAX_RESVPORT,
|
||||
};
|
||||
|
||||
#endif /* _LINUX_SUNRPC_DEBUG_H_ */
|
||||
|
@ -114,7 +114,6 @@ void svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *,
|
||||
int svc_create_xprt(struct svc_serv *, const char *, struct net *,
|
||||
const int, const unsigned short, int);
|
||||
void svc_xprt_enqueue(struct svc_xprt *xprt);
|
||||
void svc_xprt_received(struct svc_xprt *);
|
||||
void svc_xprt_put(struct svc_xprt *xprt);
|
||||
void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt);
|
||||
void svc_close_xprt(struct svc_xprt *xprt);
|
||||
@ -124,6 +123,7 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
|
||||
struct net *net, const sa_family_t af,
|
||||
const unsigned short port);
|
||||
int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen);
|
||||
void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *xprt);
|
||||
|
||||
static inline void svc_xprt_get(struct svc_xprt *xprt)
|
||||
{
|
||||
@ -166,8 +166,7 @@ static inline size_t svc_addr_len(const struct sockaddr *sa)
|
||||
case AF_INET6:
|
||||
return sizeof(struct sockaddr_in6);
|
||||
}
|
||||
|
||||
return 0;
|
||||
BUG();
|
||||
}
|
||||
|
||||
static inline unsigned short svc_xprt_local_port(const struct svc_xprt *xprt)
|
||||
|
@ -39,9 +39,6 @@ int svc_recv(struct svc_rqst *, long);
|
||||
int svc_send(struct svc_rqst *);
|
||||
void svc_drop(struct svc_rqst *);
|
||||
void svc_sock_update_bufs(struct svc_serv *serv);
|
||||
int svc_sock_names(struct svc_serv *serv, char *buf,
|
||||
const size_t buflen,
|
||||
const char *toclose);
|
||||
int svc_addsock(struct svc_serv *serv, const int fd,
|
||||
char *name_return, const size_t len);
|
||||
void svc_init_xprt_sock(void);
|
||||
|
@ -1 +1,6 @@
|
||||
# UAPI Header export list
|
||||
header-y += cld.h
|
||||
header-y += debug.h
|
||||
header-y += export.h
|
||||
header-y += nfsfh.h
|
||||
header-y += stats.h
|
||||
|
40
include/uapi/linux/nfsd/debug.h
Normal file
40
include/uapi/linux/nfsd/debug.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* linux/include/linux/nfsd/debug.h
|
||||
*
|
||||
* Debugging-related stuff for nfsd
|
||||
*
|
||||
* Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef _UAPILINUX_NFSD_DEBUG_H
|
||||
#define _UAPILINUX_NFSD_DEBUG_H
|
||||
|
||||
#include <linux/sunrpc/debug.h>
|
||||
|
||||
/*
|
||||
* Enable debugging for nfsd.
|
||||
* Requires RPC_DEBUG.
|
||||
*/
|
||||
#ifdef RPC_DEBUG
|
||||
# define NFSD_DEBUG 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* knfsd debug flags
|
||||
*/
|
||||
#define NFSDDBG_SOCK 0x0001
|
||||
#define NFSDDBG_FH 0x0002
|
||||
#define NFSDDBG_EXPORT 0x0004
|
||||
#define NFSDDBG_SVC 0x0008
|
||||
#define NFSDDBG_PROC 0x0010
|
||||
#define NFSDDBG_FILEOP 0x0020
|
||||
#define NFSDDBG_AUTH 0x0040
|
||||
#define NFSDDBG_REPCACHE 0x0080
|
||||
#define NFSDDBG_XDR 0x0100
|
||||
#define NFSDDBG_LOCKD 0x0200
|
||||
#define NFSDDBG_ALL 0x7FFF
|
||||
#define NFSDDBG_NOCHANGE 0xFFFF
|
||||
|
||||
|
||||
|
||||
#endif /* _UAPILINUX_NFSD_DEBUG_H */
|
58
include/uapi/linux/nfsd/export.h
Normal file
58
include/uapi/linux/nfsd/export.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* include/linux/nfsd/export.h
|
||||
*
|
||||
* Public declarations for NFS exports. The definitions for the
|
||||
* syscall interface are in nfsctl.h
|
||||
*
|
||||
* Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef _UAPINFSD_EXPORT_H
|
||||
#define _UAPINFSD_EXPORT_H
|
||||
|
||||
# include <linux/types.h>
|
||||
|
||||
/*
|
||||
* Important limits for the exports stuff.
|
||||
*/
|
||||
#define NFSCLNT_IDMAX 1024
|
||||
#define NFSCLNT_ADDRMAX 16
|
||||
#define NFSCLNT_KEYMAX 32
|
||||
|
||||
/*
|
||||
* Export flags.
|
||||
*/
|
||||
#define NFSEXP_READONLY 0x0001
|
||||
#define NFSEXP_INSECURE_PORT 0x0002
|
||||
#define NFSEXP_ROOTSQUASH 0x0004
|
||||
#define NFSEXP_ALLSQUASH 0x0008
|
||||
#define NFSEXP_ASYNC 0x0010
|
||||
#define NFSEXP_GATHERED_WRITES 0x0020
|
||||
/* 40 80 100 currently unused */
|
||||
#define NFSEXP_NOHIDE 0x0200
|
||||
#define NFSEXP_NOSUBTREECHECK 0x0400
|
||||
#define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */
|
||||
#define NFSEXP_MSNFS 0x1000 /* do silly things that MS clients expect; no longer supported */
|
||||
#define NFSEXP_FSID 0x2000
|
||||
#define NFSEXP_CROSSMOUNT 0x4000
|
||||
#define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */
|
||||
/*
|
||||
* The NFSEXP_V4ROOT flag causes the kernel to give access only to NFSv4
|
||||
* clients, and only to the single directory that is the root of the
|
||||
* export; further lookup and readdir operations are treated as if every
|
||||
* subdirectory was a mountpoint, and ignored if they are not themselves
|
||||
* exported. This is used by nfsd and mountd to construct the NFSv4
|
||||
* pseudofilesystem, which provides access only to paths leading to each
|
||||
* exported filesystem.
|
||||
*/
|
||||
#define NFSEXP_V4ROOT 0x10000
|
||||
/* All flags that we claim to support. (Note we don't support NOACL.) */
|
||||
#define NFSEXP_ALLFLAGS 0x17E3F
|
||||
|
||||
/* The flags that may vary depending on security flavor: */
|
||||
#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
|
||||
| NFSEXP_ALLSQUASH \
|
||||
| NFSEXP_INSECURE_PORT)
|
||||
|
||||
|
||||
#endif /* _UAPINFSD_EXPORT_H */
|
122
include/uapi/linux/nfsd/nfsfh.h
Normal file
122
include/uapi/linux/nfsd/nfsfh.h
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* include/linux/nfsd/nfsfh.h
|
||||
*
|
||||
* This file describes the layout of the file handles as passed
|
||||
* over the wire.
|
||||
*
|
||||
* Earlier versions of knfsd used to sign file handles using keyed MD5
|
||||
* or SHA. I've removed this code, because it doesn't give you more
|
||||
* security than blocking external access to port 2049 on your firewall.
|
||||
*
|
||||
* Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef _UAPI_LINUX_NFSD_FH_H
|
||||
#define _UAPI_LINUX_NFSD_FH_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/nfs.h>
|
||||
#include <linux/nfs2.h>
|
||||
#include <linux/nfs3.h>
|
||||
#include <linux/nfs4.h>
|
||||
|
||||
/*
|
||||
* This is the old "dentry style" Linux NFSv2 file handle.
|
||||
*
|
||||
* The xino and xdev fields are currently used to transport the
|
||||
* ino/dev of the exported inode.
|
||||
*/
|
||||
struct nfs_fhbase_old {
|
||||
__u32 fb_dcookie; /* dentry cookie - always 0xfeebbaca */
|
||||
__u32 fb_ino; /* our inode number */
|
||||
__u32 fb_dirino; /* dir inode number, 0 for directories */
|
||||
__u32 fb_dev; /* our device */
|
||||
__u32 fb_xdev;
|
||||
__u32 fb_xino;
|
||||
__u32 fb_generation;
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the new flexible, extensible style NFSv2/v3 file handle.
|
||||
* by Neil Brown <neilb@cse.unsw.edu.au> - March 2000
|
||||
*
|
||||
* The file handle starts with a sequence of four-byte words.
|
||||
* The first word contains a version number (1) and three descriptor bytes
|
||||
* that tell how the remaining 3 variable length fields should be handled.
|
||||
* These three bytes are auth_type, fsid_type and fileid_type.
|
||||
*
|
||||
* All four-byte values are in host-byte-order.
|
||||
*
|
||||
* The auth_type field specifies how the filehandle can be authenticated
|
||||
* This might allow a file to be confirmed to be in a writable part of a
|
||||
* filetree without checking the path from it up to the root.
|
||||
* Current values:
|
||||
* 0 - No authentication. fb_auth is 0 bytes long
|
||||
* Possible future values:
|
||||
* 1 - 4 bytes taken from MD5 hash of the remainer of the file handle
|
||||
* prefixed by a secret and with the important export flags.
|
||||
*
|
||||
* The fsid_type identifies how the filesystem (or export point) is
|
||||
* encoded.
|
||||
* Current values:
|
||||
* 0 - 4 byte device id (ms-2-bytes major, ls-2-bytes minor), 4byte inode number
|
||||
* NOTE: we cannot use the kdev_t device id value, because kdev_t.h
|
||||
* says we mustn't. We must break it up and reassemble.
|
||||
* 1 - 4 byte user specified identifier
|
||||
* 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED
|
||||
* 3 - 4 byte device id, encoded for user-space, 4 byte inode number
|
||||
* 4 - 4 byte inode number and 4 byte uuid
|
||||
* 5 - 8 byte uuid
|
||||
* 6 - 16 byte uuid
|
||||
* 7 - 8 byte inode number and 16 byte uuid
|
||||
*
|
||||
* The fileid_type identified how the file within the filesystem is encoded.
|
||||
* This is (will be) passed to, and set by, the underlying filesystem if it supports
|
||||
* filehandle operations. The filesystem must not use the value '0' or '0xff' and may
|
||||
* only use the values 1 and 2 as defined below:
|
||||
* Current values:
|
||||
* 0 - The root, or export point, of the filesystem. fb_fileid is 0 bytes.
|
||||
* 1 - 32bit inode number, 32 bit generation number.
|
||||
* 2 - 32bit inode number, 32 bit generation number, 32 bit parent directory inode number.
|
||||
*
|
||||
*/
|
||||
struct nfs_fhbase_new {
|
||||
__u8 fb_version; /* == 1, even => nfs_fhbase_old */
|
||||
__u8 fb_auth_type;
|
||||
__u8 fb_fsid_type;
|
||||
__u8 fb_fileid_type;
|
||||
__u32 fb_auth[1];
|
||||
/* __u32 fb_fsid[0]; floating */
|
||||
/* __u32 fb_fileid[0]; floating */
|
||||
};
|
||||
|
||||
struct knfsd_fh {
|
||||
unsigned int fh_size; /* significant for NFSv3.
|
||||
* Points to the current size while building
|
||||
* a new file handle
|
||||
*/
|
||||
union {
|
||||
struct nfs_fhbase_old fh_old;
|
||||
__u32 fh_pad[NFS4_FHSIZE/4];
|
||||
struct nfs_fhbase_new fh_new;
|
||||
} fh_base;
|
||||
};
|
||||
|
||||
#define ofh_dcookie fh_base.fh_old.fb_dcookie
|
||||
#define ofh_ino fh_base.fh_old.fb_ino
|
||||
#define ofh_dirino fh_base.fh_old.fb_dirino
|
||||
#define ofh_dev fh_base.fh_old.fb_dev
|
||||
#define ofh_xdev fh_base.fh_old.fb_xdev
|
||||
#define ofh_xino fh_base.fh_old.fb_xino
|
||||
#define ofh_generation fh_base.fh_old.fb_generation
|
||||
|
||||
#define fh_version fh_base.fh_new.fb_version
|
||||
#define fh_fsid_type fh_base.fh_new.fb_fsid_type
|
||||
#define fh_auth_type fh_base.fh_new.fb_auth_type
|
||||
#define fh_fileid_type fh_base.fh_new.fb_fileid_type
|
||||
#define fh_auth fh_base.fh_new.fb_auth
|
||||
#define fh_fsid fh_base.fh_new.fb_auth
|
||||
|
||||
|
||||
|
||||
#endif /* _UAPI_LINUX_NFSD_FH_H */
|
17
include/uapi/linux/nfsd/stats.h
Normal file
17
include/uapi/linux/nfsd/stats.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* linux/include/linux/nfsd/stats.h
|
||||
*
|
||||
* Statistics for NFS server.
|
||||
*
|
||||
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef _UAPILINUX_NFSD_STATS_H
|
||||
#define _UAPILINUX_NFSD_STATS_H
|
||||
|
||||
#include <linux/nfs4.h>
|
||||
|
||||
/* thread usage wraps very million seconds (approx one fortnight) */
|
||||
#define NFSD_USAGE_WRAP (HZ*1000000)
|
||||
|
||||
#endif /* _UAPILINUX_NFSD_STATS_H */
|
@ -1 +1,2 @@
|
||||
# UAPI Header export list
|
||||
header-y += debug.h
|
||||
|
48
include/uapi/linux/sunrpc/debug.h
Normal file
48
include/uapi/linux/sunrpc/debug.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* linux/include/linux/sunrpc/debug.h
|
||||
*
|
||||
* Debugging support for sunrpc module
|
||||
*
|
||||
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#ifndef _UAPI_LINUX_SUNRPC_DEBUG_H_
|
||||
#define _UAPI_LINUX_SUNRPC_DEBUG_H_
|
||||
|
||||
/*
|
||||
* RPC debug facilities
|
||||
*/
|
||||
#define RPCDBG_XPRT 0x0001
|
||||
#define RPCDBG_CALL 0x0002
|
||||
#define RPCDBG_DEBUG 0x0004
|
||||
#define RPCDBG_NFS 0x0008
|
||||
#define RPCDBG_AUTH 0x0010
|
||||
#define RPCDBG_BIND 0x0020
|
||||
#define RPCDBG_SCHED 0x0040
|
||||
#define RPCDBG_TRANS 0x0080
|
||||
#define RPCDBG_SVCXPRT 0x0100
|
||||
#define RPCDBG_SVCDSP 0x0200
|
||||
#define RPCDBG_MISC 0x0400
|
||||
#define RPCDBG_CACHE 0x0800
|
||||
#define RPCDBG_ALL 0x7fff
|
||||
|
||||
|
||||
/*
|
||||
* Declarations for the sysctl debug interface, which allows to read or
|
||||
* change the debug flags for rpc, nfs, nfsd, and lockd. Since the sunrpc
|
||||
* module currently registers its sysctl table dynamically, the sysctl path
|
||||
* for module FOO is <CTL_SUNRPC, CTL_FOODEBUG>.
|
||||
*/
|
||||
|
||||
enum {
|
||||
CTL_RPCDEBUG = 1,
|
||||
CTL_NFSDEBUG,
|
||||
CTL_NFSDDEBUG,
|
||||
CTL_NLMDEBUG,
|
||||
CTL_SLOTTABLE_UDP,
|
||||
CTL_SLOTTABLE_TCP,
|
||||
CTL_MIN_RESVPORT,
|
||||
CTL_MAX_RESVPORT,
|
||||
};
|
||||
|
||||
#endif /* _UAPI_LINUX_SUNRPC_DEBUG_H_ */
|
@ -208,6 +208,35 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
|
||||
return xcl->xcl_ops->xpo_create(serv, net, sap, len, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* svc_xprt_received conditionally queues the transport for processing
|
||||
* by another thread. The caller must hold the XPT_BUSY bit and must
|
||||
* not thereafter touch transport data.
|
||||
*
|
||||
* Note: XPT_DATA only gets cleared when a read-attempt finds no (or
|
||||
* insufficient) data.
|
||||
*/
|
||||
static void svc_xprt_received(struct svc_xprt *xprt)
|
||||
{
|
||||
BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags));
|
||||
/* As soon as we clear busy, the xprt could be closed and
|
||||
* 'put', so we need a reference to call svc_xprt_enqueue with:
|
||||
*/
|
||||
svc_xprt_get(xprt);
|
||||
clear_bit(XPT_BUSY, &xprt->xpt_flags);
|
||||
svc_xprt_enqueue(xprt);
|
||||
svc_xprt_put(xprt);
|
||||
}
|
||||
|
||||
void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new)
|
||||
{
|
||||
clear_bit(XPT_TEMP, &new->xpt_flags);
|
||||
spin_lock_bh(&serv->sv_lock);
|
||||
list_add(&new->xpt_list, &serv->sv_permsocks);
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
svc_xprt_received(new);
|
||||
}
|
||||
|
||||
int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
|
||||
struct net *net, const int family,
|
||||
const unsigned short port, int flags)
|
||||
@ -232,13 +261,8 @@ int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
|
||||
module_put(xcl->xcl_owner);
|
||||
return PTR_ERR(newxprt);
|
||||
}
|
||||
|
||||
clear_bit(XPT_TEMP, &newxprt->xpt_flags);
|
||||
spin_lock_bh(&serv->sv_lock);
|
||||
list_add(&newxprt->xpt_list, &serv->sv_permsocks);
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
svc_add_new_perm_xprt(serv, newxprt);
|
||||
newport = svc_xprt_local_port(newxprt);
|
||||
clear_bit(XPT_BUSY, &newxprt->xpt_flags);
|
||||
return newport;
|
||||
}
|
||||
err:
|
||||
@ -394,27 +418,6 @@ static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool)
|
||||
return xprt;
|
||||
}
|
||||
|
||||
/*
|
||||
* svc_xprt_received conditionally queues the transport for processing
|
||||
* by another thread. The caller must hold the XPT_BUSY bit and must
|
||||
* not thereafter touch transport data.
|
||||
*
|
||||
* Note: XPT_DATA only gets cleared when a read-attempt finds no (or
|
||||
* insufficient) data.
|
||||
*/
|
||||
void svc_xprt_received(struct svc_xprt *xprt)
|
||||
{
|
||||
BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags));
|
||||
/* As soon as we clear busy, the xprt could be closed and
|
||||
* 'put', so we need a reference to call svc_xprt_enqueue with:
|
||||
*/
|
||||
svc_xprt_get(xprt);
|
||||
clear_bit(XPT_BUSY, &xprt->xpt_flags);
|
||||
svc_xprt_enqueue(xprt);
|
||||
svc_xprt_put(xprt);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(svc_xprt_received);
|
||||
|
||||
/**
|
||||
* svc_reserve - change the space reserved for the reply to a request.
|
||||
* @rqstp: The request in question
|
||||
@ -565,33 +568,12 @@ static void svc_check_conn_limits(struct svc_serv *serv)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive the next request on any transport. This code is carefully
|
||||
* organised not to touch any cachelines in the shared svc_serv
|
||||
* structure, only cachelines in the local svc_pool.
|
||||
*/
|
||||
int svc_recv(struct svc_rqst *rqstp, long timeout)
|
||||
int svc_alloc_arg(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct svc_xprt *xprt = NULL;
|
||||
struct svc_serv *serv = rqstp->rq_server;
|
||||
struct svc_pool *pool = rqstp->rq_pool;
|
||||
int len, i;
|
||||
int pages;
|
||||
struct xdr_buf *arg;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
long time_left;
|
||||
|
||||
dprintk("svc: server %p waiting for data (to = %ld)\n",
|
||||
rqstp, timeout);
|
||||
|
||||
if (rqstp->rq_xprt)
|
||||
printk(KERN_ERR
|
||||
"svc_recv: service %p, transport not NULL!\n",
|
||||
rqstp);
|
||||
if (waitqueue_active(&rqstp->rq_wait))
|
||||
printk(KERN_ERR
|
||||
"svc_recv: service %p, wait queue active!\n",
|
||||
rqstp);
|
||||
struct svc_serv *serv = rqstp->rq_server;
|
||||
struct xdr_buf *arg;
|
||||
int pages;
|
||||
int i;
|
||||
|
||||
/* now allocate needed pages. If we get a failure, sleep briefly */
|
||||
pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
|
||||
@ -621,11 +603,15 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
|
||||
arg->page_len = (pages-2)*PAGE_SIZE;
|
||||
arg->len = (pages-1)*PAGE_SIZE;
|
||||
arg->tail[0].iov_len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
try_to_freeze();
|
||||
cond_resched();
|
||||
if (signalled() || kthread_should_stop())
|
||||
return -EINTR;
|
||||
struct svc_xprt *svc_get_next_xprt(struct svc_rqst *rqstp, long timeout)
|
||||
{
|
||||
struct svc_xprt *xprt;
|
||||
struct svc_pool *pool = rqstp->rq_pool;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
long time_left;
|
||||
|
||||
/* Normally we will wait up to 5 seconds for any required
|
||||
* cache information to be provided.
|
||||
@ -663,7 +649,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
|
||||
if (kthread_should_stop()) {
|
||||
set_current_state(TASK_RUNNING);
|
||||
spin_unlock_bh(&pool->sp_lock);
|
||||
return -EINTR;
|
||||
return ERR_PTR(-EINTR);
|
||||
}
|
||||
|
||||
add_wait_queue(&rqstp->rq_wait, &wait);
|
||||
@ -684,48 +670,58 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
|
||||
spin_unlock_bh(&pool->sp_lock);
|
||||
dprintk("svc: server %p, no data yet\n", rqstp);
|
||||
if (signalled() || kthread_should_stop())
|
||||
return -EINTR;
|
||||
return ERR_PTR(-EINTR);
|
||||
else
|
||||
return -EAGAIN;
|
||||
return ERR_PTR(-EAGAIN);
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&pool->sp_lock);
|
||||
return xprt;
|
||||
}
|
||||
|
||||
void svc_add_new_temp_xprt(struct svc_serv *serv, struct svc_xprt *newxpt)
|
||||
{
|
||||
spin_lock_bh(&serv->sv_lock);
|
||||
set_bit(XPT_TEMP, &newxpt->xpt_flags);
|
||||
list_add(&newxpt->xpt_list, &serv->sv_tempsocks);
|
||||
serv->sv_tmpcnt++;
|
||||
if (serv->sv_temptimer.function == NULL) {
|
||||
/* setup timer to age temp transports */
|
||||
setup_timer(&serv->sv_temptimer, svc_age_temp_xprts,
|
||||
(unsigned long)serv);
|
||||
mod_timer(&serv->sv_temptimer,
|
||||
jiffies + svc_conn_age_period * HZ);
|
||||
}
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
svc_xprt_received(newxpt);
|
||||
}
|
||||
|
||||
static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt)
|
||||
{
|
||||
struct svc_serv *serv = rqstp->rq_server;
|
||||
int len = 0;
|
||||
|
||||
len = 0;
|
||||
if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
|
||||
dprintk("svc_recv: found XPT_CLOSE\n");
|
||||
svc_delete_xprt(xprt);
|
||||
/* Leave XPT_BUSY set on the dead xprt: */
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
|
||||
struct svc_xprt *newxpt;
|
||||
/*
|
||||
* We know this module_get will succeed because the
|
||||
* listener holds a reference too
|
||||
*/
|
||||
__module_get(xprt->xpt_class->xcl_owner);
|
||||
svc_check_conn_limits(xprt->xpt_server);
|
||||
newxpt = xprt->xpt_ops->xpo_accept(xprt);
|
||||
if (newxpt) {
|
||||
/*
|
||||
* We know this module_get will succeed because the
|
||||
* listener holds a reference too
|
||||
*/
|
||||
__module_get(newxpt->xpt_class->xcl_owner);
|
||||
svc_check_conn_limits(xprt->xpt_server);
|
||||
spin_lock_bh(&serv->sv_lock);
|
||||
set_bit(XPT_TEMP, &newxpt->xpt_flags);
|
||||
list_add(&newxpt->xpt_list, &serv->sv_tempsocks);
|
||||
serv->sv_tmpcnt++;
|
||||
if (serv->sv_temptimer.function == NULL) {
|
||||
/* setup timer to age temp transports */
|
||||
setup_timer(&serv->sv_temptimer,
|
||||
svc_age_temp_xprts,
|
||||
(unsigned long)serv);
|
||||
mod_timer(&serv->sv_temptimer,
|
||||
jiffies + svc_conn_age_period * HZ);
|
||||
}
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
svc_xprt_received(newxpt);
|
||||
}
|
||||
if (newxpt)
|
||||
svc_add_new_temp_xprt(serv, newxpt);
|
||||
} else if (xprt->xpt_ops->xpo_has_wspace(xprt)) {
|
||||
/* XPT_DATA|XPT_DEFERRED case: */
|
||||
dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n",
|
||||
rqstp, pool->sp_id, xprt,
|
||||
rqstp, rqstp->rq_pool->sp_id, xprt,
|
||||
atomic_read(&xprt->xpt_ref.refcount));
|
||||
rqstp->rq_deferred = svc_deferred_dequeue(xprt);
|
||||
if (rqstp->rq_deferred)
|
||||
@ -736,10 +732,51 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
|
||||
rqstp->rq_reserved = serv->sv_max_mesg;
|
||||
atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
|
||||
}
|
||||
/* clear XPT_BUSY: */
|
||||
svc_xprt_received(xprt);
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive the next request on any transport. This code is carefully
|
||||
* organised not to touch any cachelines in the shared svc_serv
|
||||
* structure, only cachelines in the local svc_pool.
|
||||
*/
|
||||
int svc_recv(struct svc_rqst *rqstp, long timeout)
|
||||
{
|
||||
struct svc_xprt *xprt = NULL;
|
||||
struct svc_serv *serv = rqstp->rq_server;
|
||||
int len, err;
|
||||
|
||||
dprintk("svc: server %p waiting for data (to = %ld)\n",
|
||||
rqstp, timeout);
|
||||
|
||||
if (rqstp->rq_xprt)
|
||||
printk(KERN_ERR
|
||||
"svc_recv: service %p, transport not NULL!\n",
|
||||
rqstp);
|
||||
if (waitqueue_active(&rqstp->rq_wait))
|
||||
printk(KERN_ERR
|
||||
"svc_recv: service %p, wait queue active!\n",
|
||||
rqstp);
|
||||
|
||||
err = svc_alloc_arg(rqstp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
try_to_freeze();
|
||||
cond_resched();
|
||||
if (signalled() || kthread_should_stop())
|
||||
return -EINTR;
|
||||
|
||||
xprt = svc_get_next_xprt(rqstp, timeout);
|
||||
if (IS_ERR(xprt))
|
||||
return PTR_ERR(xprt);
|
||||
|
||||
len = svc_handle_xprt(rqstp, xprt);
|
||||
|
||||
/* No data, incomplete (TCP) read, or accept() */
|
||||
if (len == 0 || len == -EAGAIN)
|
||||
if (len <= 0)
|
||||
goto out;
|
||||
|
||||
clear_bit(XPT_OLD, &xprt->xpt_flags);
|
||||
@ -917,16 +954,18 @@ void svc_close_xprt(struct svc_xprt *xprt)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(svc_close_xprt);
|
||||
|
||||
static void svc_close_list(struct list_head *xprt_list, struct net *net)
|
||||
static void svc_close_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net)
|
||||
{
|
||||
struct svc_xprt *xprt;
|
||||
|
||||
spin_lock(&serv->sv_lock);
|
||||
list_for_each_entry(xprt, xprt_list, xpt_list) {
|
||||
if (xprt->xpt_net != net)
|
||||
continue;
|
||||
set_bit(XPT_CLOSE, &xprt->xpt_flags);
|
||||
set_bit(XPT_BUSY, &xprt->xpt_flags);
|
||||
}
|
||||
spin_unlock(&serv->sv_lock);
|
||||
}
|
||||
|
||||
static void svc_clear_pools(struct svc_serv *serv, struct net *net)
|
||||
@ -949,24 +988,28 @@ static void svc_clear_pools(struct svc_serv *serv, struct net *net)
|
||||
}
|
||||
}
|
||||
|
||||
static void svc_clear_list(struct list_head *xprt_list, struct net *net)
|
||||
static void svc_clear_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net)
|
||||
{
|
||||
struct svc_xprt *xprt;
|
||||
struct svc_xprt *tmp;
|
||||
LIST_HEAD(victims);
|
||||
|
||||
spin_lock(&serv->sv_lock);
|
||||
list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) {
|
||||
if (xprt->xpt_net != net)
|
||||
continue;
|
||||
svc_delete_xprt(xprt);
|
||||
list_move(&xprt->xpt_list, &victims);
|
||||
}
|
||||
list_for_each_entry(xprt, xprt_list, xpt_list)
|
||||
BUG_ON(xprt->xpt_net == net);
|
||||
spin_unlock(&serv->sv_lock);
|
||||
|
||||
list_for_each_entry_safe(xprt, tmp, &victims, xpt_list)
|
||||
svc_delete_xprt(xprt);
|
||||
}
|
||||
|
||||
void svc_close_net(struct svc_serv *serv, struct net *net)
|
||||
{
|
||||
svc_close_list(&serv->sv_tempsocks, net);
|
||||
svc_close_list(&serv->sv_permsocks, net);
|
||||
svc_close_list(serv, &serv->sv_tempsocks, net);
|
||||
svc_close_list(serv, &serv->sv_permsocks, net);
|
||||
|
||||
svc_clear_pools(serv, net);
|
||||
/*
|
||||
@ -974,8 +1017,8 @@ void svc_close_net(struct svc_serv *serv, struct net *net)
|
||||
* svc_xprt_enqueue will not add new entries without taking the
|
||||
* sp_lock and checking XPT_BUSY.
|
||||
*/
|
||||
svc_clear_list(&serv->sv_tempsocks, net);
|
||||
svc_clear_list(&serv->sv_permsocks, net);
|
||||
svc_clear_list(serv, &serv->sv_tempsocks, net);
|
||||
svc_clear_list(serv, &serv->sv_permsocks, net);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -59,7 +59,7 @@
|
||||
|
||||
|
||||
static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *,
|
||||
int *errp, int flags);
|
||||
int flags);
|
||||
static void svc_udp_data_ready(struct sock *, int);
|
||||
static int svc_udp_recvfrom(struct svc_rqst *);
|
||||
static int svc_udp_sendto(struct svc_rqst *);
|
||||
@ -305,57 +305,6 @@ static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining)
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_sock_names - construct a list of listener names in a string
|
||||
* @serv: pointer to RPC service
|
||||
* @buf: pointer to a buffer to fill in with socket names
|
||||
* @buflen: size of the buffer to be filled
|
||||
* @toclose: pointer to '\0'-terminated C string containing the name
|
||||
* of a listener to be closed
|
||||
*
|
||||
* Fills in @buf with a '\n'-separated list of names of listener
|
||||
* sockets. If @toclose is not NULL, the socket named by @toclose
|
||||
* is closed, and is not included in the output list.
|
||||
*
|
||||
* Returns positive length of the socket name string, or a negative
|
||||
* errno value on error.
|
||||
*/
|
||||
int svc_sock_names(struct svc_serv *serv, char *buf, const size_t buflen,
|
||||
const char *toclose)
|
||||
{
|
||||
struct svc_sock *svsk, *closesk = NULL;
|
||||
int len = 0;
|
||||
|
||||
if (!serv)
|
||||
return 0;
|
||||
|
||||
spin_lock_bh(&serv->sv_lock);
|
||||
list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) {
|
||||
int onelen = svc_one_sock_name(svsk, buf + len, buflen - len);
|
||||
if (onelen < 0) {
|
||||
len = onelen;
|
||||
break;
|
||||
}
|
||||
if (toclose && strcmp(toclose, buf + len) == 0) {
|
||||
closesk = svsk;
|
||||
svc_xprt_get(&closesk->sk_xprt);
|
||||
} else
|
||||
len += onelen;
|
||||
}
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
|
||||
if (closesk) {
|
||||
/* Should unregister with portmap, but you cannot
|
||||
* unregister just one protocol...
|
||||
*/
|
||||
svc_close_xprt(&closesk->sk_xprt);
|
||||
svc_xprt_put(&closesk->sk_xprt);
|
||||
} else if (toclose)
|
||||
return -ENOENT;
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(svc_sock_names);
|
||||
|
||||
/*
|
||||
* Check input queue length
|
||||
*/
|
||||
@ -598,11 +547,9 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
|
||||
dprintk("svc: recvfrom returned error %d\n", -err);
|
||||
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
|
||||
}
|
||||
return -EAGAIN;
|
||||
return 0;
|
||||
}
|
||||
len = svc_addr_len(svc_addr(rqstp));
|
||||
if (len == 0)
|
||||
return -EAFNOSUPPORT;
|
||||
rqstp->rq_addrlen = len;
|
||||
if (skb->tstamp.tv64 == 0) {
|
||||
skb->tstamp = ktime_get_real();
|
||||
@ -620,10 +567,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
|
||||
if (!svc_udp_get_dest_address(rqstp, cmh)) {
|
||||
net_warn_ratelimited("svc: received unknown control message %d/%d; dropping RPC reply datagram\n",
|
||||
cmh->cmsg_level, cmh->cmsg_type);
|
||||
out_free:
|
||||
trace_kfree_skb(skb, svc_udp_recvfrom);
|
||||
skb_free_datagram_locked(svsk->sk_sk, skb);
|
||||
return 0;
|
||||
goto out_free;
|
||||
}
|
||||
rqstp->rq_daddrlen = svc_addr_len(svc_daddr(rqstp));
|
||||
|
||||
@ -662,6 +606,10 @@ out_free:
|
||||
serv->sv_stats->netudpcnt++;
|
||||
|
||||
return len;
|
||||
out_free:
|
||||
trace_kfree_skb(skb, svc_udp_recvfrom);
|
||||
skb_free_datagram_locked(svsk->sk_sk, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -900,8 +848,9 @@ static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
|
||||
*/
|
||||
newsock->sk->sk_sndtimeo = HZ*30;
|
||||
|
||||
if (!(newsvsk = svc_setup_socket(serv, newsock, &err,
|
||||
(SVC_SOCK_ANONYMOUS | SVC_SOCK_TEMPORARY))))
|
||||
newsvsk = svc_setup_socket(serv, newsock,
|
||||
(SVC_SOCK_ANONYMOUS | SVC_SOCK_TEMPORARY));
|
||||
if (IS_ERR(newsvsk))
|
||||
goto failed;
|
||||
svc_xprt_set_remote(&newsvsk->sk_xprt, sin, slen);
|
||||
err = kernel_getsockname(newsock, sin, &slen);
|
||||
@ -1174,13 +1123,13 @@ error:
|
||||
if (len != -EAGAIN)
|
||||
goto err_other;
|
||||
dprintk("RPC: TCP recvfrom got EAGAIN\n");
|
||||
return -EAGAIN;
|
||||
return 0;
|
||||
err_other:
|
||||
printk(KERN_NOTICE "%s: recvfrom returned errno %d\n",
|
||||
svsk->sk_xprt.xpt_server->sv_name, -len);
|
||||
set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
|
||||
err_noclose:
|
||||
return -EAGAIN; /* record not complete */
|
||||
return 0; /* record not complete */
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1383,29 +1332,29 @@ EXPORT_SYMBOL_GPL(svc_sock_update_bufs);
|
||||
*/
|
||||
static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
|
||||
struct socket *sock,
|
||||
int *errp, int flags)
|
||||
int flags)
|
||||
{
|
||||
struct svc_sock *svsk;
|
||||
struct sock *inet;
|
||||
int pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
|
||||
int err = 0;
|
||||
|
||||
dprintk("svc: svc_setup_socket %p\n", sock);
|
||||
if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) {
|
||||
*errp = -ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
svsk = kzalloc(sizeof(*svsk), GFP_KERNEL);
|
||||
if (!svsk)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
inet = sock->sk;
|
||||
|
||||
/* Register socket with portmapper */
|
||||
if (*errp >= 0 && pmap_register)
|
||||
*errp = svc_register(serv, sock_net(sock->sk), inet->sk_family,
|
||||
if (pmap_register)
|
||||
err = svc_register(serv, sock_net(sock->sk), inet->sk_family,
|
||||
inet->sk_protocol,
|
||||
ntohs(inet_sk(inet)->inet_sport));
|
||||
|
||||
if (*errp < 0) {
|
||||
if (err < 0) {
|
||||
kfree(svsk);
|
||||
return NULL;
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
inet->sk_user_data = svsk;
|
||||
@ -1450,42 +1399,38 @@ int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
|
||||
int err = 0;
|
||||
struct socket *so = sockfd_lookup(fd, &err);
|
||||
struct svc_sock *svsk = NULL;
|
||||
struct sockaddr_storage addr;
|
||||
struct sockaddr *sin = (struct sockaddr *)&addr;
|
||||
int salen;
|
||||
|
||||
if (!so)
|
||||
return err;
|
||||
err = -EAFNOSUPPORT;
|
||||
if ((so->sk->sk_family != PF_INET) && (so->sk->sk_family != PF_INET6))
|
||||
err = -EAFNOSUPPORT;
|
||||
else if (so->sk->sk_protocol != IPPROTO_TCP &&
|
||||
goto out;
|
||||
err = -EPROTONOSUPPORT;
|
||||
if (so->sk->sk_protocol != IPPROTO_TCP &&
|
||||
so->sk->sk_protocol != IPPROTO_UDP)
|
||||
err = -EPROTONOSUPPORT;
|
||||
else if (so->state > SS_UNCONNECTED)
|
||||
err = -EISCONN;
|
||||
else {
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
err = -ENOENT;
|
||||
else
|
||||
svsk = svc_setup_socket(serv, so, &err,
|
||||
SVC_SOCK_DEFAULTS);
|
||||
if (svsk) {
|
||||
struct sockaddr_storage addr;
|
||||
struct sockaddr *sin = (struct sockaddr *)&addr;
|
||||
int salen;
|
||||
if (kernel_getsockname(svsk->sk_sock, sin, &salen) == 0)
|
||||
svc_xprt_set_local(&svsk->sk_xprt, sin, salen);
|
||||
clear_bit(XPT_TEMP, &svsk->sk_xprt.xpt_flags);
|
||||
spin_lock_bh(&serv->sv_lock);
|
||||
list_add(&svsk->sk_xprt.xpt_list, &serv->sv_permsocks);
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
svc_xprt_received(&svsk->sk_xprt);
|
||||
err = 0;
|
||||
} else
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
if (err) {
|
||||
sockfd_put(so);
|
||||
return err;
|
||||
goto out;
|
||||
err = -EISCONN;
|
||||
if (so->state > SS_UNCONNECTED)
|
||||
goto out;
|
||||
err = -ENOENT;
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
goto out;
|
||||
svsk = svc_setup_socket(serv, so, SVC_SOCK_DEFAULTS);
|
||||
if (IS_ERR(svsk)) {
|
||||
module_put(THIS_MODULE);
|
||||
err = PTR_ERR(svsk);
|
||||
goto out;
|
||||
}
|
||||
if (kernel_getsockname(svsk->sk_sock, sin, &salen) == 0)
|
||||
svc_xprt_set_local(&svsk->sk_xprt, sin, salen);
|
||||
svc_add_new_perm_xprt(serv, &svsk->sk_xprt);
|
||||
return svc_one_sock_name(svsk, name_return, len);
|
||||
out:
|
||||
sockfd_put(so);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(svc_addsock);
|
||||
|
||||
@ -1563,11 +1508,13 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
|
||||
goto bummer;
|
||||
}
|
||||
|
||||
if ((svsk = svc_setup_socket(serv, sock, &error, flags)) != NULL) {
|
||||
svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen);
|
||||
return (struct svc_xprt *)svsk;
|
||||
svsk = svc_setup_socket(serv, sock, flags);
|
||||
if (IS_ERR(svsk)) {
|
||||
error = PTR_ERR(svsk);
|
||||
goto bummer;
|
||||
}
|
||||
|
||||
svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen);
|
||||
return (struct svc_xprt *)svsk;
|
||||
bummer:
|
||||
dprintk("svc: svc_create_socket error = %d\n", -error);
|
||||
sock_release(sock);
|
||||
|
@ -578,10 +578,6 @@ static void handle_connect_req(struct rdma_cm_id *new_cma_id, size_t client_ird)
|
||||
list_add_tail(&newxprt->sc_accept_q, &listen_xprt->sc_accept_q);
|
||||
spin_unlock_bh(&listen_xprt->sc_lock);
|
||||
|
||||
/*
|
||||
* Can't use svc_xprt_received here because we are not on a
|
||||
* rqstp thread
|
||||
*/
|
||||
set_bit(XPT_CONN, &listen_xprt->sc_xprt.xpt_flags);
|
||||
svc_xprt_enqueue(&listen_xprt->sc_xprt);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user