]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/mountd/cache.c
mountd: gather fsid information into one struct
[nfs-utils.git] / utils / mountd / cache.c
index ab873d56ba4bb37eb36360613e5f5f132a7be26a..897d61dd2f0502f72c2f46cb5a3c29917e3c90f9 100644 (file)
@@ -64,6 +64,7 @@ enum nfsd_fsid {
  */
 static int cache_export_ent(char *domain, struct exportent *exp, char *p);
 
+#define INITIAL_MANAGED_GROUPS 100
 
 char *lbuf  = NULL;
 int lbuflen = 0;
@@ -80,7 +81,7 @@ static void auth_unix_ip(FILE *f)
         */
        char *cp;
        char class[20];
-       char ipaddr[20];
+       char ipaddr[INET6_ADDRSTRLEN];
        char *client = NULL;
        struct addrinfo *tmp = NULL;
        struct addrinfo *ai = NULL;
@@ -95,7 +96,7 @@ static void auth_unix_ip(FILE *f)
            strcmp(class, "nfsd") != 0)
                return;
 
-       if (qword_get(&cp, ipaddr, 20) <= 0)
+       if (qword_get(&cp, ipaddr, sizeof(ipaddr)) <= 0)
                return;
 
        tmp = host_pton(ipaddr);
@@ -114,7 +115,7 @@ static void auth_unix_ip(FILE *f)
 
        qword_print(f, "nfsd");
        qword_print(f, ipaddr);
-       qword_printint(f, time(0)+30*60);
+       qword_printuint(f, time(0) + DEFAULT_TTL);
        if (use_ipaddr)
                qword_print(f, ipaddr);
        else if (client)
@@ -134,11 +135,23 @@ static void auth_unix_gid(FILE *f)
         */
        uid_t uid;
        struct passwd *pw;
-       gid_t glist[100], *groups = glist;
-       int ngroups = 100;
+       static gid_t *groups = NULL;
+       static int groups_len = 0;
+       gid_t *more_groups;
+       int ngroups;
        int rv, i;
        char *cp;
 
+       if (groups_len == 0) {
+               groups = malloc(sizeof(gid_t) * INITIAL_MANAGED_GROUPS);
+               if (!groups)
+                       return;
+
+               groups_len = INITIAL_MANAGED_GROUPS;
+       }
+
+       ngroups = groups_len;
+
        if (readline(fileno(f), &lbuf, &lbuflen) != 1)
                return;
 
@@ -151,17 +164,20 @@ static void auth_unix_gid(FILE *f)
                rv = -1;
        else {
                rv = getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
-               if (rv == -1 && ngroups >= 100) {
-                       groups = malloc(sizeof(gid_t)*ngroups);
-                       if (!groups)
+               if (rv == -1 && ngroups >= groups_len) {
+                       more_groups = realloc(groups, sizeof(gid_t)*ngroups);
+                       if (!more_groups)
                                rv = -1;
-                       else
+                       else {
+                               groups = more_groups;
+                               groups_len = ngroups;
                                rv = getgrouplist(pw->pw_name, pw->pw_gid,
                                                  groups, &ngroups);
+                       }
                }
        }
        qword_printuint(f, uid);
-       qword_printuint(f, time(0)+30*60);
+       qword_printuint(f, time(0) + DEFAULT_TTL);
        if (rv >= 0) {
                qword_printuint(f, ngroups);
                for (i=0; i<ngroups; i++)
@@ -169,9 +185,6 @@ static void auth_unix_gid(FILE *f)
        } else
                qword_printuint(f, 0);
        qword_eol(f);
-
-       if (groups != glist)
-               free(groups);
 }
 
 #if USE_BLKID
@@ -328,6 +341,29 @@ static char *next_mnt(void **v, char *p)
        return me->mnt_dir;
 }
 
+/* True iff e1 is a child of e2 and e2 has crossmnt set: */
+static bool subexport(struct exportent *e1, struct exportent *e2)
+{
+       char *p1 = e1->e_path, *p2 = e2->e_path;
+       int l2 = strlen(p2);
+
+       return e2->e_flags & NFSEXP_CROSSMOUNT
+              && strncmp(p1, p2, l2) == 0
+              && p1[l2] == '/';
+}
+
+struct parsed_fsid {
+       int fsidtype;
+       /* We could use a union for this, but it would be more
+        * complicated; why bother? */
+       unsigned int inode;
+       unsigned int minor;
+       unsigned int major;
+       unsigned int fsidnum;
+       int uuidlen;
+       char *fhuuid;
+};
+
 static void nfsd_fh(FILE *f)
 {
        /* request are:
@@ -339,19 +375,16 @@ static void nfsd_fh(FILE *f)
        char *dom;
        int fsidtype;
        int fsidlen;
-       unsigned int dev, major=0, minor=0;
-       unsigned int inode=0;
        unsigned long long inode64;
-       unsigned int fsidnum=0;
+       unsigned int dev;
        char fsid[32];
+       struct parsed_fsid parsed;
        struct exportent *found = NULL;
        struct addrinfo *ai = NULL;
        char *found_path = NULL;
        nfs_export *exp;
        int i;
        int dev_missing = 0;
-       int uuidlen = 0;
-       char *fhuuid = NULL;
 
        if (readline(fileno(f), &lbuf, &lbuflen) != 1)
                return;
@@ -376,15 +409,15 @@ static void nfsd_fh(FILE *f)
                if (fsidlen != 8)
                        goto out;
                memcpy(&dev, fsid, 4);
-               memcpy(&inode, fsid+4, 4);
-               major = ntohl(dev)>>16;
-               minor = ntohl(dev) & 0xFFFF;
+               memcpy(&parsed.inode, fsid+4, 4);
+               parsed.major = ntohl(dev)>>16;
+               parsed.minor = ntohl(dev) & 0xFFFF;
                break;
 
        case FSID_NUM: /* 4 bytes - fsid */
                if (fsidlen != 4)
                        goto out;
-               memcpy(&fsidnum, fsid, 4);
+               memcpy(&parsed.fsidnum, fsid, 4);
                break;
 
        case FSID_MAJOR_MINOR: /* 12 bytes: 4 major, 4 minor, 4 inode 
@@ -393,9 +426,11 @@ static void nfsd_fh(FILE *f)
                 */
                if (fsidlen != 12)
                        goto out;
-               memcpy(&dev, fsid, 4); major = ntohl(dev);
-               memcpy(&dev, fsid+4, 4); minor = ntohl(dev);
-               memcpy(&inode, fsid+8, 4);
+               memcpy(&dev, fsid, 4);
+               parsed.major = ntohl(dev);
+               memcpy(&dev, fsid+4, 4);
+               parsed.minor = ntohl(dev);
+               memcpy(&parsed.inode, fsid+8, 4);
                break;
 
        case FSID_ENCODE_DEV: /* 8 bytes: 4 byte packed device number, 4 inode */
@@ -405,37 +440,37 @@ static void nfsd_fh(FILE *f)
                if (fsidlen != 8)
                        goto out;
                memcpy(&dev, fsid, 4);
-               memcpy(&inode, fsid+4, 4);
-               major = (dev & 0xfff00) >> 8;
-               minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
+               memcpy(&parsed.inode, fsid+4, 4);
+               parsed.major = (dev & 0xfff00) >> 8;
+               parsed.minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
                break;
 
        case FSID_UUID4_INUM: /* 4 byte inode number and 4 byte uuid */
                if (fsidlen != 8)
                        goto out;
-               memcpy(&inode, fsid, 4);
-               uuidlen = 4;
-               fhuuid = fsid+4;
+               memcpy(&parsed.inode, fsid, 4);
+               parsed.uuidlen = 4;
+               parsed.fhuuid = fsid+4;
                break;
        case FSID_UUID8: /* 8 byte uuid */
                if (fsidlen != 8)
                        goto out;
-               uuidlen = 8;
-               fhuuid = fsid;
+               parsed.uuidlen = 8;
+               parsed.fhuuid = fsid;
                break;
        case FSID_UUID16: /* 16 byte uuid */
                if (fsidlen != 16)
                        goto out;
-               uuidlen = 16;
-               fhuuid = fsid;
+               parsed.uuidlen = 16;
+               parsed.fhuuid = fsid;
                break;
        case FSID_UUID16_INUM: /* 8 byte inode number and 16 byte uuid */
                if (fsidlen != 24)
                        goto out;
                memcpy(&inode64, fsid, 8);
-               inode = inode64;
-               uuidlen = 16;
-               fhuuid = fsid+8;
+               parsed.inode = inode64;
+               parsed.uuidlen = 16;
+               parsed.fhuuid = fsid+8;
                break;
        }
 
@@ -490,20 +525,20 @@ static void nfsd_fh(FILE *f)
                        case FSID_DEV:
                        case FSID_MAJOR_MINOR:
                        case FSID_ENCODE_DEV:
-                               if (stb.st_ino != inode)
+                               if (stb.st_ino != parsed.inode)
                                        continue;
-                               if (major != major(stb.st_dev) ||
-                                   minor != minor(stb.st_dev))
+                               if (parsed.major != major(stb.st_dev) ||
+                                   parsed.minor != minor(stb.st_dev))
                                        continue;
                                break;
                        case FSID_NUM:
                                if (((exp->m_export.e_flags & NFSEXP_FSID) == 0 ||
-                                    exp->m_export.e_fsid != fsidnum))
+                                    exp->m_export.e_fsid != parsed.fsidnum))
                                        continue;
                                break;
                        case FSID_UUID4_INUM:
                        case FSID_UUID16_INUM:
-                               if (stb.st_ino != inode)
+                               if (stb.st_ino != parsed.inode)
                                        continue;
                                goto check_uuid;
                        case FSID_UUID8:
@@ -513,15 +548,15 @@ static void nfsd_fh(FILE *f)
                        check_uuid:
                                if (exp->m_export.e_uuid)
                                        get_uuid(exp->m_export.e_uuid,
-                                                uuidlen, u);
+                                                parsed.uuidlen, u);
                                else
                                        for (type = 0;
-                                            uuid_by_path(path, type, uuidlen, u);
+                                            uuid_by_path(path, type, parsed.uuidlen, u);
                                             type++)
-                                               if (memcmp(u, fhuuid, uuidlen) == 0)
+                                               if (memcmp(u, parsed.fhuuid, parsed.uuidlen) == 0)
                                                        break;
 
-                               if (memcmp(u, fhuuid, uuidlen) != 0)
+                               if (memcmp(u, parsed.fhuuid, parsed.uuidlen) != 0)
                                        continue;
                                break;
                        }
@@ -537,13 +572,14 @@ static void nfsd_fh(FILE *f)
                                if (!client_check(exp->m_client, ai))
                                        continue;
                        }
-                       /* It's a match !! */
-                       if (!found) {
+                       if (!found || subexport(&exp->m_export, found)) {
                                found = &exp->m_export;
+                               free(found_path);
                                found_path = strdup(path);
                                if (found_path == NULL)
                                        goto out;
-                       } else if (strcmp(found->e_path, exp->m_export.e_path)!= 0)
+                       } else if (strcmp(found->e_path, exp->m_export.e_path)
+                                  && !subexport(found, &exp->m_export))
                        {
                                xlog(L_WARNING, "%s and %s have same filehandle for %s, using first",
                                     found_path, path, dom);
@@ -644,11 +680,11 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex
 {
        qword_print(f, domain);
        qword_print(f, path);
-       qword_printint(f, time(0)+30*60);
        if (exp) {
                int different_fs = strcmp(path, exp->e_path) != 0;
                int flag_mask = different_fs ? ~NFSEXP_FSID : ~0;
 
+               qword_printuint(f, time(0) + exp->e_ttl);
                qword_printint(f, exp->e_flags & flag_mask);
                qword_printint(f, exp->e_anonuid);
                qword_printint(f, exp->e_anongid);
@@ -667,7 +703,8 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex
                        qword_print(f, "uuid");
                        qword_printhex(f, u, 16);
                }
-       }
+       } else
+               qword_printuint(f, time(0) + DEFAULT_TTL);
        return qword_eol(f);
 }
 
@@ -813,12 +850,13 @@ struct {
        char *cache_name;
        void (*cache_handle)(FILE *f);
        FILE *f;
+       char vbuf[RPC_CHAN_BUF_SIZE];
 } cachelist[] = {
-       { "auth.unix.ip", auth_unix_ip, NULL},
-       { "auth.unix.gid", auth_unix_gid, NULL},
-       { "nfsd.export", nfsd_export, NULL},
-       { "nfsd.fh", nfsd_fh, NULL},
-       { NULL, NULL, NULL }
+       { "auth.unix.ip", auth_unix_ip, NULL, ""},
+       { "auth.unix.gid", auth_unix_gid, NULL, ""},
+       { "nfsd.export", nfsd_export, NULL, ""},
+       { "nfsd.fh", nfsd_fh, NULL, ""},
+       { NULL, NULL, NULL, ""}
 };
 
 extern int manage_gids;
@@ -836,6 +874,10 @@ void cache_open(void)
                        continue;
                sprintf(path, "/proc/net/rpc/%s/channel", cachelist[i].cache_name);
                cachelist[i].f = fopen(path, "r+");
+               if (cachelist[i].f != NULL) {
+                       setvbuf(cachelist[i].f, cachelist[i].vbuf, _IOLBF, 
+                               RPC_CHAN_BUF_SIZE);
+               }
        }
 }
 
@@ -874,8 +916,8 @@ int cache_process_req(fd_set *readfds)
 
 /*
  * Give IP->domain and domain+path->options to kernel
- * % echo nfsd $IP  $[now+30*60] $domain > /proc/net/rpc/auth.unix.ip/channel
- * % echo $domain $path $[now+30*60] $options $anonuid $anongid $fsid > /proc/net/rpc/nfsd.export/channel
+ * % echo nfsd $IP  $[now+DEFAULT_TTL] $domain > /proc/net/rpc/auth.unix.ip/channel
+ * % echo $domain $path $[now+DEFAULT_TTL] $options $anonuid $anongid $fsid > /proc/net/rpc/nfsd.export/channel
  */
 
 static int cache_export_ent(char *domain, struct exportent *exp, char *path)
@@ -943,7 +985,7 @@ static int cache_export_ent(char *domain, struct exportent *exp, char *path)
  */
 int cache_export(nfs_export *exp, char *path)
 {
-       char buf[INET_ADDRSTRLEN];
+       char buf[INET6_ADDRSTRLEN];
        int err;
        FILE *f;
 
@@ -953,9 +995,9 @@ int cache_export(nfs_export *exp, char *path)
 
 
        qword_print(f, "nfsd");
-       qword_print(f, 
+       qword_print(f,
                host_ntop(get_addrlist(exp->m_client, 0), buf, sizeof(buf)));
-       qword_printint(f, time(0)+30*60);
+       qword_printuint(f, time(0) + exp->m_export.e_ttl);
        qword_print(f, exp->m_client->m_hostname);
        err = qword_eol(f);