@@ -1496,19 +1496,200 @@ static int create_proc_exports_entry(void)
14961496
14971497unsigned int nfsd_net_id ;
14981498
1499+ /**
1500+ * nfsd_nl_rpc_status_get_start - Prepare rpc_status_get dumpit
1501+ * @cb: netlink metadata and command arguments
1502+ *
1503+ * Return values:
1504+ * %0: The rpc_status_get command may proceed
1505+ * %-ENODEV: There is no NFSD running in this namespace
1506+ */
14991507int nfsd_nl_rpc_status_get_start (struct netlink_callback * cb )
15001508{
1509+ struct nfsd_net * nn = net_generic (sock_net (cb -> skb -> sk ), nfsd_net_id );
1510+ int ret = - ENODEV ;
1511+
1512+ mutex_lock (& nfsd_mutex );
1513+ if (nn -> nfsd_serv ) {
1514+ svc_get (nn -> nfsd_serv );
1515+ ret = 0 ;
1516+ }
1517+ mutex_unlock (& nfsd_mutex );
1518+
1519+ return ret ;
1520+ }
1521+
1522+ static int nfsd_genl_rpc_status_compose_msg (struct sk_buff * skb ,
1523+ struct netlink_callback * cb ,
1524+ struct nfsd_genl_rqstp * rqstp )
1525+ {
1526+ void * hdr ;
1527+ u32 i ;
1528+
1529+ hdr = genlmsg_put (skb , NETLINK_CB (cb -> skb ).portid , cb -> nlh -> nlmsg_seq ,
1530+ & nfsd_nl_family , 0 , NFSD_CMD_RPC_STATUS_GET );
1531+ if (!hdr )
1532+ return - ENOBUFS ;
1533+
1534+ if (nla_put_be32 (skb , NFSD_A_RPC_STATUS_XID , rqstp -> rq_xid ) ||
1535+ nla_put_u32 (skb , NFSD_A_RPC_STATUS_FLAGS , rqstp -> rq_flags ) ||
1536+ nla_put_u32 (skb , NFSD_A_RPC_STATUS_PROG , rqstp -> rq_prog ) ||
1537+ nla_put_u32 (skb , NFSD_A_RPC_STATUS_PROC , rqstp -> rq_proc ) ||
1538+ nla_put_u8 (skb , NFSD_A_RPC_STATUS_VERSION , rqstp -> rq_vers ) ||
1539+ nla_put_s64 (skb , NFSD_A_RPC_STATUS_SERVICE_TIME ,
1540+ ktime_to_us (rqstp -> rq_stime ),
1541+ NFSD_A_RPC_STATUS_PAD ))
1542+ return - ENOBUFS ;
1543+
1544+ switch (rqstp -> rq_saddr .sa_family ) {
1545+ case AF_INET : {
1546+ const struct sockaddr_in * s_in , * d_in ;
1547+
1548+ s_in = (const struct sockaddr_in * )& rqstp -> rq_saddr ;
1549+ d_in = (const struct sockaddr_in * )& rqstp -> rq_daddr ;
1550+ if (nla_put_in_addr (skb , NFSD_A_RPC_STATUS_SADDR4 ,
1551+ s_in -> sin_addr .s_addr ) ||
1552+ nla_put_in_addr (skb , NFSD_A_RPC_STATUS_DADDR4 ,
1553+ d_in -> sin_addr .s_addr ) ||
1554+ nla_put_be16 (skb , NFSD_A_RPC_STATUS_SPORT ,
1555+ s_in -> sin_port ) ||
1556+ nla_put_be16 (skb , NFSD_A_RPC_STATUS_DPORT ,
1557+ d_in -> sin_port ))
1558+ return - ENOBUFS ;
1559+ break ;
1560+ }
1561+ case AF_INET6 : {
1562+ const struct sockaddr_in6 * s_in , * d_in ;
1563+
1564+ s_in = (const struct sockaddr_in6 * )& rqstp -> rq_saddr ;
1565+ d_in = (const struct sockaddr_in6 * )& rqstp -> rq_daddr ;
1566+ if (nla_put_in6_addr (skb , NFSD_A_RPC_STATUS_SADDR6 ,
1567+ & s_in -> sin6_addr ) ||
1568+ nla_put_in6_addr (skb , NFSD_A_RPC_STATUS_DADDR6 ,
1569+ & d_in -> sin6_addr ) ||
1570+ nla_put_be16 (skb , NFSD_A_RPC_STATUS_SPORT ,
1571+ s_in -> sin6_port ) ||
1572+ nla_put_be16 (skb , NFSD_A_RPC_STATUS_DPORT ,
1573+ d_in -> sin6_port ))
1574+ return - ENOBUFS ;
1575+ break ;
1576+ }
1577+ }
1578+
1579+ for (i = 0 ; i < rqstp -> rq_opcnt ; i ++ )
1580+ if (nla_put_u32 (skb , NFSD_A_RPC_STATUS_COMPOUND_OPS ,
1581+ rqstp -> rq_opnum [i ]))
1582+ return - ENOBUFS ;
1583+
1584+ genlmsg_end (skb , hdr );
15011585 return 0 ;
15021586}
15031587
1588+ /**
1589+ * nfsd_nl_rpc_status_get_dumpit - Handle rpc_status_get dumpit
1590+ * @skb: reply buffer
1591+ * @cb: netlink metadata and command arguments
1592+ *
1593+ * Returns the size of the reply or a negative errno.
1594+ */
15041595int nfsd_nl_rpc_status_get_dumpit (struct sk_buff * skb ,
15051596 struct netlink_callback * cb )
15061597{
1507- return 0 ;
1598+ struct nfsd_net * nn = net_generic (sock_net (skb -> sk ), nfsd_net_id );
1599+ int i , ret , rqstp_index = 0 ;
1600+
1601+ rcu_read_lock ();
1602+
1603+ for (i = 0 ; i < nn -> nfsd_serv -> sv_nrpools ; i ++ ) {
1604+ struct svc_rqst * rqstp ;
1605+
1606+ if (i < cb -> args [0 ]) /* already consumed */
1607+ continue ;
1608+
1609+ rqstp_index = 0 ;
1610+ list_for_each_entry_rcu (rqstp ,
1611+ & nn -> nfsd_serv -> sv_pools [i ].sp_all_threads ,
1612+ rq_all ) {
1613+ struct nfsd_genl_rqstp genl_rqstp ;
1614+ unsigned int status_counter ;
1615+
1616+ if (rqstp_index ++ < cb -> args [1 ]) /* already consumed */
1617+ continue ;
1618+ /*
1619+ * Acquire rq_status_counter before parsing the rqst
1620+ * fields. rq_status_counter is set to an odd value in
1621+ * order to notify the consumers the rqstp fields are
1622+ * meaningful.
1623+ */
1624+ status_counter =
1625+ smp_load_acquire (& rqstp -> rq_status_counter );
1626+ if (!(status_counter & 1 ))
1627+ continue ;
1628+
1629+ genl_rqstp .rq_xid = rqstp -> rq_xid ;
1630+ genl_rqstp .rq_flags = rqstp -> rq_flags ;
1631+ genl_rqstp .rq_vers = rqstp -> rq_vers ;
1632+ genl_rqstp .rq_prog = rqstp -> rq_prog ;
1633+ genl_rqstp .rq_proc = rqstp -> rq_proc ;
1634+ genl_rqstp .rq_stime = rqstp -> rq_stime ;
1635+ genl_rqstp .rq_opcnt = 0 ;
1636+ memcpy (& genl_rqstp .rq_daddr , svc_daddr (rqstp ),
1637+ sizeof (struct sockaddr ));
1638+ memcpy (& genl_rqstp .rq_saddr , svc_addr (rqstp ),
1639+ sizeof (struct sockaddr ));
1640+
1641+ #ifdef CONFIG_NFSD_V4
1642+ if (rqstp -> rq_vers == NFS4_VERSION &&
1643+ rqstp -> rq_proc == NFSPROC4_COMPOUND ) {
1644+ /* NFSv4 compound */
1645+ struct nfsd4_compoundargs * args ;
1646+ int j ;
1647+
1648+ args = rqstp -> rq_argp ;
1649+ genl_rqstp .rq_opcnt = args -> opcnt ;
1650+ for (j = 0 ; j < genl_rqstp .rq_opcnt ; j ++ )
1651+ genl_rqstp .rq_opnum [j ] =
1652+ args -> ops [j ].opnum ;
1653+ }
1654+ #endif /* CONFIG_NFSD_V4 */
1655+
1656+ /*
1657+ * Acquire rq_status_counter before reporting the rqst
1658+ * fields to the user.
1659+ */
1660+ if (smp_load_acquire (& rqstp -> rq_status_counter ) !=
1661+ status_counter )
1662+ continue ;
1663+
1664+ ret = nfsd_genl_rpc_status_compose_msg (skb , cb ,
1665+ & genl_rqstp );
1666+ if (ret )
1667+ goto out ;
1668+ }
1669+ }
1670+
1671+ cb -> args [0 ] = i ;
1672+ cb -> args [1 ] = rqstp_index ;
1673+ ret = skb -> len ;
1674+ out :
1675+ rcu_read_unlock ();
1676+
1677+ return ret ;
15081678}
15091679
1680+ /**
1681+ * nfsd_nl_rpc_status_get_done - rpc_status_get dumpit post-processing
1682+ * @cb: netlink metadata and command arguments
1683+ *
1684+ * Return values:
1685+ * %0: Success
1686+ */
15101687int nfsd_nl_rpc_status_get_done (struct netlink_callback * cb )
15111688{
1689+ mutex_lock (& nfsd_mutex );
1690+ nfsd_put (sock_net (cb -> skb -> sk ));
1691+ mutex_unlock (& nfsd_mutex );
1692+
15121693 return 0 ;
15131694}
15141695
@@ -1606,6 +1787,10 @@ static int __init init_nfsd(void)
16061787 retval = register_filesystem (& nfsd_fs_type );
16071788 if (retval )
16081789 goto out_free_all ;
1790+ retval = genl_register_family (& nfsd_nl_family );
1791+ if (retval )
1792+ goto out_free_all ;
1793+
16091794 return 0 ;
16101795out_free_all :
16111796 nfsd4_destroy_laundry_wq ();
@@ -1630,6 +1815,7 @@ static int __init init_nfsd(void)
16301815
16311816static void __exit exit_nfsd (void )
16321817{
1818+ genl_unregister_family (& nfsd_nl_family );
16331819 unregister_filesystem (& nfsd_fs_type );
16341820 nfsd4_destroy_laundry_wq ();
16351821 unregister_cld_notifier ();
0 commit comments