Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH 2/2] NFS: handle IPv6 addresses in nfs ctl
From: Aurélien Charbon @ 2007-10-31  9:06 UTC (permalink / raw)
  To: Brian Haley; +Cc: netdev ML, Mailing list NFSv4
In-Reply-To: <47278145.8010002@hp.com>

[-- Attachment #1: Type: text/plain, Size: 15624 bytes --]

Thank you Brian
Sorry, I did not see what you sent.

I have tested it with an IPv4 configuration. It's OK.
So Neil, Bruce, you can take this one for review.

 fs/nfsd/export.c               |    9 ++-
 fs/nfsd/nfsctl.c               |   42 ++++++++++++--
 include/linux/sunrpc/svcauth.h |    5 +
 include/net/ipv6.h             |   10 +++
 net/sunrpc/svcauth_unix.c      |  118 
+++++++++++++++++++++++++++--------------
 5 files changed, 134 insertions(+), 50 deletions(-)

Signed-off-by: Brian Haley <brian.haley@hp.com>
Signed-off-by: Aurelien Charbon <aurelien.charbon@bull.net>

---

diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 66d0aeb..c47ba77 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -35,6 +35,7 @@
 #include <linux/lockd/bind.h>
 #include <linux/sunrpc/msg_prot.h>
 #include <linux/sunrpc/gss_api.h>
+#include <net/ipv6.h>
 
 #define NFSDDBG_FACILITY    NFSDDBG_EXPORT
 
@@ -1556,6 +1557,7 @@ exp_addclient(struct nfsctl_client *ncp)
 {
     struct auth_domain    *dom;
     int            i, err;
+    struct in6_addr        in6;
 
     /* First, consistency check. */
     err = -EINVAL;
@@ -1574,9 +1576,10 @@ exp_addclient(struct nfsctl_client *ncp)
         goto out_unlock;
 
     /* Insert client into hashtable. */
-    for (i = 0; i < ncp->cl_naddr; i++)
-        auth_unix_add_addr(ncp->cl_addrlist[i], dom);
-
+    for (i = 0; i < ncp->cl_naddr; i++) {
+        ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &in6);
+        auth_unix_add_addr(&in6, dom);
+    }
     auth_unix_forget_old(dom);
     auth_domain_put(dom);
 
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 77dc989..5cb5f0d 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -37,6 +37,7 @@
 #include <linux/nfsd/syscall.h>
 
 #include <asm/uaccess.h>
+#include <net/ipv6.h>
 
 /*
  *    We have a single directory with 9 nodes in it.
@@ -219,24 +220,37 @@ static ssize_t write_getfs(struct file *file, char 
*buf, size_t size)
 {
     struct nfsctl_fsparm *data;
     struct sockaddr_in *sin;
+    struct sockaddr_in6 *sin6;
     struct auth_domain *clp;
     int err = 0;
     struct knfsd_fh *res;
+    struct in6_addr in6;
 
     if (size < sizeof(*data))
         return -EINVAL;
     data = (struct nfsctl_fsparm*)buf;
     err = -EPROTONOSUPPORT;
-    if (data->gd_addr.sa_family != AF_INET)
+    switch (data->gd_addr.sa_family) {
+    case AF_INET:
+        sin = (struct sockaddr_in *)&data->gd_addr;
+        ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
+        break;
+    case AF_INET6:
+        sin6 = (struct sockaddr_in6 *)&data->gd_addr;
+        ipv6_addr_copy(&in6, &sin6->sin6_addr);
+        break;
+    default:
         goto out;
-    sin = (struct sockaddr_in *)&data->gd_addr;
+    }
+
     if (data->gd_maxlen > NFS3_FHSIZE)
         data->gd_maxlen = NFS3_FHSIZE;
 
     res = (struct knfsd_fh*)buf;
 
     exp_readlock();
-    if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+    if (!(clp = auth_unix_lookup(&in6)))
         err = -EPERM;
     else {
         err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
@@ -253,25 +267,41 @@ static ssize_t write_getfd(struct file *file, char 
*buf, size_t size)
 {
     struct nfsctl_fdparm *data;
     struct sockaddr_in *sin;
+    struct sockaddr_in6 *sin6;
     struct auth_domain *clp;
     int err = 0;
     struct knfsd_fh fh;
     char *res;
+    struct in6_addr in6;
 
     if (size < sizeof(*data))
         return -EINVAL;
     data = (struct nfsctl_fdparm*)buf;
     err = -EPROTONOSUPPORT;
-    if (data->gd_addr.sa_family != AF_INET)
+    if (data->gd_addr.sa_family != AF_INET &&
+        data->gd_addr.sa_family != AF_INET6)
         goto out;
     err = -EINVAL;
     if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
         goto out;
 
     res = buf;
-    sin = (struct sockaddr_in *)&data->gd_addr;
     exp_readlock();
-    if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+    switch (data->gd_addr.sa_family) {
+    case AF_INET:
+        sin = (struct sockaddr_in *)&data->gd_addr;
+        ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
+        break;
+    case AF_INET6:
+        sin6 = (struct sockaddr_in6 *)&data->gd_addr;
+        ipv6_addr_copy(&in6, &sin6->sin6_addr);
+        break;
+    default:
+        goto out;
+    }
+
+    if (!(clp = auth_unix_lookup(&in6)))
         err = -EPERM;
     else {
         err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index 22e1ef8..64ecb93 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -15,6 +15,7 @@
 #include <linux/sunrpc/msg_prot.h>
 #include <linux/sunrpc/cache.h>
 #include <linux/hash.h>
+#include <net/ipv6.h>
 
 #define SVC_CRED_NGROUPS    32
 struct svc_cred {
@@ -120,10 +121,10 @@ extern void    
svc_auth_unregister(rpc_authflavor_t flavor);
 
 extern struct auth_domain *unix_domain_find(char *name);
 extern void auth_domain_put(struct auth_domain *item);
-extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain 
*dom);
+extern int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain 
*dom);
 extern struct auth_domain *auth_domain_lookup(char *name, struct 
auth_domain *new);
 extern struct auth_domain *auth_domain_find(char *name);
-extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
+extern struct auth_domain *auth_unix_lookup(struct in6_addr *addr);
 extern int auth_unix_forget_old(struct auth_domain *dom);
 extern void svcauth_unix_purge(void);
 extern void svcauth_unix_info_release(void *);
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index ae328b6..366fdca 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -16,6 +16,7 @@
 #define _NET_IPV6_H
 
 #include <linux/ipv6.h>
+#include <linux/in.h>
 #include <linux/hardirq.h>
 #include <net/if_inet6.h>
 #include <net/ndisc.h>
@@ -400,6 +401,15 @@ static inline int ipv6_addr_v4mapped(const struct 
in6_addr *a)
          a->s6_addr32[2] == htonl(0x0000ffff));
 }
 
+static inline void ipv6_addr_set_v4mapped(const __be32 addr,
+                      struct in6_addr *v4mapped)
+{
+    ipv6_addr_set(v4mapped,
+              0, 0,
+              __constant_htonl(0x0000FFFF),
+              addr);
+}
+
 /*
  * find the first different bit between two addresses
  * length of address must be a multiple of 32bits
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 4114794..a40d769 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -11,6 +11,7 @@
 #include <linux/hash.h>
 #include <linux/string.h>
 #include <net/sock.h>
+#include <net/ipv6.h>
 
 #define RPCDBG_FACILITY    RPCDBG_AUTH
 
@@ -84,7 +85,7 @@ static void svcauth_unix_domain_release(struct 
auth_domain *dom)
 struct ip_map {
     struct cache_head    h;
     char            m_class[8]; /* e.g. "nfsd" */
-    struct in_addr        m_addr;
+    struct in6_addr        m_addr;
     struct unix_domain    *m_client;
     int            m_add_change;
 };
@@ -101,7 +102,6 @@ static void ip_map_put(struct kref *kref)
     kfree(im);
 }
 
