* Record is terminated with newline.
*
*/
-int cache_export_ent(char *domain, struct exportent *exp);
+int cache_export_ent(char *domain, struct exportent *exp, char *p);
char *lbuf = NULL;
}
if (found)
- cache_export_ent(dom, found);
+ cache_export_ent(dom, found, found->e_path);
qword_print(f, dom);
qword_printint(f, fsidtype);
qword_printhex(f, fsid, fsidlen);
- qword_printint(f, time(0)+30*60);
+ /* 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
+ * change underneath us, and an 'exportfs -f' can always
+ * remove this from the kernel, so use a really log
+ * timeout. Maybe this should be configurable on the command
+ * line.
+ */
+ qword_printint(f, 0x7fffffff);
if (found)
qword_print(f, found->e_path);
qword_eol(f);
write_fsloc(f, exp, path);
if (exp->e_uuid == NULL) {
char u[16];
- if (get_uuid(exp->e_path, NULL, 16, u)) {
+ if (get_uuid(path, NULL, 16, u)) {
qword_print(f, "uuid");
qword_printhex(f, u, 16);
}
int i;
char *dom, *path;
nfs_export *exp, *found = NULL;
+ int found_type = 0;
if (readline(fileno(f), &lbuf, &lbuflen) != 1)
continue;
if (strcmp(path, exp->m_export.e_path))
continue;
- if (!found)
+ if (!found) {
found = exp;
- else {
- xlog(L_WARNING, "%s exported to both %s and %s in %s",
- path, exp->m_client->m_hostname, found->m_client->m_hostname,
+ found_type = i;
+ } else if (found_type == i && found->m_warned == 0) {
+ xlog(L_WARNING, "%s exported to both %s and %s, "
+ "arbitrarily choosing options from first",
+ path, found->m_client->m_hostname, exp->m_client->m_hostname,
dom);
+ found->m_warned = 1;
}
}
}
* % echo $domain $path $[now+30*60] $options $anonuid $anongid $fsid > /proc/net/rpc/nfsd.export/channel
*/
-int cache_export_ent(char *domain, struct exportent *exp)
+int cache_export_ent(char *domain, struct exportent *exp, char *path)
{
int err;
FILE *f = fopen("/proc/net/rpc/nfsd.export/channel", "w");
return -1;
err = dump_to_cache(f, domain, exp->e_path, exp);
- fclose(f);
mountlist_add(domain, exp->e_path);
+
+ while ((exp->e_flags & NFSEXP_CROSSMOUNT) && path) {
+ /* really an 'if', but we can break out of
+ * a 'while' more easily */
+ /* Look along 'path' for other filesystems
+ * and export them with the same options
+ */
+ struct stat stb;
+ int l = strlen(exp->e_path);
+ int dev;
+
+ if (strlen(path) <= l || path[l] != '/' ||
+ strncmp(exp->e_path, path, l) != 0)
+ break;
+ if (stat(exp->e_path, &stb) != 0)
+ break;
+ dev = stb.st_dev;
+ while(path[l] == '/') {
+ char c;
+ int err;
+
+ l++;
+ while (path[l] != '/' && path[l])
+ l++;
+ c = path[l];
+ path[l] = 0;
+ err = lstat(path, &stb);
+ path[l] = c;
+ if (err < 0)
+ break;
+ if (stb.st_dev == dev)
+ continue;
+ dev = stb.st_dev;
+ path[l] = 0;
+ dump_to_cache(f, domain, path, exp);
+ path[l] = c;
+ }
+ break;
+ }
+
+ fclose(f);
return err;
}
-int cache_export(nfs_export *exp)
+int cache_export(nfs_export *exp, char *path)
{
int err;
FILE *f;
- if (exp->m_export.e_maptype != CLE_MAP_IDENT) {
- xlog(L_ERROR, "%s: unsupported mapping; kernel supports only 'identity' (default)",
- exp->m_export.m_path);
- return -1;
- }
-
f = fopen("/proc/net/rpc/auth.unix.ip/channel", "w");
if (!f)
return -1;
fclose(f);
- err = cache_export_ent(exp->m_client->m_hostname, &exp->m_export)
+ err = cache_export_ent(exp->m_client->m_hostname, &exp->m_export, path)
|| err;
return err;
}