Skip to content

Commit fc8738c

Browse files
neilbrownchucklever
authored andcommitted
nfsd: add support for freeing unused session-DRC slots
Reducing the number of slots in the session slot table requires confirmation from the client. This patch adds reduce_session_slots() which starts the process of getting confirmation, but never calls it. That will come in a later patch. Before we can free a slot we need to confirm that the client won't try to use it again. This involves returning a lower cr_maxrequests in a SEQUENCE reply and then seeing a ca_maxrequests on the same slot which is not larger than we limit we are trying to impose. So for each slot we need to remember that we have sent a reduced cr_maxrequests. To achieve this we introduce a concept of request "generations". Each time we decide to reduce cr_maxrequests we increment the generation number, and record this when we return the lower cr_maxrequests to the client. When a slot with the current generation reports a low ca_maxrequests, we commit to that level and free extra slots. We use an 16 bit generation number (64 seems wasteful) and if it cycles we iterate all slots and reset the generation number to avoid false matches. When we free a slot we store the seqid in the slot pointer so that it can be restored when we reactivate the slot. The RFC can be read as suggesting that the slot number could restart from one after a slot is retired and reactivated, but also suggests that retiring slots is not required. So when we reactive a slot we accept with the next seqid in sequence, or 1. When decoding sa_highest_slotid into maxslots we need to add 1 - this matches how it is encoded for the reply. se_dead is moved in struct nfsd4_session to remove a hole. Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: NeilBrown <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent 60aa656 commit fc8738c

File tree

4 files changed

+92
-15
lines changed

4 files changed

+92
-15
lines changed

fs/nfsd/nfs4state.c

Lines changed: 84 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1910,17 +1910,69 @@ gen_sessionid(struct nfsd4_session *ses)
19101910
#define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44)
19111911

