-
name: min-threads
type: u32
+ -
+ name: fh-key
+ type: binary
+ checks:
+ exact-len: 16
-
name: version
attributes:
- leasetime
- scope
- min-threads
+ - fh-key
-
name: threads-get
doc: get the maximum number of running threads
};
/* NFSD_CMD_THREADS_SET - do */
-static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_MIN_THREADS + 1] = {
+static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_FH_KEY + 1] = {
[NFSD_A_SERVER_THREADS] = { .type = NLA_U32, },
[NFSD_A_SERVER_GRACETIME] = { .type = NLA_U32, },
[NFSD_A_SERVER_LEASETIME] = { .type = NLA_U32, },
[NFSD_A_SERVER_SCOPE] = { .type = NLA_NUL_STRING, },
[NFSD_A_SERVER_MIN_THREADS] = { .type = NLA_U32, },
+ [NFSD_A_SERVER_FH_KEY] = NLA_POLICY_EXACT_LEN(16),
};
/* NFSD_CMD_VERSION_SET - do */
.cmd = NFSD_CMD_THREADS_SET,
.doit = nfsd_nl_threads_set_doit,
.policy = nfsd_threads_set_nl_policy,
- .maxattr = NFSD_A_SERVER_MIN_THREADS,
+ .maxattr = NFSD_A_SERVER_FH_KEY,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
{
spinlock_t local_clients_lock;
struct list_head local_clients;
#endif
+ siphash_key_t *fh_key;
};
/* Simple check to find out if a given net was properly initialized */
return ret;
}
+/**
+ * nfsd_nl_fh_key_set - helper to copy fh_key from userspace
+ * @attr: nlattr NFSD_A_SERVER_FH_KEY
+ * @nn: nfsd_net
+ *
+ * Callers should hold nfsd_mutex, returns 0 on success or negative errno.
+ * Callers must ensure the server is shut down (sv_nrthreads == 0),
+ * userspace documentation asserts the key may only be set when the server
+ * is not running.
+ */
+static int nfsd_nl_fh_key_set(const struct nlattr *attr, struct nfsd_net *nn)
+{
+ siphash_key_t *fh_key = nn->fh_key;
+
+ if (!fh_key) {
+ fh_key = kmalloc(sizeof(siphash_key_t), GFP_KERNEL);
+ if (!fh_key)
+ return -ENOMEM;
+ nn->fh_key = fh_key;
+ }
+
+ fh_key->key[0] = get_unaligned_le64(nla_data(attr));
+ fh_key->key[1] = get_unaligned_le64(nla_data(attr) + 8);
+ return 0;
+}
+
/**
* nfsd_nl_threads_set_doit - set the number of running threads
* @skb: reply buffer
if (info->attrs[NFSD_A_SERVER_GRACETIME] ||
info->attrs[NFSD_A_SERVER_LEASETIME] ||
- info->attrs[NFSD_A_SERVER_SCOPE]) {
+ info->attrs[NFSD_A_SERVER_SCOPE] ||
+ info->attrs[NFSD_A_SERVER_FH_KEY]) {
ret = -EBUSY;
if (nn->nfsd_serv && nn->nfsd_serv->sv_nrthreads)
goto out_unlock;
attr = info->attrs[NFSD_A_SERVER_SCOPE];
if (attr)
scope = nla_data(attr);
+
+ attr = info->attrs[NFSD_A_SERVER_FH_KEY];
+ if (attr) {
+ ret = nfsd_nl_fh_key_set(attr, nn);
+ trace_nfsd_ctl_fh_key_set((const char *)nn->fh_key, ret);
+ if (ret)
+ goto out_unlock;
+ }
}
attr = info->attrs[NFSD_A_SERVER_MIN_THREADS];
{
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ kfree_sensitive(nn->fh_key);
nfsd_proc_stat_shutdown(net);
percpu_counter_destroy_many(nn->counter, NFSD_STATS_COUNTERS_NUM);
nfsd_idmap_shutdown(net);
)
);
+TRACE_EVENT(nfsd_ctl_fh_key_set,
+ TP_PROTO(
+ const char *key,
+ int result
+ ),
+ TP_ARGS(key, result),
+ TP_STRUCT__entry(
+ __field(u32, key_hash)
+ __field(int, result)
+ ),
+ TP_fast_assign(
+ if (key)
+ __entry->key_hash = ~crc32_le(0xFFFFFFFF, key, 16);
+ else
+ __entry->key_hash = 0;
+ __entry->result = result;
+ ),
+ TP_printk("key=0x%08x result=%d",
+ __entry->key_hash, __entry->result
+ )
+);
+
DECLARE_EVENT_CLASS(nfsd_copy_class,
TP_PROTO(
const struct nfsd4_copy *copy
NFSD_A_SERVER_LEASETIME,
NFSD_A_SERVER_SCOPE,
NFSD_A_SERVER_MIN_THREADS,
+ NFSD_A_SERVER_FH_KEY,
__NFSD_A_SERVER_MAX,
NFSD_A_SERVER_MAX = (__NFSD_A_SERVER_MAX - 1)