@@ -1496,19 +1496,200 @@ static int create_proc_exports_entry(void)
1496
1496
1497
1497
unsigned int nfsd_net_id ;
1498
1498
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
+ */
1499
1507
int nfsd_nl_rpc_status_get_start (struct netlink_callback * cb )
1500
1508
{
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 );
1501
1585
return 0 ;
1502
1586
}
1503
1587
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
+ */
1504
1595
int nfsd_nl_rpc_status_get_dumpit (struct sk_buff * skb ,
1505
1596
struct netlink_callback * cb )
1506
1597
{
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 ;
1508
1678
}
1509
1679
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
+ */
1510
1687
int nfsd_nl_rpc_status_get_done (struct netlink_callback * cb )
1511
1688
{
1689
+ mutex_lock (& nfsd_mutex );
1690
+ nfsd_put (sock_net (cb -> skb -> sk ));
1691
+ mutex_unlock (& nfsd_mutex );
1692
+
1512
1693
return 0 ;
1513
1694
}
1514
1695
@@ -1606,6 +1787,10 @@ static int __init init_nfsd(void)
1606
1787
retval = register_filesystem (& nfsd_fs_type );
1607
1788
if (retval )
1608
1789
goto out_free_all ;
1790
+ retval = genl_register_family (& nfsd_nl_family );
1791
+ if (retval )
1792
+ goto out_free_all ;
1793
+
1609
1794
return 0 ;
1610
1795
out_free_all :
1611
1796
nfsd4_destroy_laundry_wq ();
@@ -1630,6 +1815,7 @@ static int __init init_nfsd(void)
1630
1815
1631
1816
static void __exit exit_nfsd (void )
1632
1817
{
1818
+ genl_unregister_family (& nfsd_nl_family );
1633
1819
unregister_filesystem (& nfsd_fs_type );
1634
1820
nfsd4_destroy_laundry_wq ();
1635
1821
unregister_cld_notifier ();
0 commit comments