From 59ad91a880695808c5b4efe88fa46286662e4cfc Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Thu, 30 Dec 2010 10:12:14 +0000 Subject: unfs-server: Fix PV so it obeys the version number policy Signed-off-by: Richard Purdie --- .../unfs-server-2.1+2.2beta47/006-reiserfs.patch | 1272 ++++++++++++++++++++ 1 file changed, 1272 insertions(+) create mode 100644 meta/recipes-devtools/unfs-server/unfs-server-2.1+2.2beta47/006-reiserfs.patch (limited to 'meta/recipes-devtools/unfs-server/unfs-server-2.1+2.2beta47/006-reiserfs.patch') diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.1+2.2beta47/006-reiserfs.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.1+2.2beta47/006-reiserfs.patch new file mode 100644 index 0000000000..abdc67476e --- /dev/null +++ b/meta/recipes-devtools/unfs-server/unfs-server-2.1+2.2beta47/006-reiserfs.patch @@ -0,0 +1,1272 @@ +# Patch origin: nfs-server source RPM from openSUSE 10.3 + +--- nfs-server/Makefile.in ++++ nfs-server/Makefile.in 2002/11/08 13:59:16 +@@ -100,7 +100,7 @@ + utimes.c mkdir.c rename.c getopt.c getopt_long.c \ + alloca.c mountlist.c xmalloc.c \ + xstrdup.c strdup.c strstr.c nfsmounted.c faccess.c \ +- haccess.c daemon.c signals.c ++ haccess.c daemon.c signals.c teahash3.c + XDRFILES = mount.x nfs_prot.x + GENFILES = mount.h mount_xdr.c mount_svc.c nfs_prot.h nfs_prot_xdr.c \ + ugid.h ugid_xdr.c ugid_clnt.c +@@ -112,7 +112,7 @@ + MANPAGES8 = showmount + MANPAGES = $(MANPAGES5) $(MANPAGES8p) $(MANPAGES8) + LIBOBJS = version.o fsusage.o mountlist.o xmalloc.o xstrdup.o \ +- nfsmounted.o faccess.o haccess.o daemon.o \ ++ nfsmounted.o faccess.o haccess.o daemon.o teahash3.o \ + signals.o @LIBOBJS@ @ALLOCA@ + OBJS = logging.o fh.o devtab.o auth_init.o auth_clnt.o auth.o + NFSD_OBJS = nfsd.o rpcmisc.o nfs_dispatch.o getattr.o setattr.o \ +--- nfs-server/auth.c ++++ nfs-server/auth.c 2002/11/08 13:59:16 +@@ -83,6 +83,7 @@ + 0, /* read-only */ + 0, /* relative links */ + 0, /* noaccess */ ++ 0, /* hashed inodes */ + 1, /* cross_mounts */ + 1, /* allow setuid */ + 65534, /* default uid */ +@@ -100,6 +101,7 @@ + 0, /* relative links */ + 0, /* noaccess */ + 1, /* cross_mounts */ ++ 0, /* hashed inodes */ + 0, /* allow setuid */ + 65534, /* default uid */ + 65534, /* default gid */ +@@ -991,6 +993,7 @@ + if (mp == 0) { + mp = (nfs_mount*) xmalloc(sizeof(nfs_mount)); + memset(mp, 0, sizeof(*mp)); ++ mp->mount_dev = 0; + mp->origin = cp; + mp->client = cp; + mp->path = xstrdup(path); +@@ -1169,6 +1172,8 @@ + default_options.nobody_gid = anon_gid; + anonymous_options.nobody_uid = anon_uid; + anonymous_options.nobody_gid = anon_gid; ++ default_options.cross_mounts = cross_mounts; ++ default_options.hashed_inodes = hashed_inodes; + + memset(cached_clients, 0, sizeof(cached_clients)); + cached_next = 0; +--- nfs-server/auth.h ++++ nfs-server/auth.h 2002/11/08 13:59:16 +@@ -43,15 +43,16 @@ + + typedef struct nfs_options { + ugid_mapping_t uidmap; /* uid/gid mapping behavior */ +- int root_squash; +- int all_squash; +- int some_squash; /* speed up luid() etc. */ +- int secure_port; +- int read_only; +- int link_relative; +- int noaccess; +- int cross_mounts; +- int allow_setuid; ++ unsigned root_squash : 1; ++ unsigned all_squash : 1; ++ unsigned some_squash : 1; /* speed up luid() etc. */ ++ unsigned secure_port : 1; ++ unsigned read_only : 1; ++ unsigned link_relative : 1; ++ unsigned noaccess : 1; ++ unsigned cross_mounts : 1; ++ unsigned hashed_inodes : 1; ++ unsigned allow_setuid : 1; + uid_t nobody_uid; + gid_t nobody_gid; + char * clnt_nisdomain; +@@ -64,6 +65,7 @@ + int length; + char * path; + nfs_options o; ++ dev_t mount_dev; + /* Original NFS client */ + struct nfs_client * origin; + } nfs_mount; +@@ -121,6 +123,8 @@ + extern void auth_check_all_netmasks(void); + extern void auth_sort_all_mountlists(void); + extern void auth_log_all(void); ++extern int auth_checkdev(nfs_mount *, dev_t dev); ++extern int auth_checkpathdev(char *, dev_t dev); + + /* This function lets us set our euid/fsuid temporarily */ + extern void auth_override_uid(uid_t); +--- nfs-server/auth_clnt.c ++++ nfs-server/auth_clnt.c 2002/11/08 13:59:16 +@@ -89,6 +89,13 @@ + return NULL; + } + ++ if (!mp->o.cross_mounts && !mp->mount_dev) { ++ struct stat st; ++ if (!lstat(mp->path, &st) < 0) ++ return NULL; ++ mp->mount_dev = st.st_dev; ++ } ++ + /* Check request originated on a privileged port. */ + if (!allow_non_root && mp->o.secure_port + && !SECURE_PORT(svc_getcaller(rqstp->rq_xprt)->sin_port)) { +@@ -350,3 +357,28 @@ + return 1; + } + #endif ++ ++int auth_checkpathdev(char *path, dev_t dev) ++{ ++ nfs_mount *mp = auth_match_mount(nfsclient, path); ++ if (!mp) ++ return 0; ++ return auth_checkdev(mp, dev); ++} ++ ++int auth_checkdev(nfs_mount *mp, dev_t dev) ++{ ++ if (!mp->mount_dev) ++ return 1; ++ if (mp->mount_dev != dev) { ++ struct stat st; ++ /* Restat in case the cd switched */ ++ if (efs_lstat(mp->path, &st) < 0) { ++ Dprintf(L_ERROR, "Unable to stat mount point %s\n", mp->path); ++ return 0; ++ } ++ mp->mount_dev = st.st_dev; ++ } ++ return mp->mount_dev == dev; ++} ++ +--- nfs-server/auth_init.c ++++ nfs-server/auth_init.c 2002/11/08 13:59:16 +@@ -320,6 +320,14 @@ + /* knfsd compatibility, ignore */; + else ifkwd(4, "sync") + /* knfsd compatibility, ignore */; ++ else ifkwd(13, "hashed_inodes") ++ mp->o.hashed_inodes = 1; ++ else ifkwd(16, "no_hashed_inodes") ++ mp->o.hashed_inodes = 0; ++ else ifkwd(12, "cross_mounts") ++ mp->o.cross_mounts = 1; ++ else ifkwd(15, "no_cross_mounts") ++ mp->o.cross_mounts = 0; + else { + Dprintf(L_ERROR, + "Unknown keyword \"%.*s\" in export file\n", +--- nfs-server/exports.man ++++ nfs-server/exports.man 2002/11/08 13:59:16 +@@ -208,6 +208,17 @@ + .IR no_all_squash , + which is the default setting. + .TP ++.IR hashed_inodes ++Use a special scheme to generate inode numbers that may work better with ++reiserfs filesystems. ++.IR no_hashed_inodes ++which uses a direct mapping is the default. ++.TP ++.IR cross_mounts ++Do not cross mount points in exports. Turning this off with ++.IR no_cross_mounts ++avoids inode number space conflicts when there are too many files. ++.TP + .IR map_daemon + This option turns on dynamic uid/gid mapping. Each uid in an NFS request + will be translated to the equivalent server uid, and each uid in an +--- nfs-server/fh.c ++++ nfs-server/fh.c 2002/11/08 14:11:31 +@@ -4,8 +4,9 @@ + * + * Interfaces: + * pseudo_inode +- * mostly used internally, but also called from unfsd.c +- * when reporting directory contents. ++ * mostly used internally, for hash tables ++ * visible_inode ++ * generate visible inode shown to the client in the fattr. + * fh_init + * Initializes the queues and 'flush' timer + * fh_pr +@@ -47,6 +48,8 @@ + * Note: the original code mistakenly assumes that the overall path + * length remains within the value given by PATH_MAX... that leads + * to interesting buffer overflows all over the place. ++ * ++ * Depends that dev_t only uses 16bits. + */ + + #include +@@ -137,9 +140,9 @@ + }; + + /* Forward declared local functions */ +-static psi_t path_psi(char *, nfsstat *, struct stat *, int); ++static psi_t path_psi(char *, nfsstat *, struct stat *, int, int *); + static psi_t path_psi_m(char *, nfsstat *, struct stat *, +- struct stat *, int); ++ struct stat *, int, int *); + static int fh_flush_fds(void); + static char * fh_dump(svc_fh *); + static void fh_insert_fdcache(fhcache *fhc); +@@ -173,19 +176,22 @@ + fh_list_size++; + + /* Insert into hash tab. */ +- hash_slot = &(fh_hashed[fhc->h.psi % HASH_TAB_SIZE]); ++ hash_slot = &(fh_hashed[pseudo_inode(fhc->h.ino,fhc->h.dev) % HASH_TAB_SIZE]); + fhc->hash_next = *hash_slot; + *hash_slot = fhc; + } + + static fhcache * +-fh_lookup(psi_t psi) ++fh_lookup(ino_t ino, dev_t dev) + { + register fhcache *fhc; + +- fhc = fh_hashed[psi % HASH_TAB_SIZE]; +- while (fhc != NULL && fhc->h.psi != psi) ++ fhc = fh_hashed[pseudo_inode(ino,dev) % HASH_TAB_SIZE]; ++ while (fhc != NULL) { ++ if (fhc->h.ino == ino && fhc->h.dev == dev) ++ break; + fhc = fhc->hash_next; ++ } + return (fhc); + } + +@@ -193,7 +199,8 @@ + fh_insert_fdcache(fhcache *fhc) + { + #ifdef FHTRACE +- Dprintf(D_FHTRACE, "insert fh %x into fdcache @%d\n", fhc->h.psi, fhc->fd); ++ Dprintf(D_FHTRACE, "insert fh %x,%x into fdcache @%d\n", ++ fhc->h.ino, fhc->h.dev, fhc->fd); + if (fhc->fd < 0) { + fh_complain("fd cache bug: bad fd", fhc); + return; +@@ -289,8 +296,9 @@ + #endif + + Dprintf(D_FHTRACE|D_FHCACHE, +- "fh_delete: deleting handle %x ('%s', fd=%d)\n", +- fhc, fhc->path ? fhc->path : "", fhc->fd); ++ "fh_delete: deleting handle %x [%x,%x] ('%s', fd=%d)\n", ++ fhc, fhc->h.dev, fhc->h.ino, fhc->path ? fhc->path : "", ++ fhc->fd); + + /* Remove from current posn */ + fhc->prev->next = fhc->next; +@@ -298,7 +306,7 @@ + fh_list_size--; + + /* Remove from hash tab */ +- hash_slot = &(fh_hashed[fhc->h.psi % HASH_TAB_SIZE]); ++ hash_slot = &(fh_hashed[pseudo_inode(fhc->h.ino,fhc->h.dev) % HASH_TAB_SIZE]); + while (*hash_slot != NULL && *hash_slot != fhc) + hash_slot = &((*hash_slot)->hash_next); + if (*hash_slot == NULL) +@@ -528,6 +536,7 @@ + index -= 8; + } + ++#if 0 + /* If we have an XXL inode number, spew out warning (but at most + * once a second) */ + if (inode & ~mask) { +@@ -541,14 +550,34 @@ + } + inode &= mask; + } +- ++#endif + return (psi_t) (prefix | inode); + #endif + } + ++/* Inode as handed out by attr calls. */ ++psi_t ++visible_inode(ino_t ino, dev_t dev, nfs_mount *mount) ++{ ++ if (!mount->o.cross_mounts) ++ return ino; ++ ++ if (mount->o.hashed_inodes) { ++ extern __u32 teahash3(/*u32 k[2], *//*u8*/const char *msg, int len); ++ ++ struct { ++ ino_t ino; ++ dev_t dev; ++ } tup = { ino,dev }; ++ return teahash3((char *) &tup, sizeof tup); ++ } ++ ++ return pseudo_inode(ino, dev); ++} ++ + #if 1 + static char * +-fh_buildpath(svc_fh *h) ++fh_buildpath(svc_fh *h, dev_t basedev) + { + char pathbuf[PATH_MAX + NAME_MAX + 1], *path; + long cookie_stack[HP_LEN + 1]; +@@ -565,13 +594,17 @@ + + if (efs_stat("/", &sbuf) < 0) + return (NULL); +- psi = pseudo_inode(sbuf.st_ino, sbuf.st_dev); + if (h->hash_path[0] == 0) { +- if (psi != h->psi) +- return (NULL); +- return xstrdup("/"); ++ if (sbuf.st_ino == h->ino && sbuf.st_dev == h->dev) ++ ; ++ else ++ return NULL; ++ strcpy(pathbuf,"/"); ++ path = xstrdup(pathbuf); ++ return (path); + } + ++ psi = pseudo_inode(sbuf.st_ino, sbuf.st_dev); + if (hash_psi(psi) != h->hash_path[1]) + return (NULL); + +@@ -599,11 +632,18 @@ + + psi = pseudo_inode(dp->d_ino, sbuf.st_dev); + if (i == h->hash_path[0] + 1) { +- if (psi != h->psi) ++ if (sbuf.st_dev != h->dev || dp->d_ino != h->ino) + continue; + /* GOT IT */ + strcpy(pathbuf + pathlen, dp->d_name); +- path = xstrdup(pathbuf); ++ if (!basedev || sbuf.st_dev == basedev || ++ auth_checkpathdev(pathbuf, sbuf.st_dev)) { ++ path = xstrdup(pathbuf); ++ } else { ++ dprintf(L_ERROR, "fh_buildpath: basedev %x != dev %x for %s\n", ++ (unsigned)basedev,(unsigned)sbuf.st_dev,pathbuf); ++ path = NULL; ++ } + efs_closedir(dir); + auth_override_uid(auth_uid); + return (path); +@@ -754,16 +794,16 @@ + #endif + + static psi_t +-path_psi(char *path, nfsstat *status, struct stat *sbp, int svalid) ++path_psi(char *path, nfsstat *status, struct stat *sbp, int svalid, int *mp) + { + struct stat smounted; + +- return path_psi_m(path, status, sbp, &smounted, svalid); ++ return path_psi_m(path, status, sbp, &smounted, svalid, mp); + } + + static psi_t + path_psi_m(char *path, nfsstat *status, +- struct stat *sbp, struct stat *mbp, int svalid) ++ struct stat *sbp, struct stat *mbp, int svalid, int *mp) + { + struct stat sbuf, ddbuf; + +@@ -815,6 +855,8 @@ + DIR *dirp; + struct dirent *dp; + ++ if (mp) *mp = 1; ++ + errno = 0; + dirp = efs_opendir(dname); + fname[-1] = '/'; /* Restore path */ +@@ -860,9 +902,70 @@ + } + + fhcache * +-fh_find(svc_fh *h, int mode) ++fh_newfh(svc_fh *h, int mode, dev_t basedev) ++{ ++ fhcache *fhc, *flush; ++ ++ ex_state = active; ++ for (flush = fh_tail.prev; fh_list_size > FH_CACHE_LIMIT; flush = fhc) { ++ /* Don't flush current head. */ ++ if (flush == &fh_head) ++ break; ++ fhc = flush->prev; ++ fh_delete(flush); ++ } ++ fhc = (fhcache *) xmalloc(sizeof *fhc); ++ if (mode == FHFIND_FCREATE) { ++ /* File will be created */ ++ fhc->path = NULL; ++ } else { ++ /* File must exist. Attempt to construct from hash_path */ ++ char *path; ++ ++ if ((path = fh_buildpath(h, basedev)) == NULL) { ++#ifdef FHTRACE ++ Dprintf(D_FHTRACE, "fh_find: stale fh (hash path)\n"); ++ Dprintf(D_FHTRACE, "\tdata: %s\n", fh_dump(h)); ++#endif ++ free(fhc); ++ ex_state = inactive; ++ return NULL; ++ } ++ fhc->path = path; ++ } ++ fhc->flags = 0; ++ if (fhc->path && efs_lstat(fhc->path, &fhc->attrs) >= 0) { ++ if (re_export && nfsmounted(fhc->path, &fhc->attrs)) ++ fhc->flags |= FHC_NFSMOUNTED; ++ fhc->flags |= FHC_ATTRVALID; ++ } ++ fhc->fd = -1; ++ fhc->last_used = curtime; ++ fhc->h = *h; ++ fhc->last_clnt = NULL; ++ fhc->last_mount = NULL; ++ fhc->last_uid = (uid_t)-1; ++ fhc->fd_next = fhc->fd_prev = NULL; ++ fh_inserthead(fhc); ++ Dprintf(D_FHCACHE, ++ "fh_find: created new handle %x (path `%s' ino:%x dev:%x)\n", ++ fhc, fhc->path ? fhc->path : "", fhc->h.ino, fhc->h.dev); ++ ex_state = inactive; ++ if (fh_list_size > FH_CACHE_LIMIT) ++ flush_cache(0); ++#ifdef FHTRACE ++ if (fhc->h.hash_path[0] == 0xFF) { ++ Dprintf(L_ERROR, "newly created fh instantly flushed?!"); ++ return NULL; ++ } ++#endif ++ return (fhc); ++} ++ ++fhcache * ++fh_find(svc_fh *h, int mode, dev_t basedev) + { +- register fhcache *fhc, *flush; ++ register fhcache *fhc; + int check; + + check = (mode & FHFIND_CHECK); +@@ -877,12 +980,12 @@ + + ex_state = active; + time(&curtime); +- while ((fhc = fh_lookup(h->psi)) != NULL) { ++ while ((fhc = fh_lookup(h->ino,h->dev)) != NULL) { + struct stat sbuf, *s = NULL; + nfsstat dummy; + +- Dprintf(D_FHCACHE, "fh_find: psi=%lx... found '%s', fd=%d\n", +- (unsigned long) h->psi, ++ Dprintf(D_FHCACHE, "fh_find: (%u,%u)... found '%s', fd=%d\n", ++ h->ino, h->dev, + fhc->path ? fhc->path : "", + fhc->fd); + +@@ -905,6 +1008,7 @@ + Dprintf(D_FHTRACE, + "fh_find: stale fh: lstat: %m\n"); + } else { ++ int mp = 0; + /* If device/ino don't match, fhc->path may + * be a mount point (hence lstat() returns + * a different inode number than the readdir() +@@ -915,19 +1019,26 @@ + + /* Get the dev/ino of the underlying + * mount point. */ +- path_psi(fhc->path, &dummy, s, 1); +- if (fh_attrmatch(fhc, s)) +- goto fh_return; ++ if (path_psi(fhc->path, &dummy, s, 1, &mp) && ++ fh_attrmatch(fhc, s)) { ++ if (!mp) ++ Dprintf(D_FHTRACE,"fh_find: should be mount point %x,%x\n", ++ h->dev,h->ino); ++ ++ } + +- Dprintf(D_FHTRACE, "fh_find: stale fh: %lx", +- (unsigned long) h->psi); ++ Dprintf(D_FHTRACE, "fh_find: stale fh: " ++ "dev/ino %x/%lx ino:%x dev:%x", ++ s->st_dev, s->st_ino, ++ (unsigned)h->ino, (unsigned)h->dev); + } + + fh_discard: + #ifdef FHTRACE + Dprintf(D_FHTRACE, "\tdata: %s\n", fh_dump(h)); + #endif +- Dprintf(D_FHCACHE, "fh_find: delete cached handle\n"); ++ Dprintf(D_FHCACHE, "fh_find: delete cached handle %x,%x <%x>\n", ++ fhc->h.dev,fhc->h.ino,fhc->path ? fhc->path : "no path"); + fh_delete(fhc); + break; + } +@@ -947,88 +1058,13 @@ + return (fhc); + } + +- Dprintf(D_FHCACHE, "fh_find: psi=%lx... not found\n", +- (unsigned long) h->psi); +- +- if (mode == FHFIND_FCACHED) { +- ex_state = inactive; +- return NULL; +- } +- +- for (flush = fh_tail.prev; fh_list_size > FH_CACHE_LIMIT; flush = fhc) { +- /* Don't flush current head. */ +- if (flush == &fh_head) +- break; +- fhc = flush->prev; +- fh_delete(flush); +- } +- +- fhc = (fhcache *) xmalloc(sizeof *fhc); +- if (mode == FHFIND_FCREATE) { +- /* File will be created */ +- fhc->path = NULL; +- } else { +- /* File must exist. Attempt to construct from hash_path */ +- char *path; +- +- if ((path = fh_buildpath(h)) == NULL) { +-#ifdef FHTRACE +- Dprintf(D_FHTRACE, "fh_find: stale fh (hash path)\n"); +- Dprintf(D_FHTRACE, "\tdata: %s\n", fh_dump(h)); +-#endif +- free(fhc); +- ex_state = inactive; +- return NULL; +- } +- fhc->path = path; +- } +- +- fhc->flags = 0; +- if (fhc->path && efs_lstat(fhc->path, &fhc->attrs) >= 0) { +- if (nfsmounted(fhc->path, &fhc->attrs)) { +- fhc->flags |= FHC_NFSMOUNTED; +-#if 0 +- /* We must allow the client to send us the +- * file handle for the NFS mount point itself, +- * but not for entries within an NFS mount. +- * XXX: needs fixing. +- */ +- if (!re_export) { +- Dprintf(D_FHTRACE, +- "Attempt to use %s (non-exportable)\n", +- fhc->path); +- free(fhc); +- ex_state = inactive; +- return NULL; +- } +-#endif +- } +- fhc->flags |= FHC_ATTRVALID; +- fhc->dev = fhc->attrs.st_dev; +- fhc->ino = fhc->attrs.st_ino; +- fhc->type = fhc->attrs.st_mode & S_IFMT; +- } +- fhc->fd = -1; +- fhc->last_used = curtime; +- fhc->h = *h; +- fhc->last_clnt = NULL; +- fhc->last_mount = NULL; +- fhc->last_uid = (uid_t)-1; +- fhc->fd_next = fhc->fd_prev = NULL; +- fh_inserthead(fhc); +- Dprintf(D_FHCACHE, +- "fh_find: created new handle %x (path `%s' psi %08x)\n", +- fhc, fhc->path ? fhc->path : "", fhc->h.psi); + ex_state = inactive; +- if (fh_list_size > FH_CACHE_LIMIT) +- flush_cache(0); +-#ifdef FHTRACE +- if (fhc->h.hash_path[0] == 0xFF) { +- Dprintf(L_ERROR, "newly created fh instantly flushed?!"); ++ ++ Dprintf(D_FHCACHE, "fh_find: (%u,%u) ... not found\n", ++ h->ino, h->dev); ++ if (mode == FHFIND_FCACHED) + return NULL; +- } +-#endif +- return (fhc); ++ return fh_newfh(h, mode, basedev); + } + + /* +@@ -1040,7 +1076,7 @@ + { + fhcache *h; + +- if ((h = fh_find((svc_fh *) fh, FHFIND_FCACHED)) == NULL) ++ if ((h = fh_find((svc_fh *) fh, FHFIND_FCACHED, 0)) == NULL) + return fh_dump((svc_fh *) fh); + return (h->path); + } +@@ -1050,10 +1086,10 @@ + { + static char buf[65]; + char *sp; +- int i, n = fh->hash_path[0]; ++ int i, n = fh->hash_path[0], l; + +- sprintf(buf, "%08x %02x ", fh->psi, fh->hash_path[0]); +- for (i = 1, sp = buf + 12; i <= n && i < HP_LEN; i++, sp += 2) ++ l = sprintf(buf, "%08x %04x %02x ", fh->ino, fh->dev, fh->hash_path[0]); ++ for (i = 1, sp = buf + l; i <= n && i < HP_LEN; i++, sp += 2) + sprintf(sp, "%02x", fh->hash_path[i]); + return buf; + } +@@ -1082,7 +1118,7 @@ + + memset(&key, 0, sizeof(key)); + status = NFS_OK; +- if ((psi = path_psi("/", &status, &stb, 0)) == 0) ++ if ((psi = path_psi("/", &status, &stb, 0, NULL)) == 0) + return ((int) status); + + s = path; +@@ -1091,7 +1127,7 @@ + return ((int) NFSERR_NAMETOOLONG); + key.hash_path[key.hash_path[0]] = hash_psi(psi); + *s = '\0'; +- if ((psi = path_psi(path, &status, &stb, 0)) == 0) ++ if ((psi = path_psi(path, &status, &stb, 0, NULL)) == 0) + return ((int) status); + *s = '/'; + } +@@ -1099,11 +1135,12 @@ + if (++(key.hash_path[0]) >= HP_LEN) + return ((int) NFSERR_NAMETOOLONG); + key.hash_path[key.hash_path[0]] = hash_psi(psi); +- if ((psi = path_psi(path, &status, &stb, 0)) == 0) ++ if ((psi = path_psi(path, &status, &stb, 0, NULL)) == 0) + return ((int) status); + } +- key.psi = psi; +- h = fh_find(&key, FHFIND_FCREATE); ++ key.dev = stb.st_dev; ++ key.ino = stb.st_ino; ++ h = fh_find(&key, FHFIND_FCREATE, 0); + + #ifdef FHTRACE + if (!h) +@@ -1123,6 +1160,7 @@ + return ((int) status); + } + ++#if 0 + char * + fh_path(nfs_fh *fh, nfsstat *status) + { +@@ -1135,6 +1173,7 @@ + *status = NFS_OK; + return (h->path); + } ++#endif + + nfs_fh * + fh_handle(fhcache *h) +@@ -1349,7 +1388,7 @@ + if (sbp == NULL) + sbp = &sbuf; + +- if ((dirh = fh_find((svc_fh *) &dopa->dir, FHFIND_FEXISTS)) == NULL) ++ if ((dirh = fh_find((svc_fh *) &dopa->dir, FHFIND_FEXISTS, 0)) == NULL) + return NFSERR_STALE; + + /* +@@ -1419,8 +1458,22 @@ + + *new_fh = dopa->dir; + key = (svc_fh *) new_fh; +- if ((key->psi = path_psi_m(pathbuf, &ret, sbp, &smount, 0)) == 0) ++ ++ if (path_psi_m(pathbuf, &ret, sbp, &smount, 0, NULL) == 0) + return (ret); ++ key->ino = sbp->st_ino; ++ key->dev = sbp->st_dev; ++ ++ if (sbp->st_dev != dirh->h.dev) { ++ nfs_mount *mp = dirh->last_mount; ++ if (!mp) ++ Dprintf(L_ERROR, "no last mount in fh_compose for %s\n", pathbuf); ++ else if (auth_checkdev(mp, sbp->st_dev) == 0) { ++ Dprintf(L_ERROR, "access to no cross path below mountpoint (<%s>, %x<->%x)\n", ++ pathbuf, mp->mount_dev, sbp->st_dev); ++ return NFSERR_STALE; ++ } ++ } + + if (is_dd) { + /* Don't cd .. from root, or mysterious ailments will +@@ -1430,11 +1483,12 @@ + } else { + if (++(key->hash_path[0]) >= HP_LEN) + return NFSERR_NAMETOOLONG; +- key->hash_path[key->hash_path[0]] = hash_psi(dirh->h.psi); ++ key->hash_path[key->hash_path[0]] = hash_psi(pseudo_inode(dirh->h.ino, ++ dirh->h.dev)); + } + /* FIXME: when crossing a mount point, we'll find the real + * dev/ino in sbp and can store it in h... */ +- h = fh_find(key, FHFIND_FCREATE); ++ h = fh_find(key, FHFIND_FCREATE, 0); + + #ifdef FHTRACE + if (h == NULL) +@@ -1456,7 +1510,7 @@ + /* We must have cached an old file under the same inode # */ + Dprintf(D_FHTRACE, "Disposing of fh with bad path.\n"); + fh_delete(h); +- h = fh_find(key, FHFIND_FCREATE); ++ h = fh_find(key, FHFIND_FCREATE, dirh->last_mount ? dirh->last_mount->mount_dev : 0); + #ifdef FHTRACE + if (!h) return NFSERR_STALE; + #endif +@@ -1511,12 +1565,14 @@ + return (NFS_OK); + } + ++#if 0 + psi_t + fh_psi(nfs_fh *fh) + { + svc_fh *h = (svc_fh *) fh; + return (h->psi); + } ++#endif + + void + fh_remove(char *path) +@@ -1524,12 +1580,13 @@ + psi_t psi; + nfsstat status; + fhcache *fhc; ++ struct stat st; + +- psi = path_psi(path, &status, NULL, 0); ++ psi = path_psi(path, &status, &st, 0, NULL); + if (psi == 0) + return; + ex_state = active; +- fhc = fh_lookup(psi); ++ fhc = fh_lookup(st.st_ino,st.st_dev); + if (fhc != NULL) + fh_delete(fhc); + +@@ -1634,6 +1691,11 @@ + fh_init(void) + { + static int initialized = 0; ++ ++ if (sizeof(svc_fh) > 32) { ++ fprintf(stderr, "filehandle wrong size %d\n", sizeof(svc_fh)); ++ exit(10); ++ } + + if (initialized) + return; +--- nfs-server/fh.h ++++ nfs-server/fh.h 2002/11/08 13:59:16 +@@ -20,6 +20,7 @@ + #define FHC_XONLY_PATH 001 /* NOT USED ANYMORE */ + #define FHC_ATTRVALID 002 + #define FHC_NFSMOUNTED 004 ++#define FHC_CROSS 010 + + /* Modes for fh_find */ + #define FHFIND_FEXISTS 0 /* file must exist */ +@@ -65,11 +66,12 @@ + * + * hash_path[hash_path[0]+1] ... hash_path[HP_LEN-1] == 0 + */ +-#define HP_LEN (NFS_FHSIZE - sizeof(psi_t)) ++#define HP_LEN (NFS_FHSIZE-sizeof(u_int32_t)-sizeof(u_int16_t)) + typedef struct { +- psi_t psi; ++ u_int32_t ino; ++ u_int16_t dev; + __u8 hash_path[HP_LEN]; +-} svc_fh; ++} svc_fh __attribute__((packed)); + + typedef enum { inactive, active } mutex; + +@@ -100,6 +102,7 @@ + + /* These are fixed during the lifetime of this object */ + svc_fh h; ++ psi_t psi; + dev_t dev; + ino_t ino; + mode_t type; /* st_mode & S_IFMT */ +@@ -122,10 +125,11 @@ + /* Global function prototypes. */ + extern nfsstat nfs_errno(void); + extern psi_t pseudo_inode(ino_t inode, dev_t dev); ++extern psi_t visible_inode(ino_t inode, dev_t dev, nfs_mount *); + extern void fh_init(void); + extern char *fh_pr(nfs_fh *fh); + extern int fh_create(nfs_fh *fh, char *path); +-extern fhcache *fh_find(svc_fh *h, int create); ++extern fhcache *fh_find(svc_fh *h, int create, dev_t basedev); + extern char *fh_path(nfs_fh *fh, nfsstat *status); + extern int path_open(char *path, int omode, int perm); + extern int fh_fd(fhcache *fhc, nfsstat *status, int omode); +@@ -139,6 +143,7 @@ + extern void fh_flush(int force); + extern RETSIGTYPE flush_cache(int sig); + extern int nfsmounted(const char *path, struct stat *sbp); ++extern fhcache *fh_newfh(svc_fh *fh, int mode, dev_t basedev); + + #ifdef ENABLE_DEVTAB + extern unsigned int devtab_index(dev_t); +--- nfs-server/getattr.c ++++ nfs-server/getattr.c 2002/11/08 13:59:16 +@@ -43,7 +43,7 @@ + { + fhcache *fhc; + +- if ((fhc = fh_find((svc_fh*)fh, FHFIND_FEXISTS)) == NULL) { ++ if ((fhc = fh_find((svc_fh*)fh, FHFIND_FEXISTS, 0)) == NULL) { + Dprintf(D_CALL, "getattr: failed! No such file.\n"); + return (NFSERR_STALE); + } +@@ -103,18 +103,8 @@ + #else + attr->blocks = st_blocks(s); + #endif +-#if 0 +- if (nfsmount->o.cross_mounts) { +- attr->fsid = 1; +- attr->fileid = fh_psi((nfs_fh *)&(fhc->h)); +- } else { +- attr->fsid = s->st_dev; +- attr->fileid = covered_ino(fhc->path); +- } +-#else +- attr->fsid = 1; +- attr->fileid = fh_psi((nfs_fh *)&(fhc->h)); +-#endif ++ attr->fsid = 1; // XXX ++ attr->fileid = visible_inode(fhc->h.ino, fhc->h.dev, nfsmount); + + /* This may be needed by some Suns... testing */ + #define MINTIME (24 * 2600) +--- nfs-server/mountd.c ++++ nfs-server/mountd.c 2002/11/08 13:59:16 +@@ -36,6 +36,8 @@ + #include "signals.h" + #include + ++int cross_mounts = 1; ++int hashed_inodes; /* dummy */ + + static void usage(FILE *, int); + static void terminate(void); +@@ -58,9 +60,9 @@ + { "no-spoof-trace", 0, 0, 't' }, + { "version", 0, 0, 'v' }, + { "fail-safe", optional_argument, 0, 'z' }, ++ { "no-cross-mounts", 0, 0, 'x' }, + { "no-tcp", 0, 0, OPT_NOTCP }, + { "loopback-only", 0, 0, OPT_LOOPBACK }, +- + { NULL, 0, 0, 0 } + }; + static const char * shortopts = "Fd:f:hnpP:rtvz::"; +@@ -80,6 +82,7 @@ + int need_reinit = 0; + int need_flush = 0; + extern char version[]; ++nfs_client *nfsclient; /* dummy */ + + /* + * NULL +@@ -319,6 +322,9 @@ + opterr = 0; + while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != EOF) + switch (c) { ++ case 'x': ++ cross_mounts = 0; ++ break; + case 'F': + foreground = 1; + break; +@@ -444,7 +450,7 @@ + program_name); + fprintf(fp, " [--debug kind] [--help] [--allow-non-root]\n"); + fprintf(fp, " [--promiscuous] [--version] [--port portnum]\n"); +- fprintf(fp, " [--exports-file=file]\n"); ++ fprintf(fp, " [--exports-file=file] [--no-cross-mounts]\n"); + exit(n); + } + +--- nfs-server/nfsd.c ++++ nfs-server/nfsd.c 2002/11/08 14:20:57 +@@ -72,7 +72,7 @@ + { "no-tcp", 0, 0, OPT_NOTCP }, + { "udp-only", 0, 0, OPT_NOTCP }, + { "loopback-only", 0, 0, OPT_LOOPBACK }, +- ++ { "hashed-inodes", 0, 0, 'I' }, + { NULL, 0, 0, 0 } + }; + static const char * shortopts = "a:d:Ff:hlnP:prR:tvz::"; +@@ -91,6 +91,7 @@ + int need_flush = 0; /* flush fh cache */ + int read_only = 0; /* Global ro forced */ + int cross_mounts = 1; /* Transparently cross mnts */ ++int hashed_inodes = 0; + int log_transfers = 0; /* Log transfers */ + static svc_fh public_fh; /* Public NFSv2 FH */ + +@@ -122,12 +123,17 @@ + { + static int total = 0, cached = 0; + fhcache *fhc; ++ int newfh = 0; + +- /* Try to map FH. If not cached, reconstruct path with root priv */ +- fhc = fh_find((svc_fh *)fh, FHFIND_FEXISTS|FHFIND_CHECK); +- if (fhc == NULL) { +- *statp = NFSERR_STALE; +- return NULL; ++ /* Try to map FH. */ ++ fhc = fh_find((svc_fh *)fh, FHFIND_FCACHED|FHFIND_CHECK, 0); ++ if (!fhc) { ++ fhc = fh_newfh((svc_fh*)fh, FHFIND_FEXISTS|FHFIND_CHECK, 0); ++ if (!fhc) { ++ *statp = NFSERR_STALE; ++ return NULL; ++ } ++ newfh = 1; + } + + /* Try to retrieve last client who accessed this fh */ +@@ -163,6 +169,16 @@ + 100 * (double) cached / total); + */ + ++ /* Trust the crossmount check of the parent directory for creates */ ++ if (newfh && ++ (fhc->flags & FHC_ATTRVALID) && ++ auth_checkdev(nfsmount, fhc->attrs.st_dev) == 0) { ++ Dprintf(L_ERROR, "auth_fh: fh crossed mount %s: %x<->%x\n", ++ fhc->path ? fhc->path : "???", nfsmount->mount_dev, fhc->attrs.st_dev); ++ *statp = NFSERR_STALE; /* or ACCES? */ ++ return NULL; ++ } ++ + if (nfsmount->o.noaccess && + ((flags & CHK_NOACCESS) || strcmp(nfsmount->path, fhc->path))) { + struct in_addr addr = svc_getcaller(rqstp->rq_xprt)->sin_addr; +@@ -195,6 +211,7 @@ + fhcache *fhc; + nfsstat status; + char *path = buf, *sp; ++ struct stat st; + + /* Authenticate directory file handle */ + if ((fhc = auth_fh(rqstp, &dopa->dir, &status, flags)) == NULL) +@@ -219,6 +236,9 @@ + if ((nfsmount = auth_path(nfsclient, rqstp, path)) == NULL) + return NFSERR_ACCES; + ++ if (efs_lstat(path, &st) >= 0 && !auth_checkdev(nfsmount, st.st_dev)) ++ return NFSERR_ACCES; ++ + /* XXX: really need to call it again here? + * Already invoked in auth_fh */ + if (!auth_user(nfsmount, rqstp)) +@@ -318,7 +338,8 @@ + int ispublic = 0; + + /* First check whether this is the public FH */ +- if (((svc_fh *) fh)->psi == 0 && !memcmp(fh, &public_fh, FHSIZE)) { ++ if (((svc_fh *) fh)->dev == 0 && ((svc_fh*)fh)->ino == 0 && ++ !memcmp(fh, &public_fh, FHSIZE)) { + if (public_root_path == NULL) + return NFSERR_ACCES; + memcpy(&argp->dir, &public_root, NFS_FHSIZE); +@@ -333,6 +354,7 @@ + if (!(fhc = auth_fh(rqstp, fh, &status, CHK_READ))) + return status; + ++ /* FIXME: does too many stats */ + status = fh_compose(argp, &dp->file, &sbuf, -1, -1, ispublic); + if (status != NFS_OK) + return status; +@@ -896,6 +918,9 @@ + errno = 0; + if (efs_lstat(h->path, &sbuf) < 0 || !(S_ISDIR(sbuf.st_mode))) + return (NFSERR_NOTDIR); ++ if (!auth_checkdev(h->last_mount, sbuf.st_dev)) ++ dotsonly = 1; ++ + if ((dirp = efs_opendir(h->path)) == NULL) + return ((errno ? nfs_errno() : NFSERR_NAMETOOLONG)); + +@@ -923,7 +948,7 @@ + } + + e = *ep = (entry *) xmalloc(sizeof(entry)); +- e->fileid = pseudo_inode(dp->d_ino, sbuf.st_dev); ++ e->fileid = visible_inode(dp->d_ino, sbuf.st_dev, h->last_mount); + e->name = xmalloc(NLENGTH(dp) + 1); + strcpy(e->name, dp->d_name); + dloc = htonl(efs_telldir(dirp)); +@@ -1033,6 +1058,9 @@ + case 'x': + cross_mounts = 0; + break; ++ case 'I': ++ hashed_inodes = 1; ++ break; + case 'z': + if (optarg) + failsafe_level = atoi(optarg); +@@ -1189,7 +1217,7 @@ + " [--debug kind] [--exports-file=file] [--port port]\n" + " [--allow-non-root] [--promiscuous] [--version] [--foreground]\n" + " [--re-export] [--log-transfers] [--public-root path]\n" +-" [--no-spoof-trace] [--help]\n" ++" [--no-spoof-trace] [--no-cross-mounts] [--hashed-inodes] [--help]\n" + , program_name); + exit(n); + } +--- nfs-server/nfsd.h ++++ nfs-server/nfsd.h 2002/11/08 13:59:16 +@@ -51,6 +51,7 @@ + extern int need_reinit; + extern int need_flush; + extern time_t nfs_dispatch_time; ++extern int cross_mounts, hashed_inodes; + + /* Include the other module definitions. */ + #include "auth.h" +--- nfs-server/setattr.c ++++ nfs-server/setattr.c 2002/11/08 13:59:16 +@@ -17,6 +17,7 @@ + + #define IGNORE_TIME ((unsigned int) -1) + ++#if 0 + /* + * Set file attributes based on file handle + */ +@@ -33,6 +34,7 @@ + } + return setattr(path, attr, s, rqstp, flags); + } ++#endif + + /* + * Set file attributes given the path. The flags argument +--- nfs-server/teahash3.c ++++ nfs-server/teahash3.c 2002/11/08 13:59:16 +@@ -0,0 +1,168 @@ ++/* Taken from the reiserfs source code and hacked slightly by AK. ++ * This is GPLed. */ ++/* ++ * Keyed 32-bit hash function using TEA in a Davis-Meyer function ++ * H0 = Key ++ * Hi = E Mi(Hi-1) + Hi-1 ++ * ++ * (see Applied Cryptography, 2nd edition, p448). ++ * ++ * Jeremy Fitzhardinge 1998 ++ * ++ * Jeremy has agreed to the contents of reiserfs/README. -Hans ++ */ ++ ++#include ++ ++#if 0 ++/* OK for Intel */ ++typedef unsigned long u32; ++typedef const unsigned char u8; ++#else ++#include ++typedef uint32_t u32; ++typedef uint8_t u8; ++#endif ++ ++ ++#define DELTA 0x9E3779B9 ++#define FULLROUNDS 10 /* 32 is overkill, 16 is strong crypto */ ++#define PARTROUNDS 6 /* 6 gets complete mixing */ ++ ++/* a, b, c, d - data; h0, h1 - accumulated hash */ ++#define TEACORE(rounds) \ ++ do { \ ++ u32 sum = 0; \ ++ int n = rounds; \ ++ u32 b0, b1; \ ++ \ ++ b0 = h0; \ ++ b1 = h1; \ ++ \ ++ do \ ++ { \ ++ sum += DELTA; \ ++ b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); \ ++ b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); \ ++ } while(--n); \ ++ \ ++ h0 += b0; \ ++ h1 += b1; \ ++ } while(0) ++ ++u32 teahash3(/*u32 k[2], *//*u8*/const char *msg, int len) ++{ ++ u32 k[] = { 0x9464a485, 0x542e1a94, 0x3e846bff, 0xb75bcfc3}; ++ ++ u32 h0 = k[0], h1 = k[1]; ++ u32 a, b, c, d; ++ u32 pad; ++ int i; ++ ++ assert(len >= 0 && len < 256); ++ ++ pad = (u32)len | ((u32)len << 8); ++ pad |= pad << 16; ++ ++ while(len >= 16) ++ { ++ a = (u32)msg[ 0] | ++ (u32)msg[ 1] << 8 | ++ (u32)msg[ 2] << 16| ++ (u32)msg[ 3] << 24; ++ b = (u32)msg[ 4] | ++ (u32)msg[ 5] << 8 | ++ (u32)msg[ 6] << 16| ++ (u32)msg[ 7] << 24; ++ c = (u32)msg[ 8] | ++ (u32)msg[ 9] << 8 | ++ (u32)msg[10] << 16| ++ (u32)msg[11] << 24; ++ d = (u32)msg[12] | ++ (u32)msg[13] << 8 | ++ (u32)msg[14] << 16| ++ (u32)msg[15] << 24; ++ ++ TEACORE(PARTROUNDS); ++ ++ len -= 16; ++ msg += 16; ++ } ++ ++ if (len >= 12) ++ { ++ assert(len < 16); ++ ++ a = (u32)msg[ 0] | ++ (u32)msg[ 1] << 8 | ++ (u32)msg[ 2] << 16| ++ (u32)msg[ 3] << 24; ++ b = (u32)msg[ 4] | ++ (u32)msg[ 5] << 8 | ++ (u32)msg[ 6] << 16| ++ (u32)msg[ 7] << 24; ++ c = (u32)msg[ 8] | ++ (u32)msg[ 9] << 8 | ++ (u32)msg[10] << 16| ++ (u32)msg[11] << 24; ++ ++ d = pad; ++ for(i = 12; i < len; i++) ++ { ++ d <<= 8; ++ d |= msg[i]; ++ } ++ } ++ else if (len >= 8) ++ { ++ assert(len < 12); ++ ++ a = (u32)msg[ 0] | ++ (u32)msg[ 1] << 8 | ++ (u32)msg[ 2] << 16| ++ (u32)msg[ 3] << 24; ++ b = (u32)msg[ 4] | ++ (u32)msg[ 5] << 8 | ++ (u32)msg[ 6] << 16| ++ (u32)msg[ 7] << 24; ++ ++ c = d = pad; ++ for(i = 8; i < len; i++) ++ { ++ c <<= 8; ++ c |= msg[i]; ++ } ++ } ++ else if (len >= 4) ++ { ++ assert(len < 8); ++ ++ a = (u32)msg[ 0] | ++ (u32)msg[ 1] << 8 | ++ (u32)msg[ 2] << 16| ++ (u32)msg[ 3] << 24; ++ ++ b = c = d = pad; ++ for(i = 4; i < len; i++) ++ { ++ b <<= 8; ++ b |= msg[i]; ++ } ++ } ++ else ++ { ++ assert(len < 4); ++ ++ a = b = c = d = pad; ++ for(i = 0; i < len; i++) ++ { ++ a <<= 8; ++ a |= msg[i]; ++ } ++ } ++ ++ TEACORE(FULLROUNDS); ++ ++/* return 0;*/ ++ return h0^h1; ++} +--- nfs-server/ugid_map.c ++++ nfs-server/ugid_map.c 2002/11/08 13:59:16 +@@ -276,8 +276,10 @@ + if ((gid == 0 && mountp->o.root_squash) || mountp->o.all_squash) + retgid = mountp->o.nobody_gid; + ++#if 0 + Dprintf(D_UGID, "lgid(%s, %d) = %d\n", + inet_ntoa(mountp->client->clnt_addr), gid, retgid); ++#endif + return retgid; + } + -- cgit v1.2.3-54-g00ecf