-#if IP_HASHBITS == 8
 /* hash_long on a 64 bit machine is currently REALLY BAD for
  * IP addresses in reverse-endian (i.e. on a little-endian machine).
  * So use a trivial but reliable hash instead
@@ -111,13 +111,20 @@ static inline int hash_ip(__be32 ip)
     int hash = (__force u32)ip ^ ((__force u32)ip>>16);
     return (hash ^ (hash>>8)) & 0xff;
 }
-#endif
+
+static inline int hash_ip6(struct in6_addr *ip6)
+{
+    return (hash_ip(ip6->s6_addr32[0]) ^
+        hash_ip(ip6->s6_addr32[1]) ^
+        hash_ip(ip6->s6_addr32[2]) ^
+        hash_ip(ip6->s6_addr32[3]));
+}
 static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
 {
     struct ip_map *orig = container_of(corig, struct ip_map, h);
     struct ip_map *new = container_of(cnew, struct ip_map, h);
     return strcmp(orig->m_class, new->m_class) == 0
-        && orig->m_addr.s_addr == new->m_addr.s_addr;
+        && ipv6_addr_equal(&orig->m_addr, &new->m_addr);
 }
 static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
 {
@@ -125,7 +132,7 @@ static void ip_map_init(struct cache_head *cnew, 
struct cache_head *citem)
     struct ip_map *item = container_of(citem, struct ip_map, h);
 
     strcpy(new->m_class, item->m_class);
-    new->m_addr.s_addr = item->m_addr.s_addr;
+    ipv6_addr_copy(&new->m_addr, &item->m_addr);
 }
 static void update(struct cache_head *cnew, struct cache_head *citem)
 {
@@ -149,22 +156,24 @@ static void ip_map_request(struct cache_detail *cd,
                   struct cache_head *h,
                   char **bpp, int *blen)
 {
-    char text_addr[20];
+    char text_addr[40];
     struct ip_map *im = container_of(h, struct ip_map, h);
-    __be32 addr = im->m_addr.s_addr;
-
-    snprintf(text_addr, 20, "%u.%u.%u.%u",
-         ntohl(addr) >> 24 & 0xff,
-         ntohl(addr) >> 16 & 0xff,
-         ntohl(addr) >>  8 & 0xff,
-         ntohl(addr) >>  0 & 0xff);
 
+    if (ipv6_addr_v4mapped(&(im->m_addr))) {
+        snprintf(text_addr, 20, NIPQUAD_FMT,
+                ntohl(im->m_addr.s6_addr32[3]) >> 24 & 0xff,
+                ntohl(im->m_addr.s6_addr32[3]) >> 16 & 0xff,
+                ntohl(im->m_addr.s6_addr32[3]) >>  8 & 0xff,
+                ntohl(im->m_addr.s6_addr32[3]) >>  0 & 0xff);
+    } else {
+        snprintf(text_addr, 40, NIP6_FMT, NIP6(im->m_addr));
+    }
     qword_add(bpp, blen, im->m_class);
     qword_add(bpp, blen, text_addr);
     (*bpp)[-1] = '\n';
 }
 
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr);
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr);
 static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, 
time_t expiry);
 
 static int ip_map_parse(struct cache_detail *cd,
@@ -175,10 +184,10 @@ static int ip_map_parse(struct cache_detail *cd,
      * for scratch: */
     char *buf = mesg;
     int len;
-    int b1,b2,b3,b4;
+    int b1, b2, b3, b4, b5, b6, b7, b8;
     char c;
     char class[8];
-    struct in_addr addr;
+    struct in6_addr addr6;
     int err;
 
     struct ip_map *ipmp;
