SUNRPC: track whether a request is coming from a loop-back interface.
authorNeilBrown <neilb@suse.de>
Mon, 12 May 2014 01:22:47 +0000 (11:22 +1000)
committerJ. Bruce Fields <bfields@redhat.com>
Thu, 22 May 2014 19:59:18 +0000 (15:59 -0400)
If an incoming NFS request is coming from the local host, then
nfsd will need to perform some special handling.  So detect that
possibility and make the source visible in rq_local.

Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
include/linux/sunrpc/svc.h
include/linux/sunrpc/svc_xprt.h
net/sunrpc/sunrpc.h
net/sunrpc/svcsock.c

index 04e7632..a0dbbd1 100644 (file)
@@ -254,6 +254,7 @@ struct svc_rqst {
        u32                     rq_prot;        /* IP protocol */
        unsigned short
                                rq_secure  : 1; /* secure port */
+       unsigned short          rq_local   : 1; /* local request */
 
        void *                  rq_argp;        /* decoded arguments */
        void *                  rq_resp;        /* xdr'd results */
index 0cec1b9..7235040 100644 (file)
@@ -64,6 +64,7 @@ struct svc_xprt {
 #define        XPT_DETACHED    10              /* detached from tempsocks list */
 #define XPT_LISTENER   11              /* listening endpoint */
 #define XPT_CACHE_AUTH 12              /* cache auth info */
+#define XPT_LOCAL      13              /* connection from loopback interface */
 
        struct svc_serv         *xpt_server;    /* service for transport */
        atomic_t                xpt_reserved;   /* space on outq that is rsvd */
index 14c9f6d..f2b7cb5 100644 (file)
@@ -43,6 +43,19 @@ static inline int rpc_reply_expected(struct rpc_task *task)
                (task->tk_msg.rpc_proc->p_decode != NULL);
 }
 
+static inline int sock_is_loopback(struct sock *sk)
+{
+       struct dst_entry *dst;
+       int loopback = 0;
+       rcu_read_lock();
+       dst = rcu_dereference(sk->sk_dst_cache);
+       if (dst && dst->dev &&
+           (dst->dev->features & NETIF_F_LOOPBACK))
+               loopback = 1;
+       rcu_read_unlock();
+       return loopback;
+}
+
 int svc_send_common(struct socket *sock, struct xdr_buf *xdr,
                    struct page *headpage, unsigned long headoffset,
                    struct page *tailpage, unsigned long tailoffset);
index 0cb34f5..f3b8eb3 100644 (file)
@@ -874,6 +874,10 @@ static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
        }
        svc_xprt_set_local(&newsvsk->sk_xprt, sin, slen);
 
+       if (sock_is_loopback(newsock->sk))
+               set_bit(XPT_LOCAL, &newsvsk->sk_xprt.xpt_flags);
+       else
+               clear_bit(XPT_LOCAL, &newsvsk->sk_xprt.xpt_flags);
        if (serv->sv_stats)
                serv->sv_stats->nettcpconn++;
 
@@ -1119,6 +1123,7 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
 
        rqstp->rq_xprt_ctxt   = NULL;
        rqstp->rq_prot        = IPPROTO_TCP;
+       rqstp->rq_local       = !!test_bit(XPT_LOCAL, &svsk->sk_xprt.xpt_flags);
 
        p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
        calldir = p[1];