diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index d6881774ea5758ed1bb9b635aaa823741c046c40..d4041a05bc19934eae12894a1802aafc7e1df3d4 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -23,10 +23,12 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -51,6 +53,7 @@ enum { NFSD_Fh, NFSD_Threads, NFSD_Versions, + NFSD_Ports, /* * The below MUST come last. Otherwise we leave a hole in nfsd_files[] * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops @@ -74,6 +77,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size); static ssize_t write_filehandle(struct file *file, char *buf, size_t size); static ssize_t write_threads(struct file *file, char *buf, size_t size); static ssize_t write_versions(struct file *file, char *buf, size_t size); +static ssize_t write_ports(struct file *file, char *buf, size_t size); #ifdef CONFIG_NFSD_V4 static ssize_t write_leasetime(struct file *file, char *buf, size_t size); static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); @@ -90,6 +94,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = { [NFSD_Fh] = write_filehandle, [NFSD_Threads] = write_threads, [NFSD_Versions] = write_versions, + [NFSD_Ports] = write_ports, #ifdef CONFIG_NFSD_V4 [NFSD_Leasetime] = write_leasetime, [NFSD_RecoveryDir] = write_recoverydir, @@ -419,6 +424,20 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) return len; } +static ssize_t write_ports(struct file *file, char *buf, size_t size) +{ + /* for now, ignore what was written and just + * return known ports + * AF proto address port + */ + int len = 0; + lock_kernel(); + if (nfsd_serv) + len = svc_sock_names(buf, nfsd_serv); + unlock_kernel(); + return len; +} + #ifdef CONFIG_NFSD_V4 extern time_t nfs4_leasetime(void); @@ -482,6 +501,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, + [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO}, #ifdef CONFIG_NFSD_V4 [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index b4acb3d37c3f2556e2b5f01efe587c94c6b8cced..3caf92d72a81207ee39f0cd0be82a0e619368c9f 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -61,5 +61,6 @@ int svc_recv(struct svc_serv *, struct svc_rqst *, long); int svc_send(struct svc_rqst *); void svc_drop(struct svc_rqst *); void svc_sock_update_bufs(struct svc_serv *serv); +int svc_sock_names(char *buf, struct svc_serv *serv); #endif /* SUNRPC_SVCSOCK_H */ diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 5b0fe1b66a23d5fbed578179268bedc15eae52c2..3ee4b78742b12e1f2780632ecdce9b2c09b47984 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -428,6 +428,46 @@ svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) return len; } +/* + * Report socket names for nfsdfs + */ +static int one_sock_name(char *buf, struct svc_sock *svsk) +{ + int len; + + switch(svsk->sk_sk->sk_family) { + case AF_INET: + len = sprintf(buf, "ipv4 %s %u.%u.%u.%u %d\n", + svsk->sk_sk->sk_protocol==IPPROTO_UDP? + "udp" : "tcp", + NIPQUAD(inet_sk(svsk->sk_sk)->rcv_saddr), + inet_sk(svsk->sk_sk)->num); + break; + default: + len = sprintf(buf, "*unknown-%d*\n", + svsk->sk_sk->sk_family); + } + return len; +} + +int +svc_sock_names(char *buf, struct svc_serv *serv) +{ + struct svc_sock *svsk; + int len = 0; + + if (!serv) + return 0; + spin_lock(&serv->sv_lock); + list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) { + int onelen = one_sock_name(buf+len, svsk); + len += onelen; + } + spin_unlock(&serv->sv_lock); + return len; +} +EXPORT_SYMBOL(svc_sock_names); + /* * Check input queue length */