Skip to content

Commit

Permalink
Merge branch 'nfs-for-2.6.34' of git://git.linux-nfs.org/projects/tro…
Browse files Browse the repository at this point in the history
…ndmy/nfs-2.6

* 'nfs-for-2.6.34' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6: (44 commits)
  NFS: Remove requirement for inode->i_mutex from nfs_invalidate_mapping
  NFS: Clean up nfs_sync_mapping
  NFS: Simplify nfs_wb_page()
  NFS: Replace __nfs_write_mapping with sync_inode()
  NFS: Simplify nfs_wb_page_cancel()
  NFS: Ensure inode is always marked I_DIRTY_DATASYNC, if it has unstable pages
  NFS: Run COMMIT as an asynchronous RPC call when wbc->for_background is set
  NFS: Reduce the number of unnecessary COMMIT calls
  NFS: Add a count of the number of unstable writes carried by an inode
  NFS: Cleanup - move nfs_write_inode() into fs/nfs/write.c
  nfs41 fix NFS4ERR_CLID_INUSE for exchange id
  NFS: Fix an allocation-under-spinlock bug
  SUNRPC: Handle EINVAL error returns from the TCP connect operation
  NFSv4.1: Various fixes to the sequence flag error handling
  nfs4: renewd renew operations should take/put a client reference
  nfs41: renewd sequence operations should take/put client reference
  nfs: prevent backlogging of renewd requests
  nfs: kill renewd before clearing client minor version
  NFS: Make close(2) asynchronous when closing NFS O_DIRECT files
  NFS: Improve NFS iostat byte count accuracy for writes
  ...
  • Loading branch information
torvalds committed Mar 5, 2010
2 parents b13d3c6 + 3fa04ec commit cc7889f
Show file tree
Hide file tree
Showing 24 changed files with 642 additions and 443 deletions.
8 changes: 8 additions & 0 deletions fs/nfs/callback.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ struct cb_recallanyargs {
};

extern unsigned nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy);

struct cb_recallslotargs {
struct sockaddr *crsa_addr;
uint32_t crsa_target_max_slots;
};
extern unsigned nfs4_callback_recallslot(struct cb_recallslotargs *args,
void *dummy);

#endif /* CONFIG_NFS_V4_1 */

extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res);
Expand Down
165 changes: 137 additions & 28 deletions fs/nfs/callback_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,44 +143,49 @@ int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const n
* Return success if the sequenceID is one more than what we last saw on
* this slot, accounting for wraparound. Increments the slot's sequence.
*
* We don't yet implement a duplicate request cache, so at this time
* we will log replays, and process them as if we had not seen them before,
* but we don't bump the sequence in the slot. Not too worried about it,
* We don't yet implement a duplicate request cache, instead we set the
* back channel ca_maxresponsesize_cached to zero. This is OK for now
* since we only currently implement idempotent callbacks anyway.
*
* We have a single slot backchannel at this time, so we don't bother
* checking the used_slots bit array on the table. The lower layer guarantees
* a single outstanding callback request at a time.
*/
static int
validate_seqid(struct nfs4_slot_table *tbl, u32 slotid, u32 seqid)
static __be32
validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args)
{
struct nfs4_slot *slot;

dprintk("%s enter. slotid %d seqid %d\n",
__func__, slotid, seqid);
__func__, args->csa_slotid, args->csa_sequenceid);

if (slotid > NFS41_BC_MAX_CALLBACKS)
if (args->csa_slotid > NFS41_BC_MAX_CALLBACKS)
return htonl(NFS4ERR_BADSLOT);

slot = tbl->slots + slotid;
slot = tbl->slots + args->csa_slotid;
dprintk("%s slot table seqid: %d\n", __func__, slot->seq_nr);