@@ -197,7 +206,23 @@ static int ip_map_parse(struct cache_detail *cd,
     len = qword_get(&mesg, buf, mlen);
     if (len <= 0) return -EINVAL;
 
-    if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
+    if (sscanf(buf, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) == 4) {
+        addr6.s6_addr32[0] = 0;
+        addr6.s6_addr32[1] = 0;
+        addr6.s6_addr32[2] = htonl(0xffff);
+        addr6.s6_addr32[3] =
+            htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
+       } else if (sscanf(buf, NIP6_FMT "%c",
+            &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) {
+        addr6.s6_addr16[0] = htons(b1);
+        addr6.s6_addr16[1] = htons(b2);
+        addr6.s6_addr16[2] = htons(b3);
+        addr6.s6_addr16[3] = htons(b4);
+        addr6.s6_addr16[4] = htons(b5);
+        addr6.s6_addr16[5] = htons(b6);
+        addr6.s6_addr16[6] = htons(b7);
+        addr6.s6_addr16[7] = htons(b8);
+       } else
         return -EINVAL;
 
     expiry = get_expiry(&mesg);
@@ -215,10 +240,7 @@ static int ip_map_parse(struct cache_detail *cd,
     } else
         dom = NULL;
 
-    addr.s_addr =
-        htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
-
-    ipmp = ip_map_lookup(class,addr);
+    ipmp = ip_map_lookup(class, &addr6);
     if (ipmp) {
         err = ip_map_update(ipmp,
                  container_of(dom, struct unix_domain, h),
@@ -238,7 +260,7 @@ static int ip_map_show(struct seq_file *m,
                struct cache_head *h)
 {
     struct ip_map *im;
-    struct in_addr addr;
+    struct in6_addr addr6;
     char *dom = "-no-domain-";
 
     if (h == NULL) {
@@ -247,20 +269,24 @@ static int ip_map_show(struct seq_file *m,
     }
     im = container_of(h, struct ip_map, h);
     /* class addr domain */
-    addr = im->m_addr;
+    ipv6_addr_copy(&addr6, &im->m_addr);
 
     if (test_bit(CACHE_VALID, &h->flags) &&
         !test_bit(CACHE_NEGATIVE, &h->flags))
         dom = im->m_client->h.name;
 
-    seq_printf(m, "%s %d.%d.%d.%d %s\n",
-           im->m_class,
-           ntohl(addr.s_addr) >> 24 & 0xff,
-           ntohl(addr.s_addr) >> 16 & 0xff,
-           ntohl(addr.s_addr) >>  8 & 0xff,
-           ntohl(addr.s_addr) >>  0 & 0xff,
-           dom
-           );
+    if (ipv6_addr_v4mapped(&addr6)) {
+        seq_printf(m, "%s" NIPQUAD_FMT "%s\n",
+            im->m_class,
+            ntohl(addr6.s6_addr32[3]) >> 24 & 0xff,
+            ntohl(addr6.s6_addr32[3]) >> 16 & 0xff,
+            ntohl(addr6.s6_addr32[3]) >>  8 & 0xff,
+            ntohl(addr6.s6_addr32[3]) >>  0 & 0xff,
+            dom);
+    } else {
+        seq_printf(m, "%s" NIP6_FMT "%s\n",
+            im->m_class, NIP6(addr6), dom);
+    }
     return 0;
 }
 
@@ -280,16 +306,16 @@ struct cache_detail ip_map_cache = {
     .alloc        = ip_map_alloc,
 };
 
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr)
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr)
 {
     struct ip_map ip;
     struct cache_head *ch;
 
     strcpy(ip.m_class, class);
-    ip.m_addr = addr;
+    ipv6_addr_copy(&ip.m_addr, addr);
     ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
                  hash_str(class, IP_HASHBITS) ^
-                 hash_ip(addr.s_addr));
+                 hash_ip6(addr));
 
     if (ch)
         return container_of(ch, struct ip_map, h);
@@ -318,14 +344,14 @@ static int ip_map_update(struct ip_map *ipm, 
struct unix_domain *udom, time_t ex
     ch = sunrpc_cache_update(&ip_map_cache,
                  &ip.h, &ipm->h,
                  hash_str(ipm->m_class, IP_HASHBITS) ^
-                 hash_ip(ipm->m_addr.s_addr));
+                 hash_ip6(&ipm->m_addr));
     if (!ch)
         return -ENOMEM;
     cache_put(ch, &ip_map_cache);
     return 0;
 }
 
-int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
+int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
 {
     struct unix_domain *udom;
     struct ip_map *ipmp;
@@ -352,7 +378,7 @@ int auth_unix_forget_old(struct auth_domain *dom)
     return 0;
 }
 
-struct auth_domain *auth_unix_lookup(struct in_addr addr)
+struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
 {
     struct ip_map *ipm;
     struct auth_domain *rv;
@@ -641,9 +667,23 @@ static int unix_gid_find(uid_t uid, struct 
group_info **gip,
 int
 svcauth_unix_set_client(struct svc_rqst *rqstp)
 {
-    struct sockaddr_in *sin = svc_addr_in(rqstp);
+    struct sockaddr_in *sin;
+    struct sockaddr_in6 *sin6, sin6_storage;
     struct ip_map *ipm;
 
+    switch (rqstp->rq_addr.ss_family) {
+    case AF_INET:
+        sin = svc_addr_in(rqstp);
+        sin6 = &sin6_storage;
+        ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &sin6->sin6_addr);
+        break;
+    case AF_INET6:
+        sin6 = svc_addr_in6(rqstp);
+        break;
+    default:
+        BUG();
+    }
+
     rqstp->rq_client = NULL;
     if (rqstp->rq_proc == 0)
         return SVC_OK;
@@ -651,7 +691,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
     ipm = ip_map_cached_get(rqstp);
     if (ipm == NULL)
         ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
-                    sin->sin_addr);
+                    &sin6->sin6_addr);
 
     if (ipm == NULL)
         return SVC_DENIED;


-- 

********************************
       Aurelien Charbon
       Linux NFSv4 team
           Bull SAS
     Echirolles - France
http://nfsv4.bullopensource.org/
********************************


[-- Attachment #2: nfs.ipv6.patch --]
[-- Type: text/x-patch, Size: 13502 bytes --]

diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 66d0aeb..c47ba77 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -35,6 +35,7 @@
 #include <linux/lockd/bind.h>
 #include <linux/sunrpc/msg_prot.h>
 #include <linux/sunrpc/gss_api.h>
+#include <net/ipv6.h>
 
 #define NFSDDBG_FACILITY	NFSDDBG_EXPORT
 
@@ -1556,6 +1557,7 @@ exp_addclient(struct nfsctl_client *ncp)
 {
 	struct auth_domain	*dom;
 	int			i, err;
+	struct in6_addr		in6;
 
 	/* First, consistency check. */
 	err = -EINVAL;
@@ -1574,9 +1576,10 @@ exp_addclient(struct nfsctl_client *ncp)
 		goto out_unlock;
 
 	/* Insert client into hashtable. */
-	for (i = 0; i < ncp->cl_naddr; i++)
-		auth_unix_add_addr(ncp->cl_addrlist[i], dom);
-
+	for (i = 0; i < ncp->cl_naddr; i++) {
+		ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &in6);
+		auth_unix_add_addr(&in6, dom);
+	}
 	auth_unix_forget_old(dom);
 	auth_domain_put(dom);
 
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 77dc989..5cb5f0d 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -37,6 +37,7 @@
 #include <linux/nfsd/syscall.h>
 
 #include <asm/uaccess.h>
+#include <net/ipv6.h>
 
 /*
  *	We have a single directory with 9 nodes in it.
@@ -219,24 +220,37 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size)
 {
 	struct nfsctl_fsparm *data;
 	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin6;
 	struct auth_domain *clp;
 	int err = 0;
 	struct knfsd_fh *res;
+	struct in6_addr in6;
 
 	if (size < sizeof(*data))
 		return -EINVAL;
 	data = (struct nfsctl_fsparm*)buf;
 	err = -EPROTONOSUPPORT;
-	if (data->gd_addr.sa_family != AF_INET)
+	switch (data->gd_addr.sa_family) {
+	case AF_INET:
+		sin = (struct sockaddr_in *)&data->gd_addr;
+		ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
+		break;
+	case AF_INET6:
+		sin6 = (struct sockaddr_in6 *)&data->gd_addr;
+		ipv6_addr_copy(&in6, &sin6->sin6_addr); 
+		break;
+	default:
 		goto out;
-	sin = (struct sockaddr_in *)&data->gd_addr;
+	}
+
 	if (data->gd_maxlen > NFS3_FHSIZE)
 		data->gd_maxlen = NFS3_FHSIZE;
 
 	res = (struct knfsd_fh*)buf;
 
 	exp_readlock();
-	if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+	if (!(clp = auth_unix_lookup(&in6)))
 		err = -EPERM;
 	else {
 		err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
@@ -253,25 +267,41 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
 {
 	struct nfsctl_fdparm *data;
 	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin6;
 	struct auth_domain *clp;
 	int err = 0;
 	struct knfsd_fh fh;
 	char *res;
+	struct in6_addr in6;
 
 	if (size < sizeof(*data))
 		return -EINVAL;
 	data = (struct nfsctl_fdparm*)buf;
 	err = -EPROTONOSUPPORT;
-	if (data->gd_addr.sa_family != AF_INET)
+	if (data->gd_addr.sa_family != AF_INET &&
+	    data->gd_addr.sa_family != AF_INET6)
 		goto out;
 	err = -EINVAL;
 	if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
 		goto out;
 
 	res = buf;
-	sin = (struct sockaddr_in *)&data->gd_addr;
 	exp_readlock();
-	if (!(clp = auth_unix_lookup(sin->sin_addr)))
+
+	switch (data->gd_addr.sa_family) {
+	case AF_INET:
+		sin = (struct sockaddr_in *)&data->gd_addr;
+		ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
+		break;
+	case AF_INET6:
+		sin6 = (struct sockaddr_in6 *)&data->gd_addr;
+		ipv6_addr_copy(&in6, &sin6->sin6_addr);
+		break;
+	default:
+		goto out;
+	}
+
+	if (!(clp = auth_unix_lookup(&in6)))
 		err = -EPERM;
 	else {
 		err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index 22e1ef8..64ecb93 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -15,6 +15,7 @@
 #include <linux/sunrpc/msg_prot.h>
 #include <linux/sunrpc/cache.h>
 #include <linux/hash.h>
+#include <net/ipv6.h>
 
 #define SVC_CRED_NGROUPS	32
 struct svc_cred {
@@ -120,10 +121,10 @@ extern void	svc_auth_unregister(rpc_authflavor_t flavor);
 
 extern struct auth_domain *unix_domain_find(char *name);
 extern void auth_domain_put(struct auth_domain *item);
-extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom);
+extern int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom);
 extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new);
 extern struct auth_domain *auth_domain_find(char *name);
-extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
+extern struct auth_domain *auth_unix_lookup(struct in6_addr *addr);
 extern int auth_unix_forget_old(struct auth_domain *dom);
 extern void svcauth_unix_purge(void);
 extern void svcauth_unix_info_release(void *);
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index ae328b6..366fdca 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -16,6 +16,7 @@
 #define _NET_IPV6_H
 
 #include <linux/ipv6.h>
+#include <linux/in.h>
 #include <linux/hardirq.h>
 #include <net/if_inet6.h>
 #include <net/ndisc.h>
@@ -400,6 +401,15 @@ static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
 		 a->s6_addr32[2] == htonl(0x0000ffff));
 }
 
+static inline void ipv6_addr_set_v4mapped(const __be32 addr,
+					  struct in6_addr *v4mapped)
+{
+	ipv6_addr_set(v4mapped,
+		      0, 0,
+		      __constant_htonl(0x0000FFFF),
+		      addr);
+}
+
 /*
  * find the first different bit between two addresses
  * length of address must be a multiple of 32bits
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 4114794..a40d769 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -11,6 +11,7 @@
 #include <linux/hash.h>
 #include <linux/string.h>
 #include <net/sock.h>
+#include <net/ipv6.h>
 
 #define RPCDBG_FACILITY	RPCDBG_AUTH
 
@@ -84,7 +85,7 @@ static void svcauth_unix_domain_release(struct auth_domain *dom)
 struct ip_map {
 	struct cache_head	h;
 	char			m_class[8]; /* e.g. "nfsd" */
-	struct in_addr		m_addr;
+	struct in6_addr		m_addr;
 	struct unix_domain	*m_client;
 	int			m_add_change;
 };
@@ -101,7 +102,6 @@ static void ip_map_put(struct kref *kref)
 	kfree(im);
 }
 
-#if IP_HASHBITS == 8
 /* hash_long on a 64 bit machine is currently REALLY BAD for
  * IP addresses in reverse-endian (i.e. on a little-endian machine).
  * So use a trivial but reliable hash instead
@@ -111,13 +111,20 @@ static inline int hash_ip(__be32 ip)
 	int hash = (__force u32)ip ^ ((__force u32)ip>>16);
 	return (hash ^ (hash>>8)) & 0xff;
 }
-#endif
+
+static inline int hash_ip6(struct in6_addr *ip6)
+{
+	return (hash_ip(ip6->s6_addr32[0]) ^
+		hash_ip(ip6->s6_addr32[1]) ^
+		hash_ip(ip6->s6_addr32[2]) ^
+		hash_ip(ip6->s6_addr32[3]));
+}
 static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
 {
 	struct ip_map *orig = container_of(corig, struct ip_map, h);
 	struct ip_map *new = container_of(cnew, struct ip_map, h);
 	return strcmp(orig->m_class, new->m_class) == 0
-		&& orig->m_addr.s_addr == new->m_addr.s_addr;
+		&& ipv6_addr_equal(&orig->m_addr, &new->m_addr);
 }
 static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
 {
@@ -125,7 +132,7 @@ static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
 	struct ip_map *item = container_of(citem, struct ip_map, h);
 
 	strcpy(new->m_class, item->m_class);
-	new->m_addr.s_addr = item->m_addr.s_addr;
+	ipv6_addr_copy(&new->m_addr, &item->m_addr);
 }
 static void update(struct cache_head *cnew, struct cache_head *citem)
 {
@@ -149,22 +156,24 @@ static void ip_map_request(struct cache_detail *cd,
 				  struct cache_head *h,
 				  char **bpp, int *blen)
 {
-	char text_addr[20];
+	char text_addr[40];
 	struct ip_map *im = container_of(h, struct ip_map, h);
-	__be32 addr = im->m_addr.s_addr;
-
-	snprintf(text_addr, 20, "%u.%u.%u.%u",
-		 ntohl(addr) >> 24 & 0xff,
-		 ntohl(addr) >> 16 & 0xff,
-		 ntohl(addr) >>  8 & 0xff,
-		 ntohl(addr) >>  0 & 0xff);
 
+	if (ipv6_addr_v4mapped(&(im->m_addr))) {
+		snprintf(text_addr, 20, NIPQUAD_FMT,
+				ntohl(im->m_addr.s6_addr32[3]) >> 24 & 0xff,
+				ntohl(im->m_addr.s6_addr32[3]) >> 16 & 0xff,
+				ntohl(im->m_addr.s6_addr32[3]) >>  8 & 0xff,
+				ntohl(im->m_addr.s6_addr32[3]) >>  0 & 0xff);
+	} else {
+		snprintf(text_addr, 40, NIP6_FMT, NIP6(im->m_addr));
+	}
 	qword_add(bpp, blen, im->m_class);
 	qword_add(bpp, blen, text_addr);
 	(*bpp)[-1] = '\n';
 }
 
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr);
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr);
 static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
 
 static int ip_map_parse(struct cache_detail *cd,
@@ -175,10 +184,10 @@ static int ip_map_parse(struct cache_detail *cd,
 	 * for scratch: */
 	char *buf = mesg;
 	int len;
