type: u32
enum: cache-type
enum-as-flags: true
+ -
+ name: unlock-ip
+ attributes:
+ -
+ name: address
+ type: binary
+ doc: struct sockaddr_in or struct sockaddr_in6.
+ checks:
+ min-len: 16
operations:
list:
request:
attributes:
- mask
+ -
+ name: unlock-ip
+ doc: release NLM locks held by an IP address
+ attribute-set: unlock-ip
+ flags: [admin-perm]
+ do:
+ request:
+ attributes:
+ - address
mcast-groups:
list:
[NFSD_A_CACHE_FLUSH_MASK] = NLA_POLICY_MASK(NLA_U32, 0x3),
};
+/* NFSD_CMD_UNLOCK_IP - do */
+static const struct nla_policy nfsd_unlock_ip_nl_policy[NFSD_A_UNLOCK_IP_ADDRESS + 1] = {
+ [NFSD_A_UNLOCK_IP_ADDRESS] = NLA_POLICY_MIN_LEN(16),
+};
+
/* Ops table for nfsd */
static const struct genl_split_ops nfsd_nl_ops[] = {
{
.maxattr = NFSD_A_CACHE_FLUSH_MASK,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
+ {
+ .cmd = NFSD_CMD_UNLOCK_IP,
+ .doit = nfsd_nl_unlock_ip_doit,
+ .policy = nfsd_unlock_ip_nl_policy,
+ .maxattr = NFSD_A_UNLOCK_IP_ADDRESS,
+ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
+ },
};
static const struct genl_multicast_group nfsd_nl_mcgrps[] = {
struct netlink_callback *cb);
int nfsd_nl_expkey_set_reqs_doit(struct sk_buff *skb, struct genl_info *info);
int nfsd_nl_cache_flush_doit(struct sk_buff *skb, struct genl_info *info);
+int nfsd_nl_unlock_ip_doit(struct sk_buff *skb, struct genl_info *info);
enum {
NFSD_NLGRP_NONE,
if (rpc_pton(net, fo_path, size, sap, salen) == 0)
return -EINVAL;
- trace_nfsd_ctl_unlock_ip(net, buf);
+ trace_nfsd_ctl_unlock_ip(net, sap, svc_addr_len(sap));
return nlmsvc_unlock_all_by_ip(sap);
}
NFSD_NLGRP_EXPORTD, GFP_KERNEL);
}
+/**
+ * nfsd_nl_unlock_ip_doit - release NLM locks held by an IP address
+ * @skb: reply buffer
+ * @info: netlink metadata and command arguments
+ *
+ * Return: 0 on success or a negative errno.
+ */
+int nfsd_nl_unlock_ip_doit(struct sk_buff *skb, struct genl_info *info)
+{
+ struct sockaddr *sap;
+
+ if (GENL_REQ_ATTR_CHECK(info, NFSD_A_UNLOCK_IP_ADDRESS))
+ return -EINVAL;
+ sap = nla_data(info->attrs[NFSD_A_UNLOCK_IP_ADDRESS]);
+ switch (sap->sa_family) {
+ case AF_INET:
+ if (nla_len(info->attrs[NFSD_A_UNLOCK_IP_ADDRESS]) <
+ sizeof(struct sockaddr_in))
+ return -EINVAL;
+ break;
+ case AF_INET6:
+ if (nla_len(info->attrs[NFSD_A_UNLOCK_IP_ADDRESS]) <
+ sizeof(struct sockaddr_in6))
+ return -EINVAL;
+ break;
+ default:
+ return -EAFNOSUPPORT;
+ }
+ /*
+ * nlmsvc_unlock_all_by_ip() releases matching locks
+ * across all network namespaces because lockd operates
+ * a single global instance.
+ */
+ trace_nfsd_ctl_unlock_ip(genl_info_net(info), sap,
+ svc_addr_len(sap));
+ return nlmsvc_unlock_all_by_ip(sap);
+}
+
/**
* nfsd_net_init - Prepare the nfsd_net portion of a new net namespace
* @net: a freshly-created network namespace
TRACE_EVENT(nfsd_ctl_unlock_ip,
TP_PROTO(
const struct net *net,
- const char *address
+ const struct sockaddr *addr,
+ const unsigned int addrlen
),
- TP_ARGS(net, address),
+ TP_ARGS(net, addr, addrlen),
TP_STRUCT__entry(
__field(unsigned int, netns_ino)
- __string(address, address)
+ __sockaddr(addr, addrlen)
),
TP_fast_assign(
__entry->netns_ino = net->ns.inum;
- __assign_str(address);
+ __assign_sockaddr(addr, addr, addrlen);
),
- TP_printk("address=%s",
- __get_str(address)
+ TP_printk("addr=%pISpc",
+ __get_sockaddr(addr)
)
);
NFSD_A_CACHE_FLUSH_MAX = (__NFSD_A_CACHE_FLUSH_MAX - 1)
};
+enum {
+ NFSD_A_UNLOCK_IP_ADDRESS = 1,
+
+ __NFSD_A_UNLOCK_IP_MAX,
+ NFSD_A_UNLOCK_IP_MAX = (__NFSD_A_UNLOCK_IP_MAX - 1)
+};
+
enum {
NFSD_CMD_RPC_STATUS_GET = 1,
NFSD_CMD_THREADS_SET,
NFSD_CMD_EXPKEY_GET_REQS,
NFSD_CMD_EXPKEY_SET_REQS,
NFSD_CMD_CACHE_FLUSH,
+ NFSD_CMD_UNLOCK_IP,
__NFSD_CMD_MAX,
NFSD_CMD_MAX = (__NFSD_CMD_MAX - 1)