From: Andy Adamson <andros@xxxxxxxxxx> Session statistics are needed for performance characterisation and debugging session recovery and migration. Only gather forechannel statistics as the backchannel has one session slot. Signed-off-by: Andy Adamson <andros@xxxxxxxxxx> --- fs/nfs/client.c | 120 +++++++++++++++++++++++++++++++++++++++++++++ fs/nfs/nfs4proc.c | 5 ++ include/linux/nfs_fs_sb.h | 3 + 3 files changed, 128 insertions(+), 0 deletions(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 31778f7..9d8c479 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -1815,6 +1815,118 @@ static const struct file_operations nfs_volume_list_fops = { .owner = THIS_MODULE, }; +#ifdef CONFIG_NFS_V4_1 +static int nfs_session_list_open(struct inode *inode, struct file *file); +static void *nfs_session_list_start(struct seq_file *p, loff_t *pos); +static void *nfs_session_list_next(struct seq_file *p, void *v, loff_t *pos); +static void nfs_session_list_stop(struct seq_file *p, void *v); +static int nfs_session_list_show(struct seq_file *m, void *v); + +static const struct seq_operations nfs_session_list_ops = { + .start = nfs_session_list_start, + .next = nfs_session_list_next, + .stop = nfs_session_list_stop, + .show = nfs_session_list_show, +}; + +static const struct file_operations nfs_session_list_fops = { + .open = nfs_session_list_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, + .owner = THIS_MODULE, +}; + +/* + * open "/proc/fs/nfsfs/sessions" which provides a summary of sessions with + * which we're dealing + */ +static int nfs_session_list_open(struct inode *inode, struct file *file) +{ + struct seq_file *m; + int ret; + + ret = seq_open(file, &nfs_session_list_ops); + if (ret < 0) + return ret; + + m = file->private_data; + m->private = PDE(inode)->data; + + return 0; +} + +/* + * set up the iterator to start reading from the nfs_client list and return + * the first item + */ +static void *nfs_session_list_start(struct seq_file *m, loff_t *_pos) +{ + /* lock the list against modification */ + spin_lock(&nfs_client_lock); + return seq_list_start_head(&nfs_client_list, *_pos); +} + +/* + * move to next nfs_client + */ +static void *nfs_session_list_next(struct seq_file *p, void *v, loff_t *pos) +{ + return seq_list_next(v, &nfs_client_list, pos); +} + +/* + * clean up after reading from the nfs_client list + */ +static void nfs_session_list_stop(struct seq_file *p, void *v) +{ + spin_unlock(&nfs_client_lock); +} + +/* + * display a header line followed by a load of call lines + */ +static int nfs_session_list_show(struct seq_file *m, void *v) +{ + struct nfs_client *clp; + struct nfs4_slot_table *tbl; + char sessionid[16]; + + /* display header on line 1 */ + if (v == &nfs_client_list) { + seq_puts(m, "HOSTNAME SESSIONID WAITQ:MAX,CUR" + " SLOTID:MAX,TARGET,HIGHEST \n"); + return 0; + } + + /* display one session per line on subsequent lines */ + clp = list_entry(v, struct nfs_client, cl_share_link); + + /* Check if the nfs_client has a session and is initialized */ + if (!clp->cl_session || clp->cl_cons_state != NFS_CS_READY) + return 0; + + snprintf(sessionid, 16, "%x:%x:%x:%x", + ((u32 *)&clp->cl_session->sess_id.data)[0], + ((u32 *)&clp->cl_session->sess_id.data)[1], + ((u32 *)&clp->cl_session->sess_id.data)[2], + ((u32 *)&clp->cl_session->sess_id.data)[3]); + + tbl = &clp->cl_session->fc_slot_table; + spin_lock(&tbl->slot_tbl_lock); + seq_printf(m, "%s %-16s %u, %u %d, %d, %d\n", + clp->cl_hostname, + sessionid, + tbl->max_qlen, + tbl->qlen, + tbl->max_slots = 1, + tbl->target_max_slots, + tbl->highest_used_slotid); + spin_unlock(&tbl->slot_tbl_lock); + return 0; +} +#endif /* CONFIG_NFS_V4_1 */ + /* * open "/proc/fs/nfsfs/servers" which provides a summary of servers with which * we're dealing @@ -1992,6 +2104,14 @@ int __init nfs_fs_proc_init(void) proc_fs_nfs, &nfs_volume_list_fops); if (!p) goto error_2; + +#ifdef CONFIG_NFS_V4_1 + /* a file of sessions that we are using */ + p = proc_create("sessions", S_IFREG|S_IRUGO, + proc_fs_nfs, &nfs_session_list_fops); + if (!p) + goto error_2; +#endif /* CONFIG_NFS_V4_1 */ return 0; error_2: diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 17b3d0b..1419e1e 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -692,6 +692,11 @@ int nfs41_setup_sequence(struct nfs4_session *session, tbl = &session->fc_slot_table; spin_lock(&tbl->slot_tbl_lock); + + /* Gather stats */ + tbl->max_qlen = max(tbl->max_qlen, tbl->slot_tbl_waitq.qlen); + tbl->qlen = tbl->slot_tbl_waitq.qlen; + if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) && !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { /* The state manager will wait until the slot table is empty */ diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index a091dc1..5c04d42 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -207,6 +207,9 @@ struct nfs4_slot_table { int target_max_slots; /* Set by CB_RECALL_SLOT as * the new max_slots */ struct completion complete; + /* For session statistics */ + unsigned short max_qlen; /* max waitq qlen */ + unsigned short qlen; /* current waitq qlen */ }; /* -- 1.7.6.4 -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html