From 64446a66feadac472d4f073eadc245a4de8bc1b6 Mon Sep 17 00:00:00 2001 From: Marek Becka Date: Sun, 9 Feb 2014 22:14:44 +0100 Subject: [PATCH] Added nfs4 support for linux --- src/nfs.c | 321 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 307 insertions(+), 14 deletions(-) diff --git a/src/nfs.c b/src/nfs.c index f5b579e1..ac211655 100644 --- a/src/nfs.c +++ b/src/nfs.c @@ -171,6 +171,160 @@ static const char *nfs4_procedures_names[] = static size_t nfs4_procedures_names_num = STATIC_ARRAY_SIZE (nfs4_procedures_names); #endif +#if KERNEL_LINUX +static const char *nfs4_server40_procedures_names[] = +{ + "null", + "compound", + "reserved", + "access", + "close", + "commit", + "create", + "delegpurge", + "delegreturn", + "getattr", + "getfh", + "link", + "lock", + "lockt", + "locku", + "lookup", + "lookupp", + "nverify", + "open", + "openattr", + "open_confirm", + "open_downgrade", + "putfh", + "putpubfh", + "putrootfh", + "read", + "readdir", + "readlink", + "remove", + "rename", + "renew", + "restorefh", + "savefh", + "secinfo", + "setattr", + "setclientid", + "setcltid_confirm", + "verify", + "write", + "release_lockowner" +}; + +static size_t nfs4_server40_procedures_names_num = STATIC_ARRAY_SIZE (nfs4_server40_procedures_names); + +static const char *nfs4_server41_procedures_names[] = +{ + "backchannel_ctl", + "bind_conn_to_session", + "exchange_id", + "create_session", + "destroy_session", + "free_stateid", + "get_dir_delegation", + "getdeviceinfo", + "getdevicelist", + "layoutcommit", + "layoutget", + "layoutreturn", + "secinfo_no_name", + "sequence", + "set_ssv", + "test_stateid", + "want_delegation", + "destroy_clientid", + "reclaim_complete", +}; + +static size_t nfs4_server41_procedures_names_num = STATIC_ARRAY_SIZE (nfs4_server41_procedures_names); + +#define NFS4_SERVER40_NUM_PROC ( \ + STATIC_ARRAY_SIZE (nfs4_server40_procedures_names) ) + +#define NFS4_SERVER41_NUM_PROC ( \ + STATIC_ARRAY_SIZE (nfs4_server40_procedures_names) + \ + STATIC_ARRAY_SIZE (nfs4_server41_procedures_names) ) + +#define NFS4_SERVER_MAX_PROC (NFS4_SERVER41_NUM_PROC) + +static const char *nfs4_client40_procedures_names[] = +{ + "null", + "read", + "write", + "commit", + "open", + "open_confirm", + "open_noattr", + "open_downgrade", + "close", + "setattr", + "fsinfo", + "renew", + "setclientid", + "setclientid_confirm", + "lock", + "lockt", + "locku", + "access", + "getattr", + "lookup", + "lookupp", + "remove", + "rename", + "link", + "symlink", + "create", + "pathconf", + "statfs", + "readlink", + "readdir", + "server_caps", + "delegreturn", + "getacl", + "setacl", + "fs_locations", /* |35| 2.6.18 */ + "release_lockowner", /* |42| 2.6.36 */ + "secinfo", /* |46| 2.6.39 */ + "fsid_present" /* |54| 3.13 */ +}; + +static const char *nfs4_client41_procedures_names[] = +{ + "exchange_id", /* |40| 3.6.30 */ + "create_session", /* |40| 3.6.30 */ + "destroy_session", /* |40| 3.6.30 */ + "sequence", /* |40| 3.6.30 */ + "get_lease_time", /* |40| 3.6.30 */ + "reclaim_complete", /* |41| 2.6.33 */ + "layoutget", /* |44| 2.6.37 */ + "getdeviceinfo", /* |44| 2.6.37 */ + "layoutcommit", /* |46| 2.6.39 */ + "layoutreturn", /* |47| 3.0 */ + "secinfo_no_name", /* |51| 3.1 */ + "test_stateid", /* |51| 3.1 */ + "free_stateid", /* |51| 3.1 */ + "getdevicelist", /* |51| 3.1 */ + "bind_conn_to_session", /* |53| 3.5 */ + "destroy_clientid" /* |53| 3.5 */ +}; + +#define NFS4_CLIENT40_NUM_PROC ( \ + STATIC_ARRAY_SIZE (nfs4_client40_procedures_names) ) + +#define NFS4_CLIENT41_NUM_PROC ( \ + STATIC_ARRAY_SIZE (nfs4_client40_procedures_names) + \ + STATIC_ARRAY_SIZE (nfs4_client41_procedures_names) ) + +#define NFS4_CLIENT_MAX_PROC (NFS4_CLIENT41_NUM_PROC) + +#endif + #if HAVE_LIBKSTAT extern kstat_ctl_t *kc; static kstat_t *nfs2_ksp_client; @@ -181,8 +335,6 @@ static kstat_t *nfs4_ksp_client; static kstat_t *nfs4_ksp_server; #endif -/* Possibly TODO: NFSv4 statistics */ - #if KERNEL_LINUX static int nfs_init (void) { @@ -252,14 +404,27 @@ static void nfs_procedures_submit (const char *plugin_instance, } /* void nfs_procedures_submit */ #if KERNEL_LINUX -static int nfs_submit_fields (int nfs_version, const char *instance, - char **fields, size_t fields_num, - const char **proc_names, size_t proc_names_num) +static void nfs_submit_fields (int nfs_version, const char *instance, + char **fields, size_t fields_num, const char **proc_names) { char plugin_instance[DATA_MAX_NAME_LEN]; value_t values[fields_num]; size_t i; + ssnprintf (plugin_instance, sizeof (plugin_instance), "v%i%s", + nfs_version, instance); + + for (i = 0; i < fields_num; i++) + (void) parse_value (fields[i], &values[i], DS_TYPE_DERIVE); + + nfs_procedures_submit (plugin_instance, proc_names, values, + fields_num); +} + +static int nfs_submit_fields_safe (int nfs_version, const char *instance, + char **fields, size_t fields_num, + const char **proc_names, size_t proc_names_num) +{ if (fields_num != proc_names_num) { WARNING ("nfs plugin: Wrong number of fields for " @@ -269,14 +434,130 @@ static int nfs_submit_fields (int nfs_version, const char *instance, return (EINVAL); } - ssnprintf (plugin_instance, sizeof (plugin_instance), "v%i%s", - nfs_version, instance); + nfs_submit_fields (nfs_version, instance, fields, fields_num, + proc_names); - for (i = 0; i < proc_names_num; i++) - (void) parse_value (fields[i], &values[i], DS_TYPE_DERIVE); + return (0); +} - nfs_procedures_submit (plugin_instance, proc_names, values, - proc_names_num); +static int nfs_submit_nfs4_server (const char *instance, char **fields, + size_t fields_num) +{ + static int suppress_warning = 0; + + if (fields_num != NFS4_SERVER40_NUM_PROC && + fields_num != NFS4_SERVER41_NUM_PROC) + { + if (!suppress_warning) + { + WARNING ("nfs plugin: Unexpected number of fields for " + "NFSv4 %s statistics: %zu. ", + instance, fields_num); + } + + if (fields_num > NFS4_SERVER_MAX_PROC) + { + fields_num = NFS4_SERVER_MAX_PROC; + suppress_warning = 1; + } + else + { + return (EINVAL); + } + } + + nfs_submit_fields (4, instance, fields, + nfs4_server40_procedures_names_num, + nfs4_server40_procedures_names); + + if (fields_num >= NFS4_SERVER41_NUM_PROC) + { + fields += nfs4_server40_procedures_names_num; + + nfs_submit_fields (4, instance, fields, + nfs4_server41_procedures_names_num, + nfs4_server41_procedures_names); + } + + return (0); +} + +static int nfs_submit_nfs4_client (const char *instance, char **fields, + size_t fields_num) +{ + size_t proc40_names_num, proc41_names_num; + + static int suppress_warning = 0; + + switch (fields_num) + { + case 34: + proc40_names_num = 34; + break; + case 35: + proc40_names_num = 35; + break; + case 40: + proc40_names_num = 35; + break; + case 41: + proc40_names_num = 35; + break; + case 42: + proc40_names_num = 36; + break; + case 44: + proc40_names_num = 36; + break; + case 46: + proc40_names_num = 36; + break; + case 47: + proc40_names_num = 36; + break; + case 51: + proc40_names_num = 36; + break; + case 53: + proc40_names_num = 36; + break; + case 54: + proc40_names_num = 37; + break; + default: + if (!suppress_warning) + { + WARNING ("nfs plugin: Unexpected number of " + "fields for NFSv4 %s " + "statistics: %zu. ", + instance, fields_num); + } + + if (fields_num > 34) + { + /* safe fallback to basic nfs40 procedures */ + fields_num = 34; + proc40_names_num = 34; + + suppress_warning = 1; + } + else + { + return (EINVAL); + } + } + + nfs_submit_fields (4, instance, fields, proc40_names_num, + nfs4_client40_procedures_names); + + if (fields_num > proc40_names_num) + { + proc41_names_num = fields_num - proc40_names_num; + fields += proc40_names_num; + + nfs_submit_fields (4, instance, fields,proc41_names_num, + nfs4_client41_procedures_names); + } return (0); } @@ -285,7 +566,7 @@ static void nfs_read_linux (FILE *fh, char *inst) { char buffer[1024]; - char *fields[48]; + char *fields[64]; int fields_num = 0; if (fh == NULL) @@ -301,18 +582,30 @@ static void nfs_read_linux (FILE *fh, char *inst) if (strcmp (fields[0], "proc2") == 0) { - nfs_submit_fields (/* version = */ 2, inst, + nfs_submit_fields_safe (/* version = */ 2, inst, fields + 2, (size_t) (fields_num - 2), nfs2_procedures_names, nfs2_procedures_names_num); } else if (strncmp (fields[0], "proc3", 5) == 0) { - nfs_submit_fields (/* version = */ 3, inst, + nfs_submit_fields_safe (/* version = */ 3, inst, fields + 2, (size_t) (fields_num - 2), nfs3_procedures_names, nfs3_procedures_names_num); } + else if (strcmp (fields[0], "proc4ops") == 0) + { + if (inst[0] == 's') + nfs_submit_nfs4_server (inst, fields + 2, + (size_t) (fields_num - 2)); + } + else if (strcmp (fields[0], "proc4") == 0) + { + if (inst[0] == 'c') + nfs_submit_nfs4_client (inst, fields + 2, + (size_t) (fields_num - 2)); + } } /* while (fgets) */ } /* void nfs_read_linux */ #endif /* KERNEL_LINUX */ -- 2.11.0