19121912
static void
1913-
free_session_slots(struct nfsd4_session *ses)
1913+
free_session_slots(struct nfsd4_session *ses, int from)
19141914
{
19151915
int i;
19161916

1917-
for (i = 0; i < ses->se_fchannel.maxreqs; i++) {
1917+
if (from >= ses->se_fchannel.maxreqs)
1918+
return;
1919+
1920+
for (i = from; i < ses->se_fchannel.maxreqs; i++) {
19181921
struct nfsd4_slot *slot = xa_load(&ses->se_slots, i);
19191922

1920-
xa_erase(&ses->se_slots, i);
1923+
/*
1924+
* Save the seqid in case we reactivate this slot.
1925+
* This will never require a memory allocation so GFP
1926+
* flag is irrelevant
1927+
*/
1928+
xa_store(&ses->se_slots, i, xa_mk_value(slot->sl_seqid), 0);
19211929
free_svc_cred(&slot->sl_cred);
19221930
kfree(slot);
19231931
}
1932+
ses->se_fchannel.maxreqs = from;
1933+
if (ses->se_target_maxslots > from)
1934+
ses->se_target_maxslots = from;
1935+
}
1936+
1937+
/**
1938+
* reduce_session_slots - reduce the target max-slots of a session if possible
1939+
* @ses: The session to affect
1940+
* @dec: how much to decrease the target by
1941+
*
1942+
* This interface can be used by a shrinker to reduce the target max-slots
1943+
* for a session so that some slots can eventually be freed.
1944+
* It uses spin_trylock() as it may be called in a context where another
1945+
* spinlock is held that has a dependency on client_lock. As shrinkers are
1946+
* best-effort, skiping a session is client_lock is already held has no
1947+
* great coast
1948+
*
1949+
* Return value:
1950+
* The number of slots that the target was reduced by.
1951+
*/
1952+
static int __maybe_unused
1953+
reduce_session_slots(struct nfsd4_session *ses, int dec)
1954+
{
1955+
struct nfsd_net *nn = net_generic(ses->se_client->net,
1956+
nfsd_net_id);
1957+
int ret = 0;
1958+
1959+
if (ses->se_target_maxslots <= 1)
1960+
return ret;
1961+
if (!spin_trylock(&nn->client_lock))
1962+
return ret;
1963+
ret = min(dec, ses->se_target_maxslots-1);
1964+
ses->se_target_maxslots -= ret;
1965+
ses->se_slot_gen += 1;
1966+
if (ses->se_slot_gen == 0) {
1967+
int i;
1968+
ses->se_slot_gen = 1;
1969+
for (i = 0; i < ses->se_fchannel.maxreqs; i++) {
1970+
struct nfsd4_slot *slot = xa_load(&ses->se_slots, i);
1971+
slot->sl_generation = 0;
1972+
}
1973+
}
1974+
spin_unlock(&nn->client_lock);
1975+
return ret;
19241976
}
19251977

19261978
/*
@@ -1968,6 +2020,7 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs,
19682020
}
19692021
fattrs->maxreqs = i;
19702022
memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs));
2023+
new->se_target_maxslots = i;
19712024
new->se_cb_slot_avail = ~0U;
19722025
new->se_cb_highest_slot = min(battrs->maxreqs - 1,
19732026
NFSD_BC_SLOT_TABLE_SIZE - 1);
@@ -2081,7 +2134,7 @@ static void nfsd4_del_conns(struct nfsd4_session *s)
20812134

20822135
static void __free_session(struct nfsd4_session *ses)
20832136
{
2084-
free_session_slots(ses);
2137+
free_session_slots(ses, 0);
20852138
xa_destroy(&ses->se_slots);
20862139
kfree(ses);
20872140
}
@@ -2684,6 +2737,9 @@ static int client_info_show(struct seq_file *m, void *v)
26842737
seq_printf(m, "session slots:");
26852738
list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
26862739
seq_printf(m, " %u", ses->se_fchannel.maxreqs);
2740+
seq_printf(m, "\nsession target slots:");
2741+
list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
2742+
seq_printf(m, " %u", ses->se_target_maxslots);
26872743
spin_unlock(&clp->cl_lock);
26882744
seq_puts(m, "\n");
26892745

@@ -3674,10 +3730,10 @@ nfsd4_exchange_id_release(union nfsd4_op_u *u)
36743730
kfree(exid->server_impl_name);
36753731
}
36763732

3677-
static __be32 check_slot_seqid(u32 seqid, u32 slot_seqid, bool slot_inuse)
3733+
static __be32 check_slot_seqid(u32 seqid, u32 slot_seqid, u8 flags)
36783734
{
36793735
/* The slot is in use, and no response has been sent. */
3680-
if (slot_inuse) {
3736+
if (flags & NFSD4_SLOT_INUSE) {
36813737
if (seqid == slot_seqid)
36823738
return nfserr_jukebox;
36833739
else
@@ -3686,6 +3742,8 @@ static __be32 check_slot_seqid(u32 seqid, u32 slot_seqid, bool slot_inuse)
36863742
/* Note unsigned 32-bit arithmetic handles wraparound: */
36873743
if (likely(seqid == slot_seqid + 1))
36883744
return nfs_ok;
3745+
if ((flags & NFSD4_SLOT_REUSED) && seqid == 1)
3746+
return nfs_ok;
36893747
if (seqid == slot_seqid)
36903748
return nfserr_replay_cache;
36913749
return nfserr_seq_misordered;
@@ -4236,8 +4294,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
42364294
dprintk("%s: slotid %d\n", __func__, seq->slotid);
42374295

42384296
trace_nfsd_slot_seqid_sequence(clp, seq, slot);
4239-
status = check_slot_seqid(seq->seqid, slot->sl_seqid,
4240-
slot->sl_flags & NFSD4_SLOT_INUSE);
4297+
status = check_slot_seqid(seq->seqid, slot->sl_seqid, slot->sl_flags);
42414298
if (status == nfserr_replay_cache) {
42424299
status = nfserr_seq_misordered;
42434300
if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED))
@@ -4262,6 +4319,12 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
42624319
if (status)
42634320
goto out_put_session;
42644321

4322+
if (session->se_target_maxslots < session->se_fchannel.maxreqs &&
4323+
slot->sl_generation == session->se_slot_gen &&
4324+
seq->maxslots <= session->se_target_maxslots)
4325+
/* Client acknowledged our reduce maxreqs */
4326+
free_session_slots(session, session->se_target_maxslots);
4327+
42654328
buflen = (seq->cachethis) ?
42664329
session->se_fchannel.maxresp_cached :
42674330
session->se_fchannel.maxresp_sz;
@@ -4272,9 +4335,11 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
42724335
svc_reserve(rqstp, buflen);
42734336

42744337
status = nfs_ok;
4275-
/* Success! bump slot seqid */
4338+
/* Success! accept new slot seqid */
42764339
slot->sl_seqid = seq->seqid;
4340+
slot->sl_flags &= ~NFSD4_SLOT_REUSED;
42774341
slot->sl_flags |= NFSD4_SLOT_INUSE;
4342+
slot->sl_generation = session->se_slot_gen;
42784343
if (seq->cachethis)
42794344
slot->sl_flags |= NFSD4_SLOT_CACHETHIS;
42804345
else
@@ -4291,9 +4356,11 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
42914356
* the client might use.
42924357
*/
42934358
if (seq->slotid == session->se_fchannel.maxreqs - 1 &&
4359+
session->se_target_maxslots >= session->se_fchannel.maxreqs &&
42944360
session->se_fchannel.maxreqs < NFSD_MAX_SLOTS_PER_SESSION) {
42954361
int s = session->se_fchannel.maxreqs;
42964362
int cnt = DIV_ROUND_UP(s, 5);
4363+
void *prev_slot;
42974364

42984365
do {
42994366
/*
@@ -4303,18 +4370,25 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
43034370
*/
43044371
slot = kzalloc(slot_bytes(&session->se_fchannel),
43054372
GFP_NOWAIT);
4373+
prev_slot = xa_load(&session->se_slots, s);
4374+
if (xa_is_value(prev_slot) && slot) {
4375+
slot->sl_seqid = xa_to_value(prev_slot);
4376+
slot->sl_flags |= NFSD4_SLOT_REUSED;
4377+
}
43064378
if (slot &&
43074379
!xa_is_err(xa_store(&session->se_slots, s, slot,
43084380
GFP_NOWAIT))) {
43094381
s += 1;
43104382
session->se_fchannel.maxreqs = s;
4383+
session->se_target_maxslots = s;
43114384
} else {
43124385
kfree(slot);
43134386
slot = NULL;
43144387
}
43154388
} while (slot && --cnt > 0);
43164389
}
4317-
seq->maxslots = session->se_fchannel.maxreqs;
4390+
seq->maxslots = max(session->se_target_maxslots, seq->maxslots);
4391+
seq->target_maxslots = session->se_target_maxslots;
43184392

43194393
out:
43204394
switch (clp->cl_cb_state) {

fs/nfsd/nfs4xdr.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1884,7 +1884,8 @@ nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
18841884
return nfserr_bad_xdr;
18851885
seq->seqid = be32_to_cpup(p++);
18861886
seq->slotid = be32_to_cpup(p++);
1887-
seq->maxslots = be32_to_cpup(p++);
1887+
/* sa_highest_slotid counts from 0 but maxslots counts from 1 ... */
1888+
seq->maxslots = be32_to_cpup(p++) + 1;
18881889
seq->cachethis = be32_to_cpup(p);
18891890

18901891
seq->status_flags = 0;
@@ -4968,7 +4969,7 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr,
49684969
if (nfserr != nfs_ok)
49694970
return nfserr;
49704971
/* sr_target_highest_slotid */
4971-
nfserr = nfsd4_encode_slotid4(xdr, seq->maxslots - 1);
4972+
nfserr = nfsd4_encode_slotid4(xdr, seq->target_maxslots - 1);
49724973
if (nfserr != nfs_ok)
49734974
return nfserr;
49744975
/* sr_status_flags */

fs/nfsd/state.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,10 +245,12 @@ struct nfsd4_slot {
245245
struct svc_cred sl_cred;
246246
u32 sl_datalen;
247247
u16 sl_opcnt;
248+
u16 sl_generation;
248249
#define NFSD4_SLOT_INUSE (1 << 0)
249250
#define NFSD4_SLOT_CACHETHIS (1 << 1)
250251
#define NFSD4_SLOT_INITIALIZED (1 << 2)
251252
#define NFSD4_SLOT_CACHED (1 << 3)
253+
#define NFSD4_SLOT_REUSED (1 << 4)
252254
u8 sl_flags;
253255
char sl_data[];
254256
};
@@ -321,7 +323,6 @@ struct nfsd4_session {
321323
u32 se_cb_slot_avail; /* bitmap of available slots */
322324
u32 se_cb_highest_slot; /* highest slot client wants */
323325
u32 se_cb_prog;
324-
bool se_dead;
325326
struct list_head se_hash; /* hash by sessionid */
326327
struct list_head se_perclnt;
327328
struct nfs4_client *se_client;
@@ -331,6 +332,9 @@ struct nfsd4_session {
331332
struct list_head se_conns;
332333
u32 se_cb_seq_nr[NFSD_BC_SLOT_TABLE_SIZE];
333334
struct xarray se_slots; /* forward channel slots */
335+
u16 se_slot_gen;
336+
bool se_dead;
337+
u32 se_target_maxslots;
334338
};
335339

336340
/* formatted contents of nfs4_sessionid */

fs/nfsd/xdr4.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -576,9 +576,7 @@ struct nfsd4_sequence {
576576
u32 slotid; /* request/response */
577577
u32 maxslots; /* request/response */
578578
u32 cachethis; /* request */
579-
#if 0
580579
u32 target_maxslots; /* response */
581-
#endif /* not yet */
582580
u32 status_flags; /* response */
583581
};
584582

0 commit comments

Comments
 (0)