-	int b1,b2,b3,b4;
+	int b1, b2, b3, b4, b5, b6, b7, b8;
 	char c;
 	char class[8];
-	struct in_addr addr;
+	struct in6_addr addr6;
 	int err;
 
 	struct ip_map *ipmp;
@@ -197,7 +206,23 @@ static int ip_map_parse(struct cache_detail *cd,
 	len = qword_get(&mesg, buf, mlen);
 	if (len <= 0) return -EINVAL;
 
-	if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
+	if (sscanf(buf, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) == 4) {
+		addr6.s6_addr32[0] = 0;
+		addr6.s6_addr32[1] = 0;
+		addr6.s6_addr32[2] = htonl(0xffff);
+		addr6.s6_addr32[3] =
+			htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
+       } else if (sscanf(buf, NIP6_FMT "%c",
+			&b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) {
+		addr6.s6_addr16[0] = htons(b1);
+		addr6.s6_addr16[1] = htons(b2);
+		addr6.s6_addr16[2] = htons(b3);
+		addr6.s6_addr16[3] = htons(b4);
+		addr6.s6_addr16[4] = htons(b5);
+		addr6.s6_addr16[5] = htons(b6);
+		addr6.s6_addr16[6] = htons(b7);
+		addr6.s6_addr16[7] = htons(b8);
+       } else
 		return -EINVAL;
 
 	expiry = get_expiry(&mesg);
@@ -215,10 +240,7 @@ static int ip_map_parse(struct cache_detail *cd,
 	} else
 		dom = NULL;
 
-	addr.s_addr =
-		htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
-
-	ipmp = ip_map_lookup(class,addr);
+	ipmp = ip_map_lookup(class, &addr6);
 	if (ipmp) {
 		err = ip_map_update(ipmp,
 			     container_of(dom, struct unix_domain, h),
@@ -238,7 +260,7 @@ static int ip_map_show(struct seq_file *m,
 		       struct cache_head *h)
 {
 	struct ip_map *im;
-	struct in_addr addr;
+	struct in6_addr addr6;
 	char *dom = "-no-domain-";
 
 	if (h == NULL) {
@@ -247,20 +269,24 @@ static int ip_map_show(struct seq_file *m,
 	}
 	im = container_of(h, struct ip_map, h);
 	/* class addr domain */
-	addr = im->m_addr;
+	ipv6_addr_copy(&addr6, &im->m_addr);
 
 	if (test_bit(CACHE_VALID, &h->flags) &&
 	    !test_bit(CACHE_NEGATIVE, &h->flags))
 		dom = im->m_client->h.name;
 
-	seq_printf(m, "%s %d.%d.%d.%d %s\n",
-		   im->m_class,
-		   ntohl(addr.s_addr) >> 24 & 0xff,
-		   ntohl(addr.s_addr) >> 16 & 0xff,
-		   ntohl(addr.s_addr) >>  8 & 0xff,
-		   ntohl(addr.s_addr) >>  0 & 0xff,
-		   dom
-		   );
+	if (ipv6_addr_v4mapped(&addr6)) {
+		seq_printf(m, "%s" NIPQUAD_FMT "%s\n",
+			im->m_class,
+			ntohl(addr6.s6_addr32[3]) >> 24 & 0xff,
+			ntohl(addr6.s6_addr32[3]) >> 16 & 0xff,
+			ntohl(addr6.s6_addr32[3]) >>  8 & 0xff,
+			ntohl(addr6.s6_addr32[3]) >>  0 & 0xff,
+			dom);
+	} else {
+		seq_printf(m, "%s" NIP6_FMT "%s\n",
+			im->m_class, NIP6(addr6), dom);
+	}
 	return 0;
 }
 
@@ -280,16 +306,16 @@ struct cache_detail ip_map_cache = {
 	.alloc		= ip_map_alloc,
 };
 
-static struct ip_map *ip_map_lookup(char *class, struct in_addr addr)
+static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr)
 {
 	struct ip_map ip;
 	struct cache_head *ch;
 
 	strcpy(ip.m_class, class);
-	ip.m_addr = addr;
+	ipv6_addr_copy(&ip.m_addr, addr);
 	ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
 				 hash_str(class, IP_HASHBITS) ^
-				 hash_ip(addr.s_addr));
+				 hash_ip6(addr));
 
 	if (ch)
 		return container_of(ch, struct ip_map, h);
@@ -318,14 +344,14 @@ static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t ex
 	ch = sunrpc_cache_update(&ip_map_cache,
 				 &ip.h, &ipm->h,
 				 hash_str(ipm->m_class, IP_HASHBITS) ^
-				 hash_ip(ipm->m_addr.s_addr));
+				 hash_ip6(&ipm->m_addr));
 	if (!ch)
 		return -ENOMEM;
 	cache_put(ch, &ip_map_cache);
 	return 0;
 }
 
-int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
+int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
 {
 	struct unix_domain *udom;
 	struct ip_map *ipmp;
@@ -352,7 +378,7 @@ int auth_unix_forget_old(struct auth_domain *dom)
 	return 0;
 }
 
-struct auth_domain *auth_unix_lookup(struct in_addr addr)
+struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
 {
 	struct ip_map *ipm;
 	struct auth_domain *rv;
@@ -641,9 +667,23 @@ static int unix_gid_find(uid_t uid, struct group_info **gip,
 int
 svcauth_unix_set_client(struct svc_rqst *rqstp)
 {
-	struct sockaddr_in *sin = svc_addr_in(rqstp);
+	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin6, sin6_storage;
 	struct ip_map *ipm;
 
+	switch (rqstp->rq_addr.ss_family) {
+	case AF_INET:
+		sin = svc_addr_in(rqstp);
+		sin6 = &sin6_storage;
+		ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &sin6->sin6_addr); 
+		break;
+	case AF_INET6:
+		sin6 = svc_addr_in6(rqstp);
+		break;
+	default:
+		BUG();
+	}
+
 	rqstp->rq_client = NULL;
 	if (rqstp->rq_proc == 0)
 		return SVC_OK;
@@ -651,7 +691,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
 	ipm = ip_map_cached_get(rqstp);
 	if (ipm == NULL)
 		ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
-				    sin->sin_addr);
+				    &sin6->sin6_addr);
 
 	if (ipm == NULL)
 		return SVC_DENIED;

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
NFSv4 mailing list
NFSv4@linux-nfs.org
http://linux-nfs.org/cgi-bin/mailman/listinfo/nfsv4

^ permalink raw reply related

* Re: [PATCH]: Fix networking scatterlist regressions.
From: David Miller @ 2007-10-31  9:26 UTC (permalink / raw)
  To: jens.axboe; +Cc: netdev, herbert, rusty
In-Reply-To: <20071031081428.GF5059@kernel.dk>

From: Jens Axboe <jens.axboe@oracle.com>
Date: Wed, 31 Oct 2007 09:14:28 +0100

> Subject: [PATCH] [SG] Get rid of __sg_mark_end()
> 
> sg_mark_end() overwrites the page_link information, but all users want
> __sg_mark_end() behaviour where we just set the end bit. That is the most
> natural way to use the sg list, since you'll fill it in and then mark the
> end point.
> 
> So change sg_mark_end() to only set the termination bit. Add a sg_magic
> debug check as well, and clear a chain pointer if it is set.
> 
> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

It doesn't build.  I suspect there is something else in your tree
that is necessary for this patch to work on it's own.

davem@sunset:~/src/GIT/net-2.6$ patch -p1 <diff
patching file block/ll_rw_blk.c
patching file drivers/scsi/scsi_lib.c
patching file include/linux/scatterlist.h
Hunk #2 succeeded at 242 (offset 22 lines).
patching file net/core/skbuff.c
patching file net/ipv4/tcp_ipv4.c
patching file net/ipv6/tcp_ipv6.c
patching file net/rxrpc/rxkad.c
patching file net/sunrpc/auth_gss/gss_krb5_crypto.c
 ...
  CC      init/main.o
In file included from include/asm/dma-mapping.h:4,
                 from include/linux/dma-mapping.h:52,
                 from include/asm/sbus.h:9,
                 from include/asm/dma.h:14,
                 from include/linux/bootmem.h:8,
                 from init/main.c:26:
include/linux/scatterlist.h: In function 'sg_init_one':
include/linux/scatterlist.h:228: error: too many arguments to function 'sg_mark_end'
make[1]: *** [init/main.o] Error 1
make: *** [init] Error 2

^ permalink raw reply

* Re: [PATCH]: Fix networking scatterlist regressions.
From: Jens Axboe @ 2007-10-31  9:29 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, herbert, rusty
In-Reply-To: <20071031.022643.118035583.davem@davemloft.net>

On Wed, Oct 31 2007, David Miller wrote:
> From: Jens Axboe <jens.axboe@oracle.com>
> Date: Wed, 31 Oct 2007 09:14:28 +0100
> 
> > Subject: [PATCH] [SG] Get rid of __sg_mark_end()
> > 
> > sg_mark_end() overwrites the page_link information, but all users want
> > __sg_mark_end() behaviour where we just set the end bit. That is the most
> > natural way to use the sg list, since you'll fill it in and then mark the
> > end point.
> > 
> > So change sg_mark_end() to only set the termination bit. Add a sg_magic
> > debug check as well, and clear a chain pointer if it is set.
> > 
> > Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
> 
> It doesn't build.  I suspect there is something else in your tree
> that is necessary for this patch to work on it's own.

Builds here. But yes, it's on top of other patches, it was merely for
demonstration purposes that I posted it. Locally sg_init_one() uses
sg_init_table() here, it doesn't open code the init:

static inline void sg_init_one(struct scatterlist *sg, const void *buf,
                               unsigned int buflen)
{
        sg_init_table(sg, 1);
        sg_set_buf(sg, buf, buflen);
}


-- 
Jens Axboe


^ permalink raw reply

* [PATCH 1/2] [TCP]: Process DSACKs that reside within a SACK block
From: Ilpo Järvinen @ 2007-10-31  9:48 UTC (permalink / raw)
  To: David Miller; +Cc: Netdev

[-- Attachment #1: Type: TEXT/PLAIN, Size: 3496 bytes --]


DSACK inside another SACK block were missed if start_seq of DSACK
was larger than SACK block's because sorting prioritizes full
processing of the SACK block before DSACK. After SACK block
sorting situation is like this:

             SSSSSSSSS
                  D
                        SSSSSS
                               SSSSSSS

Because write_queue is walked in-order, when the first SACK block
has been processed, TCP is already past the skb for which the
DSACK arrived and we haven't taught it to backtrack (nor should
we), so TCP just continues processing by going to the next SACK
block after the DSACK (if any).

Whenever such DSACK is present, do an embedded checking during
the previous SACK block.

If the DSACK is below snd_una, there won't be overlapping SACK
block, and thus no problem in that case. Also if start_seq of
the DSACK is equal to the actual block, it will be processed
first.

Tested this by using netem to duplicate 15% of packets, and
by printing SACK block when found_dup_sack is true and the 
selected skb in the dup_sack = 1 branch (if taken):

  SACK block 0: 4344-5792 (relative to snd_una 2019137317)
  SACK block 1: 4344-5792 (relative to snd_una 2019137317) 

equal start seqnos => next_dup = 0, dup_sack = 1 won't occur...

  SACK block 0: 5792-7240 (relative to snd_una 2019214061)
  SACK block 1: 2896-7240 (relative to snd_una 2019214061)
  DSACK skb match 5792-7240 (relative to snd_una)

...and next_dup = 1 case (after the not shown start_seq sort),
went to dup_sack = 1 branch.

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
---
 net/ipv4/tcp_input.c |   25 ++++++++++++++++++++++---
 1 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 69d8c38..4d72781 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1330,12 +1330,15 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
 		cached_fack_count = 0;
 	}
 
