summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/006-reiserfs.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/006-reiserfs.patch')
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/006-reiserfs.patch1272
1 files changed, 1272 insertions, 0 deletions
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/006-reiserfs.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/006-reiserfs.patch
new file mode 100644
index 0000000000..abdc67476e
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-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 <assert.h>
+@@ -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 : "<unnamed>", fhc->fd);
++ "fh_delete: deleting handle %x [%x,%x] ('%s', fd=%d)\n",
++ fhc, fhc->h.dev, fhc->h.ino, fhc->path ? fhc->path : "<unnamed>",
++ 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 : "<unnamed>", 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 : "<unnamed>",
+ 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 : "<unnamed>", 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 <rpc/pmap_clnt.h>
+
++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 <jeremy@zip.com.au> 1998
++ *
++ * Jeremy has agreed to the contents of reiserfs/README. -Hans
++ */
++
++#include <assert.h>
++
++#if 0
++/* OK for Intel */
++typedef unsigned long u32;
++typedef const unsigned char u8;
++#else
++#include <inttypes.h>
++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;
+ }
+