/* Normal */
if (likely(seqid == slot->seq_nr + 1)) {
if (likely(args->csa_sequenceid == slot->seq_nr + 1)) {
slot->seq_nr++;
return htonl(NFS4_OK);
}

/* Replay */
if (seqid == slot->seq_nr) {
dprintk("%s seqid %d is a replay - no DRC available\n",
__func__, seqid);
return htonl(NFS4_OK);
if (args->csa_sequenceid == slot->seq_nr) {
dprintk("%s seqid %d is a replay\n",
__func__, args->csa_sequenceid);
/* Signal process_op to set this error on next op */
if (args->csa_cachethis == 0)
return htonl(NFS4ERR_RETRY_UNCACHED_REP);

/* The ca_maxresponsesize_cached is 0 with no DRC */
else if (args->csa_cachethis == 1)
return htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE);
}

/* Wraparound */
if (seqid == 1 && (slot->seq_nr + 1) == 0) {
if (args->csa_sequenceid == 1 && (slot->seq_nr + 1) == 0) {
slot->seq_nr = 1;
return htonl(NFS4_OK);
}
Expand Down Expand Up @@ -225,27 +230,87 @@ validate_seqid(struct nfs4_slot_table *tbl, u32 slotid, u32 seqid)
return NULL;
}

/* FIXME: referring calls should be processed */
unsigned nfs4_callback_sequence(struct cb_sequenceargs *args,
/*
* For each referring call triple, check the session's slot table for
* a match. If the slot is in use and the sequence numbers match, the
* client is still waiting for a response to the original request.
*/
static bool referring_call_exists(struct nfs_client *clp,
uint32_t nrclists,
struct referring_call_list *rclists)
{
bool status = 0;
int i, j;
struct nfs4_session *session;
struct nfs4_slot_table *tbl;
struct referring_call_list *rclist;
struct referring_call *ref;

/*
* XXX When client trunking is implemented, this becomes
* a session lookup from within the loop
*/
session = clp->cl_session;
tbl = &session->fc_slot_table;

for (i = 0; i < nrclists; i++) {
rclist = &rclists[i];
if (memcmp(session->sess_id.data,
rclist->rcl_sessionid.data,
NFS4_MAX_SESSIONID_LEN) != 0)
continue;

for (j = 0; j < rclist->rcl_nrefcalls; j++) {
ref = &rclist->rcl_refcalls[j];

dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u "
"slotid %u\n", __func__,
((u32 *)&rclist->rcl_sessionid.data)[0],
((u32 *)&rclist->rcl_sessionid.data)[1],
((u32 *)&rclist->rcl_sessionid.data)[2],
((u32 *)&rclist->rcl_sessionid.data)[3],
ref->rc_sequenceid, ref->rc_slotid);

spin_lock(&tbl->slot_tbl_lock);
status = (test_bit(ref->rc_slotid, tbl->used_slots) &&
tbl->slots[ref->rc_slotid].seq_nr ==
ref->rc_sequenceid);
spin_unlock(&tbl->slot_tbl_lock);
if (status)
goto out;
}
}

out:
return status;
}

__be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
struct cb_sequenceres *res)
{
struct nfs_client *clp;
int i, status;

for (i = 0; i < args->csa_nrclists; i++)
kfree(args->csa_rclists[i].rcl_refcalls);
kfree(args->csa_rclists);
int i;
__be32 status;

status = htonl(NFS4ERR_BADSESSION);
clp = find_client_with_session(args->csa_addr, 4, &args->csa_sessionid);
if (clp == NULL)
goto out;

status = validate_seqid(&clp->cl_session->bc_slot_table,
args->csa_slotid, args->csa_sequenceid);
status = validate_seqid(&clp->cl_session->bc_slot_table, args);
if (status)
goto out_putclient;

/*
* Check for pending referring calls. If a match is found, a
* related callback was received before the response to the original
* call.
*/
if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists)) {
status = htonl(NFS4ERR_DELAY);
goto out_putclient;
}

memcpy(&res->csr_sessionid, &args->csa_sessionid,
sizeof(res->csr_sessionid));
res->csr_sequenceid = args->csa_sequenceid;
Expand All @@ -256,15 +321,23 @@ unsigned nfs4_callback_sequence(struct cb_sequenceargs *args,
out_putclient:
nfs_put_client(clp);
out:
dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
res->csr_status = status;
return res->csr_status;
for (i = 0; i < args->csa_nrclists; i++)
kfree(args->csa_rclists[i].rcl_refcalls);
kfree(args->csa_rclists);

if (status == htonl(NFS4ERR_RETRY_UNCACHED_REP))
res->csr_status = 0;
else
res->csr_status = status;
dprintk("%s: exit with status = %d res->csr_status %d\n", __func__,
ntohl(status), ntohl(res->csr_status));
return status;
}

unsigned nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy)
__be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy)
{
struct nfs_client *clp;
int status;
__be32 status;
fmode_t flags = 0;

status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
Expand All @@ -289,4 +362,40 @@ unsigned nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy)
dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
return status;
}

/* Reduce the fore channel's max_slots to the target value */
__be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy)
{
struct nfs_client *clp;
struct nfs4_slot_table *fc_tbl;
__be32 status;

status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
clp = nfs_find_client(args->crsa_addr, 4);
if (clp == NULL)
goto out;

dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d\n",
rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR),
args->crsa_target_max_slots);

fc_tbl = &clp->cl_session->fc_slot_table;

status = htonl(NFS4ERR_BAD_HIGH_SLOT);
if (args->crsa_target_max_slots > fc_tbl->max_slots ||
args->crsa_target_max_slots < 1)
goto out_putclient;

status = htonl(NFS4_OK);
if (args->crsa_target_max_slots == fc_tbl->max_slots)
goto out_putclient;

fc_tbl->target_max_slots = args->crsa_target_max_slots;
nfs41_handle_recall_slot(clp);
out_putclient:
nfs_put_client(clp); /* balance nfs_find_client */
out:
dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
return status;
}
#endif /* CONFIG_NFS_V4_1 */
Loading

0 comments on commit cc7889f

Please sign in to comment.