-	for (i=0; i<num_sacks; i++, sp++) {
+	for (i = 0; i < num_sacks; i++) {
 		struct sk_buff *skb;
 		__u32 start_seq = ntohl(sp->start_seq);
 		__u32 end_seq = ntohl(sp->end_seq);
 		int fack_count;
 		int dup_sack = (found_dup_sack && (i == first_sack_index));
+		int next_dup = (found_dup_sack && (i+1 == first_sack_index));
+
+		sp++;
 
 		if (!tcp_is_sackblock_valid(tp, dup_sack, start_seq, end_seq)) {
 			if (dup_sack) {
@@ -1361,7 +1364,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
 			flag |= FLAG_DATA_LOST;
 
 		tcp_for_write_queue_from(skb, sk) {
-			int in_sack;
+			int in_sack = 0;
 			u8 sacked;
 
 			if (skb == tcp_send_head(sk))
@@ -1380,7 +1383,23 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
 			if (!before(TCP_SKB_CB(skb)->seq, end_seq))
 				break;
 
-			in_sack = tcp_match_skb_to_sack(sk, skb, start_seq, end_seq);
+			dup_sack = (found_dup_sack && (i == first_sack_index));
+
+			/* Due to sorting DSACK may reside within this SACK block! */
+			if (next_dup) {
+				u32 dup_start = ntohl(sp->start_seq);
+				u32 dup_end = ntohl(sp->end_seq);
+
+				if (before(TCP_SKB_CB(skb)->seq, dup_end)) {
+					in_sack = tcp_match_skb_to_sack(sk, skb, dup_start, dup_end);
+					if (in_sack > 0)
+						dup_sack = 1;
+				}
+			}
+
+			/* DSACK info lost if out-of-mem, try SACK still */
+			if (in_sack <= 0)
+				in_sack = tcp_match_skb_to_sack(sk, skb, start_seq, end_seq);
 			if (in_sack < 0)
 				break;
 
-- 
1.5.0.6

^ permalink raw reply related

* [PATCH 2/2] [TCP]: Another TAGBITS -> SACKED_ACKED|LOST conversion
From: Ilpo Järvinen @ 2007-10-31  9:49 UTC (permalink / raw)
  To: David Miller; +Cc: Netdev
In-Reply-To: <Pine.LNX.4.64.0710311136200.16864@kivilampi-30.cs.helsinki.fi>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 753 bytes --]

Similar to commit 3eec0047d9bdd, point of this is to avoid
skipping R-bit skbs.

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
---
 net/ipv4/tcp_input.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 4d72781..ca9590f 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2078,7 +2078,7 @@ static void tcp_update_scoreboard(struct sock *sk)
 			if (!tcp_skb_timedout(sk, skb))
 				break;
 
-			if (!(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) {
+			if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_SACKED_ACKED|TCPCB_LOST))) {
 				TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
 				tp->lost_out += tcp_skb_pcount(skb);
 				tcp_verify_retransmit_hint(tp, skb);
-- 
1.5.0.6

^ permalink raw reply related

* Re: [PATCH 1/2] [TCP]: Process DSACKs that reside within a SACK block
From: David Miller @ 2007-10-31  9:51 UTC (permalink / raw)
  To: ilpo.jarvinen; +Cc: netdev
In-Reply-To: <Pine.LNX.4.64.0710311136200.16864@kivilampi-30.cs.helsinki.fi>

From: "Ilpo_Järvinen" <ilpo.jarvinen@helsinki.fi>
Date: Wed, 31 Oct 2007 11:48:31 +0200 (EET)

> DSACK inside another SACK block were missed if start_seq of DSACK
> was larger than SACK block's because sorting prioritizes full
> processing of the SACK block before DSACK. After SACK block
> sorting situation is like this:
> 
>              SSSSSSSSS
>                   D
>                         SSSSSS
>                                SSSSSSS
> 
> Because write_queue is walked in-order, when the first SACK block
> has been processed, TCP is already past the skb for which the
> DSACK arrived and we haven't taught it to backtrack (nor should
> we), so TCP just continues processing by going to the next SACK
> block after the DSACK (if any).
> 
> Whenever such DSACK is present, do an embedded checking during
> the previous SACK block.
> 
> If the DSACK is below snd_una, there won't be overlapping SACK
> block, and thus no problem in that case. Also if start_seq of
> the DSACK is equal to the actual block, it will be processed
> first.
> 
> Tested this by using netem to duplicate 15% of packets, and
> by printing SACK block when found_dup_sack is true and the 
> selected skb in the dup_sack = 1 branch (if taken):
> 
>   SACK block 0: 4344-5792 (relative to snd_una 2019137317)
>   SACK block 1: 4344-5792 (relative to snd_una 2019137317) 
> 
> equal start seqnos => next_dup = 0, dup_sack = 1 won't occur...
> 
>   SACK block 0: 5792-7240 (relative to snd_una 2019214061)
>   SACK block 1: 2896-7240 (relative to snd_una 2019214061)
>   DSACK skb match 5792-7240 (relative to snd_una)
> 
> ...and next_dup = 1 case (after the not shown start_seq sort),
> went to dup_sack = 1 branch.
> 
> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>

I will queue this bug fix up, thanks Ilpo!

And thanks for all of the testing information, it helps review
enormously.

^ permalink raw reply

* Re: [PATCH 2/2] [TCP]: Another TAGBITS -> SACKED_ACKED|LOST conversion
From: David Miller @ 2007-10-31  9:51 UTC (permalink / raw)
  To: ilpo.jarvinen; +Cc: netdev
In-Reply-To: <Pine.LNX.4.64.0710311149020.16864@kivilampi-30.cs.helsinki.fi>

From: "Ilpo_Järvinen" <ilpo.jarvinen@helsinki.fi>
Date: Wed, 31 Oct 2007 11:49:59 +0200 (EET)

> Similar to commit 3eec0047d9bdd, point of this is to avoid
> skipping R-bit skbs.
> 
> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>

I'll apply this also, thanks a lot.

^ permalink raw reply

* Re: [PATCH 00/33] Swap over NFS -v14
From: Peter Zijlstra @ 2007-10-31  9:53 UTC (permalink / raw)
  To: David Miller
  Cc: nickpiggin, torvalds, akpm, linux-kernel, linux-mm, netdev,
	trond.myklebust
In-Reply-To: <20071030.213753.126064697.davem@davemloft.net>

[-- Attachment #1: Type: text/plain, Size: 604 bytes --]

On Tue, 2007-10-30 at 21:37 -0700, David Miller wrote:
> From: Nick Piggin <nickpiggin@yahoo.com.au>
> Date: Wed, 31 Oct 2007 14:26:32 +1100
> 
> > Is it really worth all the added complexity of making swap
> > over NFS files work, given that you could use a network block
> > device instead?
> 
> Don't be misled.  Swapping over NFS is just a scarecrow for the
> seemingly real impetus behind these changes which is network storage
> stuff like iSCSI.

Not quite, yes, iSCSI is also on the 'want' list of quite a few people,
but swap over NFS on its own is also a feature of great demand.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [RFC][BNX2X] .h files rewrite
From: Eliezer Tamir @ 2007-10-31 10:14 UTC (permalink / raw)
  To: David Miller; +Cc: Michael Chan, jeff, netdev, masbock, eilong
In-Reply-To: <20071029.013931.203090879.davem@davemloft.net>

(Sorry It took so long to answer, I've had to go over a lot of stuff to
make sure I'm giving you accurate answers.)

On Mon, 2007-10-29 at 01:39 -0700, David Miller wrote:
> From: "Eliezer Tamir" <eliezert@broadcom.com>
> Date: Sun, 28 Oct 2007 22:21:14 +0200
> 
> Overall things look significantly better, thanks a lot!
> 
> However, there is still one set of magic constants in here
> which I hope you can clear up:
> 
> > +static const struct raw_op init_ops[] = {
> > +#define PRS_COMMON_START        0
> > +     {OP_WR, PRS_REG_INC_VALUE, 0xf},
> > +     {OP_WR, PRS_REG_EVENT_ID_1, 0x45},
> > +     {OP_WR, PRS_REG_EVENT_ID_2, 0x84},
> > +     {OP_WR, PRS_REG_EVENT_ID_3, 0x6},
> > +     {OP_WR, PRS_REG_NO_MATCH_EVENT_ID, 0x4},
> > +     {OP_WR, PRS_REG_CM_HDR_TYPE_0, 0x0},
> > +     {OP_WR, PRS_REG_CM_HDR_TYPE_1, 0x12170000},
> > +     {OP_WR, PRS_REG_CM_HDR_TYPE_2, 0x22170000},
> > +     {OP_WR, PRS_REG_CM_HDR_TYPE_3, 0x32170000},
> > +     {OP_ZR, PRS_REG_CM_HDR_TYPE_4, 0x5},
> > +     {OP_WR, PRS_REG_CM_HDR_LOOPBACK_TYPE_1, 0x12150000},
> > +     {OP_WR, PRS_REG_CM_HDR_LOOPBACK_TYPE_2, 0x22150000},
> > +     {OP_WR, PRS_REG_CM_HDR_LOOPBACK_TYPE_3, 0x32150000},
> > +     {OP_ZR, PRS_REG_CM_HDR_LOOPBACK_TYPE_4, 0x4},
>  etc. etc.

These are the steps performed to initialize the chip and load the
microcode.

Each element in the array is an operation in the form:
{operation, chip address, value}

Where the operation is one of:
OP_WR - write a value to the chip.
OP_RD - read a register (this is a read with a side effect, usually a
clear on read register).
OP_SW - string write to the chip (parts of the microcode).
OP_SI - string write using indirect write registers.
OP_ZR - clear a range of memory.
OP_ZP - unzip and copy using DMAE.
OP_WB - string copy using DMAE.

(I will add these explanations to bnx2x_init.h)

As you can see there are quite a lot of them, that is because most of
them are setting up the microcode internal structures.
Maybe it would have been better if the microcode were to do these things
but because of size issues it currently is not an option.

We will add comments to all register definitions explaining as much as
possible about each register.

All of the registers that are related to the driver flow are accessed
explicitly inside the driver code in the main .c file.

Writes to memories are simply parts of the microcode.

However, almost all of the registers written to here, are numeric values
not bit constants. The values are derived from HW definitions (and that
was the source of the extra-ugly generated code that we replaced).

In a perfect world almost all of these would have been the reset values
of the registers. 
#include "bitching_about_HW_guys.h"

The added documentation for each register in the register file will
provide all the info that I have about the values.
I feel bad about adding several hundred lines of defines that are only
used once, and do not add any real information about the values.

Your insights would be appreciated.

Thanks,
Eliezer




^ permalink raw reply

* Re: [PATCH 03/33] mm: slub: add knowledge of reserve pages
From: Peter Zijlstra @ 2007-10-31 10:42 UTC (permalink / raw)
  To: Nick Piggin
  Cc: Linus Torvalds, Andrew Morton, linux-kernel, linux-mm, netdev,
	trond.myklebust
In-Reply-To: <200710311437.28630.nickpiggin@yahoo.com.au>

[-- Attachment #1: Type: text/plain, Size: 1232 bytes --]

On Wed, 2007-10-31 at 14:37 +1100, Nick Piggin wrote:
> On Wednesday 31 October 2007 03:04, Peter Zijlstra wrote:
> > Restrict objects from reserve slabs (ALLOC_NO_WATERMARKS) to allocation
> > contexts that are entitled to it.
> >
> > Care is taken to only touch the SLUB slow path.
> >
> > This is done to ensure reserve pages don't leak out and get consumed.
> 
> I think this is generally a good idea (to prevent slab allocators
> from stealing reserve). However I naively think the implementation
> is a bit overengineered and thus has a few holes.
> 
> Humour me, what was the problem with failing the slab allocation
> (actually, not fail but just call into the page allocator to do
> correct waiting  / reclaim) in the slowpath if the process fails the
> watermark checks?

Ah, we actually need slabs below the watermarks. Its just that once I
allocated those slabs using __GFP_MEMALLOC/PF_MEMALLOC I don't want
allocation contexts that do not have rights to those pages to walk off
with objects.

So, this generic reserve framework still uses the slab allocator to
provide certain kind of objects (kmalloc, kmem_cache_alloc), it just
separates those that are and are not entitled to the reserves.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCH 05/33] mm: kmem_estimate_pages()
From: Peter Zijlstra @ 2007-10-31 10:42 UTC (permalink / raw)
  To: Nick Piggin
  Cc: Linus Torvalds, Andrew Morton, linux-kernel, linux-mm, netdev,
	trond.myklebust
In-Reply-To: <200710311443.18143.nickpiggin@yahoo.com.au>

[-- Attachment #1: Type: text/plain, Size: 649 bytes --]

On Wed, 2007-10-31 at 14:43 +1100, Nick Piggin wrote:
> On Wednesday 31 October 2007 03:04, Peter Zijlstra wrote:
> > Provide a method to get the upper bound on the pages needed to allocate
> > a given number of objects from a given kmem_cache.
> >
> 
> Fair enough, but just to make it a bit easier, can you provide a
> little reason of why in this patch (or reference the patch number
> where you use it, or put it together with the patch where you use
> it, etc.).

A generic reserve framework, as seen in patch 11/23, needs to be able
convert from a object demand (kmalloc() bytes, kmem_cache_alloc()
objects) to a page reserve.


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCH 06/33] mm: allow PF_MEMALLOC from softirq context
From: Peter Zijlstra @ 2007-10-31 10:42 UTC (permalink / raw)
  To: Nick Piggin
  Cc: Linus Torvalds, Andrew Morton, linux-kernel, linux-mm, netdev,
	trond.myklebust
In-Reply-To: <200710311451.56747.nickpiggin@yahoo.com.au>

[-- Attachment #1: Type: text/plain, Size: 845 bytes --]

On Wed, 2007-10-31 at 14:51 +1100, Nick Piggin wrote:
> On Wednesday 31 October 2007 03:04, Peter Zijlstra wrote:
> > Allow PF_MEMALLOC to be set in softirq context. When running softirqs from
> > a borrowed context save current->flags, ksoftirqd will have its own
> > task_struct.
> 
> 
> What's this for? Why would ksoftirqd pick up PF_MEMALLOC? (I guess
> that some networking thing must be picking it up in a subsequent patch,
> but I'm too lazy to look!)... Again, can you have more of a rationale in
> your patch headers, or ref the patch that uses it... thanks

Right, I knew I was forgetting something in these changelogs.

The network stack does quite a bit of packet processing from softirq
context. Once you start swapping over network, some of the packets want
to be processed under PF_MEMALLOC.

See patch 23/33.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCH 09/33] mm: system wide ALLOC_NO_WATERMARK
From: Peter Zijlstra @ 2007-10-31 10:45 UTC (permalink / raw)
  To: Nick Piggin
  Cc: Linus Torvalds, Andrew Morton, linux-kernel, linux-mm, netdev,
	trond.myklebust
In-Reply-To: <200710311452.36239.nickpiggin@yahoo.com.au>

[-- Attachment #1: Type: text/plain, Size: 878 bytes --]

On Wed, 2007-10-31 at 14:52 +1100, Nick Piggin wrote:
> On Wednesday 31 October 2007 03:04, Peter Zijlstra wrote:
> > Change ALLOC_NO_WATERMARK page allocation such that the reserves are system
> > wide - which they are per setup_per_zone_pages_min(), when we scrape the
> > barrel, do it properly.
> >
> 
> IIRC it's actually not too uncommon to have allocations coming here via
> page reclaim. It's not exactly clear that you want to break mempolicies
> at this point.

Hmm, the way I see it is that mempolicies are mainly for user-space
allocations, reserve allocations are always kernel allocations. These
already break mempolicies - for example hardirq context allocations.

Also, as it stands, the reserve is spread out evenly over all
zones/nodes (excluding highmem), so by restricting ourselves to a
subset, we don't have access to the full reserve.


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [RFC][BNX2X] .h files rewrite
From: David Miller @ 2007-10-31 10:53 UTC (permalink / raw)
  To: eliezert; +Cc: mchan, jeff, netdev, masbock, eilong
In-Reply-To: <1193825688.4836.134.camel@eliezer>

From: "Eliezer Tamir" <eliezert@broadcom.com>
Date: Wed, 31 Oct 2007 12:14:47 +0200

> I feel bad about adding several hundred lines of defines that are only
> used once, and do not add any real information about the values.

Ok, let's skip this for now.

^ permalink raw reply

* Re: [PATCH 00/33] Swap over NFS -v14
From: Peter Zijlstra @ 2007-10-31 10:56 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: David Miller, nickpiggin, torvalds, akpm, linux-kernel, linux-mm,
	netdev, trond.myklebust
In-Reply-To: <20071031085041.GA4362@infradead.org>

[-- Attachment #1: Type: text/plain, Size: 1657 bytes --]

On Wed, 2007-10-31 at 08:50 +0000, Christoph Hellwig wrote:
> On Tue, Oct 30, 2007 at 09:37:53PM -0700, David Miller wrote:
> > Don't be misled.  Swapping over NFS is just a scarecrow for the
> > seemingly real impetus behind these changes which is network storage
> > stuff like iSCSI.
> 
> So can we please do swap over network storage only first?  All these
> VM bits look conceptually sane to me, while the changes to the swap
> code to support nfs are real crackpipe material.

Yeah, I know how you stand on that. I just wanted to post all this
before going off into the woods reworking it all.

> Then again doing
> that part properly by adding address_space methods for swap I/O without
> the abuse might be a really good idea, especially as the way we
> do swapfiles on block-based filesystems is an horrible hack already.

Is planned. What do you think of the proposed a_ops extension to
accomplish this? That is,

->swapfile() - is this address space willing to back swap
->swapout() - write out a page
->swapin() - read in a page

> So please get the VM bits for swap over network blockdevices in first,

Trouble with that part is that we don't have any sane network block
devices atm, NBD is utter crap, and iSCSI is too complex to be called
sane.

Maybe Evgeniy's Distributed storage thingy would work, will have a look
at that.

> and then we can look into a complete revamp of the swapfile support
> that cleans up the current mess and adds support for nfs insted of
> making the mess even worse.

Sure, concrete suggestion are always welcome. Just being told something
is utter crap only goes so far.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: Bonding in active-backup mode with arp monitoring on Xen
From: Tsutomu Fujii @ 2007-10-31 11:08 UTC (permalink / raw)
  To: Jay Vosburgh; +Cc: netdev
In-Reply-To: <25246.1193780909@death>

Hi.

Jay Vosburgh wrote:
> 	I'm not sure if this is a solution that will work for any peer
> (some peers may not reply to an ARP with an IP source of all zeros).  At
> first glance, there doesn't seem to be much of a downside, but I'll have
> to experiment with it a bit to see if the check should be optional or
> simply removed entirely.

If there are no downside, I think it is better to remove the check.
For your information, other mode that can use arp monitoring send an
ARP with an IP source of all zero.

Thanks.

--
Tsutomu Fujii

^ permalink raw reply

* NBD was Re: [PATCH 00/33] Swap over NFS -v14
From: Pavel Machek @ 2007-10-31 11:18 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Christoph Hellwig, David Miller, nickpiggin, torvalds, akpm,
	linux-kernel, linux-mm, netdev, trond.myklebust
In-Reply-To: <1193828206.27652.145.camel@twins>

Hi!

> > So please get the VM bits for swap over network blockdevices in first,
> 
> Trouble with that part is that we don't have any sane network block
> devices atm, NBD is utter crap, and iSCSI is too complex to be called
> sane.

Hey, NBD was designed to be _simple_. And I think it works okay in
that area.. so can you elaborate on "utter crap"? [Ok, performance is
not great.]

Plus, I'd suggest you to look at ata-over-ethernet. It is in tree
today, quite simple, but should have better performance than nbd.
								Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply

* Re: NBD was Re: [PATCH 00/33] Swap over NFS -v14
From: Peter Zijlstra @ 2007-10-31 11:24 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Christoph Hellwig, David Miller, nickpiggin, torvalds, akpm,
	linux-kernel, linux-mm, netdev, trond.myklebust, Jens Axboe
In-Reply-To: <20071031111800.GA2551@elf.ucw.cz>

[-- Attachment #1: Type: text/plain, Size: 1202 bytes --]

On Wed, 2007-10-31 at 12:18 +0100, Pavel Machek wrote:
> Hi!
> 
> > > So please get the VM bits for swap over network blockdevices in first,
> > 
> > Trouble with that part is that we don't have any sane network block
> > devices atm, NBD is utter crap, and iSCSI is too complex to be called
> > sane.
> 
> Hey, NBD was designed to be _simple_. And I think it works okay in
> that area.. so can you elaborate on "utter crap"? [Ok, performance is
> not great.]

Yeah, sorry, perhaps I was overly strong.

It doesn't work for me, because:

  - it does connection management in user-space, which makes it
    impossible to reconnect. I'd want a full kernel based client.

  - it had some plugging issues, and after talking to Jens about it
    he suggested a rewrite using ->make_request() ala AoE. [ sorry if
    I'm short on details here, it was a long time ago, and I
    forgot, maybe Jens remembers ]

> Plus, I'd suggest you to look at ata-over-ethernet. It is in tree
> today, quite simple, but should have better performance than nbd.

Ah, right, I keep forgetting about that one. The only draw-back to that
on is, is that its raw ethernet, and not some IP protocol.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCH 00/33] Swap over NFS -v14
From: Peter Zijlstra @ 2007-10-31 11:27 UTC (permalink / raw)
  To: Nick Piggin
  Cc: Linus Torvalds, Andrew Morton, linux-kernel, linux-mm, netdev,
	trond.myklebust
In-Reply-To: <200710311426.33223.nickpiggin@yahoo.com.au>

[-- Attachment #1: Type: text/plain, Size: 968 bytes --]

On Wed, 2007-10-31 at 14:26 +1100, Nick Piggin wrote:
> On Wednesday 31 October 2007 03:04, Peter Zijlstra wrote:
> > Hi,
> >
> > Another posting of the full swap over NFS series.
> 
> Hi,
> 
> Is it really worth all the added complexity of making swap
> over NFS files work, given that you could use a network block
> device instead?

As it stands, we don't have a usable network block device IMHO.
NFS is by far the most used and usable network storage solution out
there, anybody with half a brain knows how to set it up and use it.

> Also, have you ensured that page_file_index, page_file_mapping
> and page_offset are only ever used on anonymous pages when the
> page is locked? (otherwise PageSwapCache could change)

Good point, I hope so, both ->readpage() and ->writepage() take a locked
page, I'd have to look if it remains locked throughout the NFS call
chain.

Then again, it might become obsolete with the extended swap a_ops.


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCH 03/33] mm: slub: add knowledge of reserve pages
From: Nick Piggin @ 2007-10-31 10:46 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Linus Torvalds, Andrew Morton, linux-kernel, linux-mm, netdev,
	trond.myklebust
In-Reply-To: <1193827358.27652.126.camel@twins>

On Wednesday 31 October 2007 21:42, Peter Zijlstra wrote:
> On Wed, 2007-10-31 at 14:37 +1100, Nick Piggin wrote:
> > On Wednesday 31 October 2007 03:04, Peter Zijlstra wrote:
> > > Restrict objects from reserve slabs (ALLOC_NO_WATERMARKS) to allocation
> > > contexts that are entitled to it.
> > >
> > > Care is taken to only touch the SLUB slow path.
> > >
> > > This is done to ensure reserve pages don't leak out and get consumed.
> >
> > I think this is generally a good idea (to prevent slab allocators
> > from stealing reserve). However I naively think the implementation
> > is a bit overengineered and thus has a few holes.
> >
> > Humour me, what was the problem with failing the slab allocation
> > (actually, not fail but just call into the page allocator to do
> > correct waiting  / reclaim) in the slowpath if the process fails the
> > watermark checks?
>
> Ah, we actually need slabs below the watermarks.

Right, I'd still allow those guys to allocate slabs. Provided they
have the right allocation context, right?


> Its just that once I 
> allocated those slabs using __GFP_MEMALLOC/PF_MEMALLOC I don't want
> allocation contexts that do not have rights to those pages to walk off
> with objects.

And I'd prevent these ones from doing so.

Without keeping track of "reserve" pages, which doesn't feel
too clean.

^ permalink raw reply

* Re: [PATCH 1/7] o80211s: Export dev_seq_{start,stop,next} symbols.
From: Johannes Berg @ 2007-10-31 12:01 UTC (permalink / raw)
  To: Luis Carlos Cobo
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <4727ddda.27ed720a.2444.6daf-ATjtLOhZ0NVl57MIdRCFDg@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 310 bytes --]



> This patches are being sent just to linux-wireless mailing list. I'm just
> sending this one patch also to netdev since it is not wireless specific.

> +EXPORT_SYMBOL_GPL(dev_seq_start);

A log message that explains why you need this would be good, rather than
a generic introduction.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]

^ permalink raw reply

* Re: [PATCH 06/33] mm: allow PF_MEMALLOC from softirq context
From: Nick Piggin @ 2007-10-31 10:49 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Linus Torvalds, Andrew Morton, linux-kernel, linux-mm, netdev,
	trond.myklebust
In-Reply-To: <1193827359.27652.129.camel@twins>

On Wednesday 31 October 2007 21:42, Peter Zijlstra wrote:
> On Wed, 2007-10-31 at 14:51 +1100, Nick Piggin wrote:
> > On Wednesday 31 October 2007 03:04, Peter Zijlstra wrote:
> > > Allow PF_MEMALLOC to be set in softirq context. When running softirqs
> > > from a borrowed context save current->flags, ksoftirqd will have its
> > > own task_struct.
> >
> > What's this for? Why would ksoftirqd pick up PF_MEMALLOC? (I guess
> > that some networking thing must be picking it up in a subsequent patch,
> > but I'm too lazy to look!)... Again, can you have more of a rationale in
> > your patch headers, or ref the patch that uses it... thanks
>
> Right, I knew I was forgetting something in these changelogs.
>
> The network stack does quite a bit of packet processing from softirq
> context. Once you start swapping over network, some of the packets want
> to be processed under PF_MEMALLOC.

Hmm... what about processing from interrupt context?

^ permalink raw reply

* Re: [PATCH 00/33] Swap over NFS -v14
From: Jeff Garzik @ 2007-10-31 12:16 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Nick Piggin, Linus Torvalds, Andrew Morton, linux-kernel,
	linux-mm, netdev, trond.myklebust
In-Reply-To: <1193830033.27652.159.camel@twins>

Thoughts:

1) I absolutely agree that NFS is far more prominent and useful than any 
network block device, at the present time.


2) Nonetheless, swap over NFS is a pretty rare case.  I view this work 
as interesting, but I really don't see a huge need, for swapping over 
NBD or swapping over NFS.  I tend to think swapping to a remote resource 
starts to approach "migration" rather than merely swapping.  Yes, we can 
do it...  but given the lack of burning need one must examine the price.


3) You note
> Swap over network has the problem that the network subsystem does not use fixed
> sized allocations, but heavily relies on kmalloc(). This makes mempools
> unusable.

True, but IMO there are mitigating factors that should be researched and 
taken into account:

a) To give you some net driver background/history, most mainstream net 
drivers were coded to allocate RX skbs of size 1538, under the theory 
that they would all be allocating out of the same underlying slab cache. 
  It would not be difficult to update a great many of the [non-jumbo] 
cases to create a fixed size allocation pattern.

b) Spare-time experiments and anecdotal evidence points to RX and TX skb 
recycling as a potentially valuable area of research.  If you are able 
to do something like that, then memory suddenly becomes a lot more 
bounded and predictable.


So my gut feeling is that taking a hard look at how net drivers function 
in the field should give you a lot of good ideas that approach the 
shared goal of making network memory allocations more predictable and 
bounded.

	Jeff

^ permalink raw reply

* Re: [PATCH 03/33] mm: slub: add knowledge of reserve pages
From: Peter Zijlstra @ 2007-10-31 12:17 UTC (permalink / raw)
  To: Nick Piggin
  Cc: Linus Torvalds, Andrew Morton, linux-kernel, linux-mm, netdev,
	trond.myklebust
In-Reply-To: <200710312146.03351.nickpiggin@yahoo.com.au>

[-- Attachment #1: Type: text/plain, Size: 2278 bytes --]

On Wed, 2007-10-31 at 21:46 +1100, Nick Piggin wrote:
> On Wednesday 31 October 2007 21:42, Peter Zijlstra wrote:
> > On Wed, 2007-10-31 at 14:37 +1100, Nick Piggin wrote:
> > > On Wednesday 31 October 2007 03:04, Peter Zijlstra wrote:
> > > > Restrict objects from reserve slabs (ALLOC_NO_WATERMARKS) to allocation
> > > > contexts that are entitled to it.
> > > >
> > > > Care is taken to only touch the SLUB slow path.
> > > >
> > > > This is done to ensure reserve pages don't leak out and get consumed.
> > >
> > > I think this is generally a good idea (to prevent slab allocators
> > > from stealing reserve). However I naively think the implementation
> > > is a bit overengineered and thus has a few holes.
> > >
> > > Humour me, what was the problem with failing the slab allocation
> > > (actually, not fail but just call into the page allocator to do
> > > correct waiting  / reclaim) in the slowpath if the process fails the
> > > watermark checks?
> >
> > Ah, we actually need slabs below the watermarks.
> 
> Right, I'd still allow those guys to allocate slabs. Provided they
> have the right allocation context, right?
> 
> 
> > Its just that once I 
> > allocated those slabs using __GFP_MEMALLOC/PF_MEMALLOC I don't want
> > allocation contexts that do not have rights to those pages to walk off
> > with objects.
> 
> And I'd prevent these ones from doing so.
> 
> Without keeping track of "reserve" pages, which doesn't feel
> too clean.

The problem with that is that once a slab was allocated with the right
allocation context, anybody can get objects from these slabs.


low memory, and empty slab:

task A                        task B

kmem_cache_alloc() = NULL

                              current->flags |= PF_MEMALLOC
                              kmem_cache_alloc() = obj
                              (slab != NULL)

kmem_cache_alloc() = obj
kmem_cache_alloc() = obj
kmem_cache_alloc() = obj


And now task A, who doesn't have the right permissions walks
away with all our reserve memory.

So we either reserve a page per object, which for 32 byte objects is a
large waste, or we stop anybody who doesn't have the right permissions
from obtaining objects. I took the latter approach.


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* [PATCH 0/8] Cleanup/fix the sk_alloc() call
From: Pavel Emelyanov @ 2007-10-31 13:40 UTC (permalink / raw)
  To: David Miller; +Cc: Linux Netdev List, devel

The sk_alloc() function suffers from two problems:
1 (major). The error path is not clean in it - if the security
   call fails, the net namespace is not put, if the try_module_get
   fails  additionally the security context is not released;
2 (minor). The zero_it argument is misleading, as it doesn't just 
   zeroes it, but performs some extra setup. Besides this argument 
   is used only in one place - in the sk_clone().

So this set fixes these problems and performs some additional
cleanup.

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox