From 0b6eff3dc8fecff610264209d458ab9ca2344440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 2 Oct 2014 15:23:29 +0300 Subject: [PATCH v2 2/5] mountd: talk to kernel using file descriptors instead of FILE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Timo Teräs --- utils/mountd/cache.c | 343 +++++++++++++++++++++++++++------------------------ 1 file changed, 183 insertions(+), 160 deletions(-) diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c index 663a52a..c23d384 100644 --- a/utils/mountd/cache.c +++ b/utils/mountd/cache.c @@ -61,15 +61,13 @@ enum nfsd_fsid { * Record is terminated with newline. * */ -static int cache_export_ent(char *domain, struct exportent *exp, char *p); +static int cache_export_ent(char *buf, int buflen, char *domain, struct exportent *exp, char *path); #define INITIAL_MANAGED_GROUPS 100 -char *lbuf = NULL; -int lbuflen = 0; extern int use_ipaddr; -static void auth_unix_ip(FILE *f) +static void auth_unix_ip(int f) { /* requests are * class IP-ADDR @@ -78,23 +76,26 @@ static void auth_unix_ip(FILE *f) * * "nfsd" IP-ADDR expiry domainname */ - char *cp; char class[20]; char ipaddr[INET6_ADDRSTRLEN + 1]; char *client = NULL; struct addrinfo *tmp = NULL; - if (readline(fileno(f), &lbuf, &lbuflen) != 1) - return; + char buf[RPC_CHAN_BUF_SIZE], *bp; + int blen; + + blen = read(f, buf, sizeof(buf)); + if (blen <= 0 || buf[blen-1] != '\n') return; + buf[blen-1] = 0; - xlog(D_CALL, "auth_unix_ip: inbuf '%s'", lbuf); + xlog(D_CALL, "auth_unix_ip: inbuf '%s'", buf); - cp = lbuf; + bp = buf; - if (qword_get(&cp, class, 20) <= 0 || + if (qword_get(&bp, class, 20) <= 0 || strcmp(class, "nfsd") != 0) return; - if (qword_get(&cp, ipaddr, sizeof(ipaddr) - 1) <= 0) + if (qword_get(&bp, ipaddr, sizeof(ipaddr) - 1) <= 0) return; tmp = host_pton(ipaddr); @@ -113,16 +114,20 @@ static void auth_unix_ip(FILE *f) freeaddrinfo(ai); } } - qword_print(f, "nfsd"); - qword_print(f, ipaddr); - qword_printtimefrom(f, DEFAULT_TTL); + bp = buf; blen = sizeof(buf); + qword_add(&bp, &blen, "nfsd"); + qword_add(&bp, &blen, ipaddr); + qword_adduint(&bp, &blen, time(0) + DEFAULT_TTL); if (use_ipaddr) { memmove(ipaddr + 1, ipaddr, strlen(ipaddr) + 1); ipaddr[0] = '$'; - qword_print(f, ipaddr); + qword_add(&bp, &blen, ipaddr); } else if (client) - qword_print(f, *client?client:"DEFAULT"); - qword_eol(f); + qword_add(&bp, &blen, *client?client:"DEFAULT"); + qword_addeol(&bp, &blen); + if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) + xlog(L_ERROR, "auth_unix_ip: error writing reply"); + xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT"); free(client); @@ -130,7 +135,7 @@ static void auth_unix_ip(FILE *f) } -static void auth_unix_gid(FILE *f) +static void auth_unix_gid(int f) { /* Request are * uid @@ -144,7 +149,8 @@ static void auth_unix_gid(FILE *f) gid_t *more_groups; int ngroups; int rv, i; - char *cp; + char buf[RPC_CHAN_BUF_SIZE], *bp; + int blen; if (groups_len == 0) { groups = malloc(sizeof(gid_t) * INITIAL_MANAGED_GROUPS); @@ -156,11 +162,12 @@ static void auth_unix_gid(FILE *f) ngroups = groups_len; - if (readline(fileno(f), &lbuf, &lbuflen) != 1) - return; + blen = read(f, buf, sizeof(buf)); + if (blen <= 0 || buf[blen-1] != '\n') return; + buf[blen-1] = 0; - cp = lbuf; - if (qword_get_uint(&cp, &uid) != 0) + bp = buf; + if (qword_get_uint(&bp, &uid) != 0) return; pw = getpwuid(uid); @@ -180,15 +187,19 @@ static void auth_unix_gid(FILE *f) } } } - qword_printuint(f, uid); - qword_printtimefrom(f, DEFAULT_TTL); + + bp = buf; blen = sizeof(buf); + qword_adduint(&bp, &blen, uid); + qword_adduint(&bp, &blen, time(0) + DEFAULT_TTL); if (rv >= 0) { - qword_printuint(f, ngroups); + qword_adduint(&bp, &blen, ngroups); for (i=0; i 7) goto out; /* unknown type */ - if ((fsidlen = qword_get(&cp, fsid, 32)) <= 0) + if ((fsidlen = qword_get(&bp, fsid, 32)) <= 0) goto out; if (parse_fsid(fsidtype, fsidlen, fsid, &parsed)) goto out; @@ -796,12 +809,13 @@ static void nfsd_fh(FILE *f) } if (found) - if (cache_export_ent(dom, found, found_path) < 0) + if (cache_export_ent(buf, sizeof(buf), dom, found, found_path) < 0) found = 0; - qword_print(f, dom); - qword_printint(f, fsidtype); - qword_printhex(f, fsid, fsidlen); + bp = buf; blen = sizeof(buf); + qword_add(&bp, &blen, dom); + qword_addint(&bp, &blen, fsidtype); + qword_addhex(&bp, &blen, fsid, fsidlen); /* The fsid -> path lookup can be quite expensive as it * potentially stats and reads lots of devices, and some of those * might have spun-down. The Answer is not likely to @@ -810,20 +824,21 @@ static void nfsd_fh(FILE *f) * timeout. Maybe this should be configurable on the command * line. */ - qword_printint(f, 0x7fffffff); + qword_addint(&bp, &blen, 0x7fffffff); if (found) - qword_print(f, found_path); - qword_eol(f); - out: + qword_add(&bp, &blen, found_path); + qword_addeol(&bp, &blen); + if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) + xlog(L_ERROR, "nfsd_fh: error writing reply"); +out: if (found_path) free(found_path); freeaddrinfo(ai); free(dom); xlog(D_CALL, "nfsd_fh: found %p path %s", found, found ? found->e_path : NULL); - return; } -static void write_fsloc(FILE *f, struct exportent *ep) +static void write_fsloc(char **bp, int *blen, struct exportent *ep) { struct servers *servers; @@ -833,20 +848,20 @@ static void write_fsloc(FILE *f, struct exportent *ep) servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata); if (!servers) return; - qword_print(f, "fsloc"); - qword_printint(f, servers->h_num); + qword_add(bp, blen, "fsloc"); + qword_addint(bp, blen, servers->h_num); if (servers->h_num >= 0) { int i; for (i=0; ih_num; i++) { - qword_print(f, servers->h_mp[i]->h_host); - qword_print(f, servers->h_mp[i]->h_path); + qword_add(bp, blen, servers->h_mp[i]->h_host); + qword_add(bp, blen, servers->h_mp[i]->h_path); } } - qword_printint(f, servers->h_referral); + qword_addint(bp, blen, servers->h_referral); release_replicas(servers); } -static void write_secinfo(FILE *f, struct exportent *ep, int flag_mask) +static void write_secinfo(char **bp, int *blen, struct exportent *ep, int flag_mask) { struct sec_entry *p; @@ -857,45 +872,52 @@ static void write_secinfo(FILE *f, struct exportent *ep, int flag_mask) return; } fix_pseudoflavor_flags(ep); - qword_print(f, "secinfo"); - qword_printint(f, p - ep->e_secinfo); + qword_add(bp, blen, "secinfo"); + qword_addint(bp, blen, p - ep->e_secinfo); for (p = ep->e_secinfo; p->flav; p++) { - qword_printint(f, p->flav->fnum); - qword_printint(f, p->flags & flag_mask); + qword_addint(bp, blen, p->flav->fnum); + qword_addint(bp, blen, p->flags & flag_mask); } } -static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *exp) +static int dump_to_cache(int f, char *buf, int buflen, char *domain, char *path, struct exportent *exp) { - qword_print(f, domain); - qword_print(f, path); + char *bp = buf; + int blen = buflen; + time_t now = time(0); + + qword_add(&bp, &blen, domain); + qword_add(&bp, &blen, path); if (exp) { int different_fs = strcmp(path, exp->e_path) != 0; int flag_mask = different_fs ? ~NFSEXP_FSID : ~0; - qword_printtimefrom(f, exp->e_ttl); - qword_printint(f, exp->e_flags & flag_mask); - qword_printint(f, exp->e_anonuid); - qword_printint(f, exp->e_anongid); - qword_printint(f, exp->e_fsid); - write_fsloc(f, exp); - write_secinfo(f, exp, flag_mask); - if (exp->e_uuid == NULL || different_fs) { - char u[16]; - if (uuid_by_path(path, 0, 16, u)) { - qword_print(f, "uuid"); - qword_printhex(f, u, 16); - } - } else { - char u[16]; - get_uuid(exp->e_uuid, 16, u); - qword_print(f, "uuid"); - qword_printhex(f, u, 16); - } + qword_adduint(&bp, &blen, now + exp->e_ttl); + qword_addint(&bp, &blen, exp->e_flags & flag_mask); + qword_addint(&bp, &blen, exp->e_anonuid); + qword_addint(&bp, &blen, exp->e_anongid); + qword_addint(&bp, &blen, exp->e_fsid); + write_fsloc(&bp, &blen, exp); + write_secinfo(&bp, &blen, exp, flag_mask); + if (exp->e_uuid == NULL || different_fs) { + char u[16]; + if (uuid_by_path(path, 0, 16, u)) { + qword_add(&bp, &blen, "uuid"); + qword_addhex(&bp, &blen, u, 16); + } + } else { + char u[16]; + get_uuid(exp->e_uuid, 16, u); + qword_add(&bp, &blen, "uuid"); + qword_addhex(&bp, &blen, u, 16); + } } else - qword_printtimefrom(f, DEFAULT_TTL); - return qword_eol(f); + qword_adduint(&bp, &blen, now + DEFAULT_TTL); + qword_addeol(&bp, &blen); + if (blen <= 0) return -1; + if (write(f, buf, bp - buf) != bp - buf) return -1; + return 0; } static nfs_export * @@ -1245,27 +1267,27 @@ static struct exportent *lookup_junction(char *dom, const char *pathname, return exp; } -static void lookup_nonexport(FILE *f, char *dom, char *path, +static void lookup_nonexport(int f, char *buf, int buflen, char *dom, char *path, struct addrinfo *ai) { struct exportent *eep; eep = lookup_junction(dom, path, ai); - dump_to_cache(f, dom, path, eep); + dump_to_cache(f, buf, buflen, dom, path, eep); if (eep == NULL) return; exportent_release(eep); free(eep); } #else /* !HAVE_NFS_PLUGIN_H */ -static void lookup_nonexport(FILE *f, char *dom, char *path, +static void lookup_nonexport(int f, char *buf, int buflen, char *dom, char *path, struct addrinfo *UNUSED(ai)) { - dump_to_cache(f, dom, path, NULL); + dump_to_cache(f, buf, buflen, dom, path, NULL); } #endif /* !HAVE_NFS_PLUGIN_H */ -static void nfsd_export(FILE *f) +static void nfsd_export(int f) { /* requests are: * domain path @@ -1273,26 +1295,28 @@ static void nfsd_export(FILE *f) * domain path expiry flags anonuid anongid fsid */ - char *cp; char *dom, *path; nfs_export *found = NULL; struct addrinfo *ai = NULL; + char buf[RPC_CHAN_BUF_SIZE], *bp; + int blen; - if (readline(fileno(f), &lbuf, &lbuflen) != 1) - return; + blen = read(f, buf, sizeof(buf)); + if (blen <= 0 || buf[blen-1] != '\n') return; + buf[blen-1] = 0; - xlog(D_CALL, "nfsd_export: inbuf '%s'", lbuf); + xlog(D_CALL, "nfsd_export: inbuf '%s'", buf); - cp = lbuf; - dom = malloc(strlen(cp)); - path = malloc(strlen(cp)); + bp = buf; + dom = malloc(blen); + path = malloc(blen); if (!dom || !path) goto out; - if (qword_get(&cp, dom, strlen(lbuf)) <= 0) + if (qword_get(&bp, dom, blen) <= 0) goto out; - if (qword_get(&cp, path, strlen(lbuf)) <= 0) + if (qword_get(&bp, path, blen) <= 0) goto out; auth_reload(); @@ -1306,14 +1330,14 @@ static void nfsd_export(FILE *f) found = lookup_export(dom, path, ai); if (found) { - if (dump_to_cache(f, dom, path, &found->m_export) < 0) { + if (dump_to_cache(f, buf, sizeof(buf), dom, path, &found->m_export) < 0) { xlog(L_WARNING, "Cannot export %s, possibly unsupported filesystem" " or fsid= required", path); - dump_to_cache(f, dom, path, NULL); + dump_to_cache(f, buf, sizeof(buf), dom, path, NULL); } } else - lookup_nonexport(f, dom, path, ai); + lookup_nonexport(f, buf, sizeof(buf), dom, path, ai); out: xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL); @@ -1325,15 +1349,14 @@ static void nfsd_export(FILE *f) struct { char *cache_name; - void (*cache_handle)(FILE *f); - FILE *f; - char vbuf[RPC_CHAN_BUF_SIZE]; + void (*cache_handle)(int f); + int f; } 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, -1 }, + { "auth.unix.gid", auth_unix_gid, -1 }, + { "nfsd.export", nfsd_export, -1 }, + { "nfsd.fh", nfsd_fh, -1 }, + { NULL, NULL, -1 } }; extern int manage_gids; @@ -1350,11 +1373,7 @@ void cache_open(void) if (!manage_gids && cachelist[i].cache_handle == auth_unix_gid) 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); - } + cachelist[i].f = open(path, O_RDWR); } } @@ -1366,8 +1385,8 @@ void cache_set_fds(fd_set *fdset) { int i; for (i=0; cachelist[i].cache_name; i++) { - if (cachelist[i].f) - FD_SET(fileno(cachelist[i].f), fdset); + if (cachelist[i].f >= 0) + FD_SET(cachelist[i].f, fdset); } } @@ -1380,11 +1399,11 @@ int cache_process_req(fd_set *readfds) int i; int cnt = 0; for (i=0; cachelist[i].cache_name; i++) { - if (cachelist[i].f != NULL && - FD_ISSET(fileno(cachelist[i].f), readfds)) { + if (cachelist[i].f >= 0 && + FD_ISSET(cachelist[i].f, readfds)) { cnt++; cachelist[i].cache_handle(cachelist[i].f); - FD_CLR(fileno(cachelist[i].f), readfds); + FD_CLR(cachelist[i].f, readfds); } } return cnt; @@ -1397,14 +1416,14 @@ int cache_process_req(fd_set *readfds) * % 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) +static int cache_export_ent(char *buf, int buflen, char *domain, struct exportent *exp, char *path) { - int err; - FILE *f = fopen("/proc/net/rpc/nfsd.export/channel", "w"); - if (!f) - return -1; + int f, err; + + f = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); + if (f < 0) return -1; - err = dump_to_cache(f, domain, exp->e_path, exp); + err = dump_to_cache(f, buf, buflen, domain, exp->e_path, exp); if (err) { xlog(L_WARNING, "Cannot export %s, possibly unsupported filesystem or" @@ -1445,13 +1464,13 @@ static int cache_export_ent(char *domain, struct exportent *exp, char *path) continue; dev = stb.st_dev; path[l] = 0; - dump_to_cache(f, domain, path, exp); + dump_to_cache(f, buf, buflen, domain, path, exp); path[l] = c; } break; } - fclose(f); + close(f); return err; } @@ -1462,27 +1481,25 @@ static int cache_export_ent(char *domain, struct exportent *exp, char *path) */ int cache_export(nfs_export *exp, char *path) { - char buf[INET6_ADDRSTRLEN]; - int err; - FILE *f; + char ip[INET6_ADDRSTRLEN]; + char buf[RPC_CHAN_BUF_SIZE], *bp; + int blen, f; - f = fopen("/proc/net/rpc/auth.unix.ip/channel", "w"); - if (!f) + f = open("/proc/net/rpc/auth.unix.ip/channel", O_WRONLY); + if (f < 0) return -1; - - qword_print(f, "nfsd"); - qword_print(f, - host_ntop(get_addrlist(exp->m_client, 0), buf, sizeof(buf))); - qword_printtimefrom(f, exp->m_export.e_ttl); - qword_print(f, exp->m_client->m_hostname); - err = qword_eol(f); - - fclose(f); - - err = cache_export_ent(exp->m_client->m_hostname, &exp->m_export, path) - || err; - return err; + bp = buf, blen = sizeof(buf); + qword_add(&bp, &blen, "nfsd"); + qword_add(&bp, &blen, host_ntop(get_addrlist(exp->m_client, 0), ip, sizeof(ip))); + qword_adduint(&bp, &blen, time(0) + exp->m_export.e_ttl); + qword_add(&bp, &blen, exp->m_client->m_hostname); + qword_addeol(&bp, &blen); + if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) blen = -1; + close(f); + if (blen < 0) return -1; + + return cache_export_ent(buf, sizeof(buf), exp->m_client->m_hostname, &exp->m_export, path); } /** @@ -1501,27 +1518,33 @@ int cache_export(nfs_export *exp, char *path) struct nfs_fh_len * cache_get_filehandle(nfs_export *exp, int len, char *p) { - FILE *f = fopen("/proc/fs/nfsd/filehandle", "r+"); - char buf[200]; - char *bp = buf; - int failed; static struct nfs_fh_len fh; + char buf[RPC_CHAN_BUF_SIZE], *bp; + int blen, f; + + f = open("/proc/fs/nfsd/filehandle", O_RDWR); + if (f < 0) { + f = open("/proc/fs/nfs/filehandle", O_RDWR); + if (f < 0) return NULL; + } - if (!f) - f = fopen("/proc/fs/nfs/filehandle", "r+"); - if (!f) + bp = buf, blen = sizeof(buf); + qword_add(&bp, &blen, exp->m_client->m_hostname); + qword_add(&bp, &blen, p); + qword_addint(&bp, &blen, len); + qword_addeol(&bp, &blen); + if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) { + close(f); return NULL; + } + bp = buf; + blen = read(f, buf, sizeof(buf)); + close(f); - qword_print(f, exp->m_client->m_hostname); - qword_print(f, p); - qword_printint(f, len); - failed = qword_eol(f); - - if (!failed) - failed = (fgets(buf, sizeof(buf), f) == NULL); - fclose(f); - if (failed) + if (blen <= 0 || buf[blen-1] != '\n') return NULL; + buf[blen-1] = 0; + memset(fh.fh_handle, 0, sizeof(fh.fh_handle)); fh.fh_size = qword_get(&bp, (char *)fh.fh_handle, NFS3_FHSIZE); return &fh; -- 2.1.2