Merge branch 'for-2.6.38' of git://linux-nfs.org/~bfields/linux
* 'for-2.6.38' of git://linux-nfs.org/~bfields/linux: (62 commits) nfsd4: fix callback restarting nfsd: break lease on unlink, link, and rename nfsd4: break lease on nfsd setattr nfsd: don't support msnfs export option nfsd4: initialize cb_per_client nfsd4: allow restarting callbacks nfsd4: simplify nfsd4_cb_prepare nfsd4: give out delegations more quickly in 4.1 case nfsd4: add helper function to run callbacks nfsd4: make sure sequence flags are set after destroy_session nfsd4: re-probe callback on connection loss nfsd4: set sequence flag when backchannel is down nfsd4: keep finer-grained callback status rpc: allow xprt_class->setup to return a preexisting xprt rpc: keep backchannel xprt as long as server connection rpc: move sk_bc_xprt to svc_xprt nfsd4: allow backchannel recovery nfsd4: support BIND_CONN_TO_SESSION nfsd4: modify session list under cl_lock Documentation: fl_mylease no longer exists ... Fix up conflicts in fs/nfsd/vfs.c with the vfs-scale work. The vfs-scale work touched some msnfs cases, and this merge removes support for that entirely, so the conflict was trivial to resolve.
This commit is contained in:
@ -230,7 +230,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
|
||||
dp->dl_client = clp;
|
||||
get_nfs4_file(fp);
|
||||
dp->dl_file = fp;
|
||||
nfs4_file_get_access(fp, O_RDONLY);
|
||||
dp->dl_vfs_file = find_readable_file(fp);
|
||||
get_file(dp->dl_vfs_file);
|
||||
dp->dl_flock = NULL;
|
||||
dp->dl_type = type;
|
||||
dp->dl_stateid.si_boot = boot_time;
|
||||
@ -252,6 +253,7 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
|
||||
if (atomic_dec_and_test(&dp->dl_count)) {
|
||||
dprintk("NFSD: freeing dp %p\n",dp);
|
||||
put_nfs4_file(dp->dl_file);
|
||||
fput(dp->dl_vfs_file);
|
||||
kmem_cache_free(deleg_slab, dp);
|
||||
num_delegations--;
|
||||
}
|
||||
@ -265,12 +267,10 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
|
||||
static void
|
||||
nfs4_close_delegation(struct nfs4_delegation *dp)
|
||||
{
|
||||
struct file *filp = find_readable_file(dp->dl_file);
|
||||
|
||||
dprintk("NFSD: close_delegation dp %p\n",dp);
|
||||
/* XXX: do we even need this check?: */
|
||||
if (dp->dl_flock)
|
||||
vfs_setlease(filp, F_UNLCK, &dp->dl_flock);
|
||||
nfs4_file_put_access(dp->dl_file, O_RDONLY);
|
||||
vfs_setlease(dp->dl_vfs_file, F_UNLCK, &dp->dl_flock);
|
||||
}
|
||||
|
||||
/* Called under the state lock. */
|
||||
@ -642,6 +642,7 @@ static void nfsd4_conn_lost(struct svc_xpt_user *u)
|
||||
free_conn(c);
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
nfsd4_probe_callback(clp);
|
||||
}
|
||||
|
||||
static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
|
||||
@ -679,15 +680,12 @@ 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)
|
||||
static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir)
|
||||
{
|
||||
struct nfsd4_conn *conn;
|
||||
u32 flags = NFS4_CDFC4_FORE;
|
||||
int ret;
|
||||
|
||||
if (ses->se_flags & SESSION4_BACK_CHAN)
|
||||
flags |= NFS4_CDFC4_BACK;
|
||||
conn = alloc_conn(rqstp, flags);
|
||||
conn = alloc_conn(rqstp, dir);
|
||||
if (!conn)
|
||||
return nfserr_jukebox;
|
||||
nfsd4_hash_conn(conn, ses);
|
||||
@ -698,6 +696,17 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses)
|
||||
{
|
||||
u32 dir = NFS4_CDFC4_FORE;
|
||||
|
||||
if (ses->se_flags & SESSION4_BACK_CHAN)
|
||||
dir |= NFS4_CDFC4_BACK;
|
||||
|
||||
return nfsd4_new_conn(rqstp, ses, dir);
|
||||
}
|
||||
|
||||
/* must be called under client_lock */
|
||||
static void nfsd4_del_conns(struct nfsd4_session *s)
|
||||
{
|
||||
struct nfs4_client *clp = s->se_client;
|
||||
@ -749,6 +758,8 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n
|
||||
*/
|
||||
slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached);
|
||||
numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs);
|
||||
if (numslots < 1)
|
||||
return NULL;
|
||||
|
||||
new = alloc_session(slotsize, numslots);
|
||||
if (!new) {
|
||||
@ -769,25 +780,30 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n
|
||||
idx = hash_sessionid(&new->se_sessionid);
|
||||
spin_lock(&client_lock);
|
||||
list_add(&new->se_hash, &sessionid_hashtbl[idx]);
|
||||
spin_lock(&clp->cl_lock);
|
||||
list_add(&new->se_perclnt, &clp->cl_sessions);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
spin_unlock(&client_lock);
|
||||
|
||||
status = nfsd4_new_conn(rqstp, new);
|
||||
status = nfsd4_new_conn_from_crses(rqstp, new);
|
||||
/* whoops: benny points out, status is ignored! (err, or bogus) */
|
||||
if (status) {
|
||||
free_session(&new->se_ref);
|
||||
return NULL;
|
||||
}
|
||||
if (!clp->cl_cb_session && (cses->flags & SESSION4_BACK_CHAN)) {
|
||||
if (cses->flags & SESSION4_BACK_CHAN) {
|
||||
struct sockaddr *sa = svc_addr(rqstp);
|
||||
|
||||
clp->cl_cb_session = new;
|
||||
clp->cl_cb_conn.cb_xprt = rqstp->rq_xprt;
|
||||
svc_xprt_get(rqstp->rq_xprt);
|
||||
/*
|
||||
* This is a little silly; with sessions there's no real
|
||||
* use for the callback address. Use the peer address
|
||||
* as a reasonable default for now, but consider fixing
|
||||
* the rpc client not to require an address in the
|
||||
* future:
|
||||
*/
|
||||
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);
|
||||
}
|
||||
nfsd4_probe_callback(clp);
|
||||
return new;
|
||||
}
|
||||
|
||||
@ -817,7 +833,9 @@ static void
|
||||
unhash_session(struct nfsd4_session *ses)
|
||||
{
|
||||
list_del(&ses->se_hash);
|
||||
spin_lock(&ses->se_client->cl_lock);
|
||||
list_del(&ses->se_perclnt);
|
||||
spin_unlock(&ses->se_client->cl_lock);
|
||||
}
|
||||
|
||||
/* must be called under the client_lock */
|
||||
@ -923,8 +941,10 @@ unhash_client_locked(struct nfs4_client *clp)
|
||||
|
||||
mark_client_expired(clp);
|
||||
list_del(&clp->cl_lru);
|
||||
spin_lock(&clp->cl_lock);
|
||||
list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
|
||||
list_del_init(&ses->se_hash);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1051,12 +1071,13 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
|
||||
|
||||
memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
|
||||
atomic_set(&clp->cl_refcount, 0);
|
||||
atomic_set(&clp->cl_cb_set, 0);
|
||||
clp->cl_cb_state = NFSD4_CB_UNKNOWN;
|
||||
INIT_LIST_HEAD(&clp->cl_idhash);
|
||||
INIT_LIST_HEAD(&clp->cl_strhash);
|
||||
INIT_LIST_HEAD(&clp->cl_openowners);
|
||||
INIT_LIST_HEAD(&clp->cl_delegations);
|
||||
INIT_LIST_HEAD(&clp->cl_lru);
|
||||
INIT_LIST_HEAD(&clp->cl_callbacks);
|
||||
spin_lock_init(&clp->cl_lock);
|
||||
INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
|
||||
clp->cl_time = get_seconds();
|
||||
@ -1132,54 +1153,55 @@ find_unconfirmed_client(clientid_t *clid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 iff clp's clientid establishment method matches the use_exchange_id
|
||||
* parameter. Matching is based on the fact the at least one of the
|
||||
* EXCHGID4_FLAG_USE_{NON_PNFS,PNFS_MDS,PNFS_DS} flags must be set for v4.1
|
||||
*
|
||||
* FIXME: we need to unify the clientid namespaces for nfsv4.x
|
||||
* and correctly deal with client upgrade/downgrade in EXCHANGE_ID
|
||||
* and SET_CLIENTID{,_CONFIRM}
|
||||
*/
|
||||
static inline int
|
||||
match_clientid_establishment(struct nfs4_client *clp, bool use_exchange_id)
|
||||
static bool clp_used_exchangeid(struct nfs4_client *clp)
|
||||
{
|
||||
bool has_exchange_flags = (clp->cl_exchange_flags != 0);
|
||||
return use_exchange_id == has_exchange_flags;
|
||||
}
|
||||
return clp->cl_exchange_flags != 0;
|
||||
}
|
||||
|
||||
static struct nfs4_client *
|
||||
find_confirmed_client_by_str(const char *dname, unsigned int hashval,
|
||||
bool use_exchange_id)
|
||||
find_confirmed_client_by_str(const char *dname, unsigned int hashval)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
|
||||
list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) {
|
||||
if (same_name(clp->cl_recdir, dname) &&
|
||||
match_clientid_establishment(clp, use_exchange_id))
|
||||
if (same_name(clp->cl_recdir, dname))
|
||||
return clp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nfs4_client *
|
||||
find_unconfirmed_client_by_str(const char *dname, unsigned int hashval,
|
||||
bool use_exchange_id)
|
||||
find_unconfirmed_client_by_str(const char *dname, unsigned int hashval)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
|
||||
list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) {
|
||||
if (same_name(clp->cl_recdir, dname) &&
|
||||
match_clientid_establishment(clp, use_exchange_id))
|
||||
if (same_name(clp->cl_recdir, dname))
|
||||
return clp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rpc_svcaddr2sockaddr(struct sockaddr *sa, unsigned short family, union svc_addr_u *svcaddr)
|
||||
{
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
((struct sockaddr_in *)sa)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)sa)->sin_addr = svcaddr->addr;
|
||||
return;
|
||||
case AF_INET6:
|
||||
((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6;
|
||||
((struct sockaddr_in6 *)sa)->sin6_addr = svcaddr->addr6;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid)
|
||||
gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
|
||||
struct sockaddr *sa = svc_addr(rqstp);
|
||||
u32 scopeid = rpc_get_scope_id(sa);
|
||||
unsigned short expected_family;
|
||||
|
||||
/* Currently, we only support tcp and tcp6 for the callback channel */
|
||||
@ -1205,6 +1227,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid)
|
||||
|
||||
conn->cb_prog = se->se_callback_prog;
|
||||
conn->cb_ident = se->se_callback_ident;
|
||||
rpc_svcaddr2sockaddr((struct sockaddr *)&conn->cb_saddr, expected_family, &rqstp->rq_daddr);
|
||||
return;
|
||||
out_err:
|
||||
conn->cb_addr.ss_family = AF_UNSPEC;
|
||||
@ -1344,7 +1367,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
|
||||
case SP4_NONE:
|
||||
break;
|
||||
case SP4_SSV:
|
||||
return nfserr_encr_alg_unsupp;
|
||||
return nfserr_serverfault;
|
||||
default:
|
||||
BUG(); /* checked by xdr code */
|
||||
case SP4_MACH_CRED:
|
||||
@ -1361,8 +1384,12 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
|
||||
nfs4_lock_state();
|
||||
status = nfs_ok;
|
||||
|
||||
conf = find_confirmed_client_by_str(dname, strhashval, true);
|
||||
conf = find_confirmed_client_by_str(dname, strhashval);
|
||||
if (conf) {
|
||||
if (!clp_used_exchangeid(conf)) {
|
||||
status = nfserr_clid_inuse; /* XXX: ? */
|
||||
goto out;
|
||||
}
|
||||
if (!same_verf(&verf, &conf->cl_verifier)) {
|
||||
/* 18.35.4 case 8 */
|
||||
if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) {
|
||||
@ -1403,7 +1430,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
|
||||
goto out;
|
||||
}
|
||||
|
||||
unconf = find_unconfirmed_client_by_str(dname, strhashval, true);
|
||||
unconf = find_unconfirmed_client_by_str(dname, strhashval);
|
||||
if (unconf) {
|
||||
/*
|
||||
* Possible retry or client restart. Per 18.35.4 case 4,
|
||||
@ -1560,6 +1587,8 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||
status = nfs_ok;
|
||||
memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
|
||||
NFS4_MAX_SESSIONID_LEN);
|
||||
memcpy(&cr_ses->fore_channel, &new->se_fchannel,
|
||||
sizeof(struct nfsd4_channel_attrs));
|
||||
cs_slot->sl_seqid++;
|
||||
cr_ses->seqid = cs_slot->sl_seqid;
|
||||
|
||||
@ -1581,6 +1610,45 @@ static bool nfsd4_last_compound_op(struct svc_rqst *rqstp)
|
||||
return argp->opcnt == resp->opcnt;
|
||||
}
|
||||
|
||||
static __be32 nfsd4_map_bcts_dir(u32 *dir)
|
||||
{
|
||||
switch (*dir) {
|
||||
case NFS4_CDFC4_FORE:
|
||||
case NFS4_CDFC4_BACK:
|
||||
return nfs_ok;
|
||||
case NFS4_CDFC4_FORE_OR_BOTH:
|
||||
case NFS4_CDFC4_BACK_OR_BOTH:
|
||||
*dir = NFS4_CDFC4_BOTH;
|
||||
return nfs_ok;
|
||||
};
|
||||
return nfserr_inval;
|
||||
}
|
||||
|
||||
__be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
|
||||
struct nfsd4_compound_state *cstate,
|
||||
struct nfsd4_bind_conn_to_session *bcts)
|
||||
{
|
||||
__be32 status;
|
||||
|
||||
if (!nfsd4_last_compound_op(rqstp))
|
||||
return nfserr_not_only_op;
|
||||
spin_lock(&client_lock);
|
||||
cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid);
|
||||
/* Sorta weird: we only need the refcnt'ing because new_conn acquires
|
||||
* client_lock iself: */
|
||||
if (cstate->session) {
|
||||
nfsd4_get_session(cstate->session);
|
||||
atomic_inc(&cstate->session->se_client->cl_refcount);
|
||||
}
|
||||
spin_unlock(&client_lock);
|
||||
if (!cstate->session)
|
||||
return nfserr_badsession;
|
||||
|
||||
status = nfsd4_map_bcts_dir(&bcts->dir);
|
||||
nfsd4_new_conn(rqstp, cstate->session, bcts->dir);
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
|
||||
{
|
||||
if (!session)
|
||||
@ -1619,8 +1687,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
|
||||
spin_unlock(&client_lock);
|
||||
|
||||
nfs4_lock_state();
|
||||
/* wait for callbacks */
|
||||
nfsd4_shutdown_callback(ses->se_client);
|
||||
nfsd4_probe_callback_sync(ses->se_client);
|
||||
nfs4_unlock_state();
|
||||
|
||||
nfsd4_del_conns(ses);
|
||||
@ -1733,8 +1800,12 @@ nfsd4_sequence(struct svc_rqst *rqstp,
|
||||
out:
|
||||
/* Hold a session reference until done processing the compound. */
|
||||
if (cstate->session) {
|
||||
struct nfs4_client *clp = session->se_client;
|
||||
|
||||
nfsd4_get_session(cstate->session);
|
||||
atomic_inc(&session->se_client->cl_refcount);
|
||||
atomic_inc(&clp->cl_refcount);
|
||||
if (clp->cl_cb_state == NFSD4_CB_DOWN)
|
||||
seq->status_flags |= SEQ4_STATUS_CB_PATH_DOWN;
|
||||
}
|
||||
kfree(conn);
|
||||
spin_unlock(&client_lock);
|
||||
@ -1775,7 +1846,6 @@ __be32
|
||||
nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct nfsd4_setclientid *setclid)
|
||||
{
|
||||
struct sockaddr *sa = svc_addr(rqstp);
|
||||
struct xdr_netobj clname = {
|
||||
.len = setclid->se_namelen,
|
||||
.data = setclid->se_name,
|
||||
@ -1801,10 +1871,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
strhashval = clientstr_hashval(dname);
|
||||
|
||||
nfs4_lock_state();
|
||||
conf = find_confirmed_client_by_str(dname, strhashval, false);
|
||||
conf = find_confirmed_client_by_str(dname, strhashval);
|
||||
if (conf) {
|
||||
/* RFC 3530 14.2.33 CASE 0: */
|
||||
status = nfserr_clid_inuse;
|
||||
if (clp_used_exchangeid(conf))
|
||||
goto out;
|
||||
if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
|
||||
char addr_str[INET6_ADDRSTRLEN];
|
||||
rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str,
|
||||
@ -1819,7 +1891,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
* has a description of SETCLIENTID request processing consisting
|
||||
* of 5 bullet points, labeled as CASE0 - CASE4 below.
|
||||
*/
|
||||
unconf = find_unconfirmed_client_by_str(dname, strhashval, false);
|
||||
unconf = find_unconfirmed_client_by_str(dname, strhashval);
|
||||
status = nfserr_resource;
|
||||
if (!conf) {
|
||||
/*
|
||||
@ -1876,7 +1948,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
* for consistent minorversion use throughout:
|
||||
*/
|
||||
new->cl_minorversion = 0;
|
||||
gen_callback(new, setclid, rpc_get_scope_id(sa));
|
||||
gen_callback(new, setclid, rqstp);
|
||||
add_to_unconfirmed(new, strhashval);
|
||||
setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
|
||||
setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
|
||||
@ -1935,7 +2007,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
|
||||
if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
|
||||
status = nfserr_clid_inuse;
|
||||
else {
|
||||
atomic_set(&conf->cl_cb_set, 0);
|
||||
nfsd4_change_callback(conf, &unconf->cl_cb_conn);
|
||||
nfsd4_probe_callback(conf);
|
||||
expire_client(unconf);
|
||||
@ -1964,7 +2035,7 @@ 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, false);
|
||||
hash);
|
||||
if (conf) {
|
||||
nfsd4_remove_clid_dir(conf);
|
||||
expire_client(conf);
|
||||
@ -2300,41 +2371,6 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
|
||||
nfsd4_cb_recall(dp);
|
||||
}
|
||||
|
||||
/*
|
||||
* The file_lock is being reapd.
|
||||
*
|
||||
* Called by locks_free_lock() with lock_flocks() held.
|
||||
*/
|
||||
static
|
||||
void nfsd_release_deleg_cb(struct file_lock *fl)
|
||||
{
|
||||
struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;
|
||||
|
||||
dprintk("NFSD nfsd_release_deleg_cb: fl %p dp %p dl_count %d\n", fl,dp, atomic_read(&dp->dl_count));
|
||||
|
||||
if (!(fl->fl_flags & FL_LEASE) || !dp)
|
||||
return;
|
||||
dp->dl_flock = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called from setlease() with lock_flocks() held
|
||||
*/
|
||||
static
|
||||
int nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try)
|
||||
{
|
||||
struct nfs4_delegation *onlistd =
|
||||
(struct nfs4_delegation *)onlist->fl_owner;
|
||||
struct nfs4_delegation *tryd =
|
||||
(struct nfs4_delegation *)try->fl_owner;
|
||||
|
||||
if (onlist->fl_lmops != try->fl_lmops)
|
||||
return 0;
|
||||
|
||||
return onlistd->dl_client == tryd->dl_client;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
|
||||
{
|
||||
@ -2346,8 +2382,6 @@ int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
|
||||
|
||||
static const struct lock_manager_operations nfsd_lease_mng_ops = {
|
||||
.fl_break = nfsd_break_deleg_cb,
|
||||
.fl_release_private = nfsd_release_deleg_cb,
|
||||
.fl_mylease = nfsd_same_client_deleg_cb,
|
||||
.fl_change = nfsd_change_deleg_cb,
|
||||
};
|
||||
|
||||
@ -2514,8 +2548,6 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file
|
||||
if (!fp->fi_fds[oflag]) {
|
||||
status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
|
||||
&fp->fi_fds[oflag]);
|
||||
if (status == nfserr_dropit)
|
||||
status = nfserr_jukebox;
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
@ -2596,6 +2628,19 @@ nfs4_set_claim_prev(struct nfsd4_open *open)
|
||||
open->op_stateowner->so_client->cl_firststate = 1;
|
||||
}
|
||||
|
||||
/* Should we give out recallable state?: */
|
||||
static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
|
||||
{
|
||||
if (clp->cl_cb_state == NFSD4_CB_UP)
|
||||
return true;
|
||||
/*
|
||||
* In the sessions case, since we don't have to establish a
|
||||
* separate connection for callbacks, we assume it's OK
|
||||
* until we hear otherwise:
|
||||
*/
|
||||
return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to hand out a delegation.
|
||||
*/
|
||||
@ -2604,10 +2649,11 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
|
||||
{
|
||||
struct nfs4_delegation *dp;
|
||||
struct nfs4_stateowner *sop = stp->st_stateowner;
|
||||
int cb_up = atomic_read(&sop->so_client->cl_cb_set);
|
||||
int cb_up;
|
||||
struct file_lock *fl;
|
||||
int status, flag = 0;
|
||||
|
||||
cb_up = nfsd4_cb_channel_good(sop->so_client);
|
||||
flag = NFS4_OPEN_DELEGATE_NONE;
|
||||
open->op_recall = 0;
|
||||
switch (open->op_claim_type) {
|
||||
@ -2655,7 +2701,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
|
||||
dp->dl_flock = fl;
|
||||
|
||||
/* vfs_setlease checks to see if delegation should be handed out.
|
||||
* the lock_manager callbacks fl_mylease and fl_change are used
|
||||
* the lock_manager callback fl_change is used
|
||||
*/
|
||||
if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) {
|
||||
dprintk("NFSD: setlease failed [%d], no delegation\n", status);
|
||||
@ -2794,7 +2840,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
renew_client(clp);
|
||||
status = nfserr_cb_path_down;
|
||||
if (!list_empty(&clp->cl_delegations)
|
||||
&& !atomic_read(&clp->cl_cb_set))
|
||||
&& clp->cl_cb_state != NFSD4_CB_UP)
|
||||
goto out;
|
||||
status = nfs_ok;
|
||||
out:
|
||||
@ -3081,9 +3127,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
|
||||
if (status)
|
||||
goto out;
|
||||
renew_client(dp->dl_client);
|
||||
if (filpp)
|
||||
if (filpp) {
|
||||
*filpp = find_readable_file(dp->dl_file);
|
||||
BUG_ON(!*filpp);
|
||||
BUG_ON(!*filpp);
|
||||
}
|
||||
} else { /* open or lock stateid */
|
||||
stp = find_stateid(stateid, flags);
|
||||
if (!stp)
|
||||
@ -4107,7 +4154,7 @@ nfs4_has_reclaimed_state(const char *name, bool use_exchange_id)
|
||||
unsigned int strhashval = clientstr_hashval(name);
|
||||
struct nfs4_client *clp;
|
||||
|
||||
clp = find_confirmed_client_by_str(name, strhashval, use_exchange_id);
|
||||
clp = find_confirmed_client_by_str(name, strhashval);
|
||||
return clp ? 1 : 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user