[PATCH] knfsd: new linux kenel nfs patch

G. Allen Morris III (gam3@dharma.sehda.com)
Mon, 28 Sep 1998 23:24:09 -0700


This is a multipart MIME message.

--==_Exmh_-14249306240
Content-Type: text/plain

Here is a newer patch for kernel.

This has three changes:

1) a bug was fixed in exp_unexport() that could keep unexports
from working.

2) Security was added fh_verify() that should make it improbable
to use an export to read a file that is not under that export.
This change checks to make sure that the export is on the same
device as the file being accessed and that the export point
is a parent of the file being accessed.

3) An OOPS was caused if the dcookie in the nfs file handle was
NULL.

This patch also contains all of the changes that where in my
knfsd-2.1.121-4 patch.

If you would like for knfsd to access directories that are coverd,
the way that SUN does. Then CONFIG_NFSD_SUN needs to be defined in
fs/nfsd/vfs.c. This should be added to .config at some point.

Allen

---------------------------------
G. Allen Morris III

--==_Exmh_-14249306240
Content-Type: text/plain; name="nfsd-2.1.122-3"
Content-Description: nfsd-2.1.122-3.patch
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="nfsd-2.1.122-3"

Index: linux/fs/nfsd/export.c
diff -c linux/fs/nfsd/export.c:1.1 linux/fs/nfsd/export.c:1.5
*** linux/fs/nfsd/export.c:1.1 Thu Sep 10 09:07:46 1998
--- linux/fs/nfsd/export.c Sun Sep 27 11:19:00 1998
***************
*** 33,39 ****
typedef struct svc_export svc_export;
=

static svc_export * exp_find(svc_client *clp, kdev_t dev);
! static svc_export * exp_parent(svc_client *clp, kdev_t dev);
static void exp_unexport_all(svc_client *clp);
static void exp_do_unexport(svc_export *unexp);
static svc_client * exp_getclientbyname(char *name);
--- 33,40 ----
typedef struct svc_export svc_export;
=

static svc_export * exp_find(svc_client *clp, kdev_t dev);
! static svc_export * exp_parent(svc_client *clp, kdev_t dev, struct dent=
ry *dentry);
! static svc_export * exp_child(svc_client *clp, kdev_t dev, struct dentr=
y *dentry);
static void exp_unexport_all(svc_client *clp);
static void exp_do_unexport(svc_export *unexp);
static svc_client * exp_getclientbyname(char *name);
***************
*** 90,97 ****
=

if (!clp)
return NULL;
! exp =3D exp_find(clp, dev);
! return (exp && exp->ex_ino =3D=3D ino)? exp : NULL;
}
=

/*
--- 91,106 ----
=

if (!clp)
return NULL;
! =

! exp =3D clp->cl_export[EXPORT_HASH(dev)];
! if (exp)
! do {
! if (exp->ex_ino =3D=3D ino && exp->ex_dev =3D=3D dev)
! goto out;
! } while (NULL !=3D (exp =3D exp->ex_next));
! exp =3D NULL;
! out:
! return exp;
}
=

/*
***************
*** 129,147 ****
* Find the parent export entry for a given fs. This function is used
* only by the export syscall to keep the export tree consistent.
*/
static svc_export *
! exp_parent(svc_client *clp, kdev_t dev)
{
! svc_export *exp;
kdev_t xdev =3D dev;
=

do {
! exp =3D exp_find(clp, xdev);
! if (exp)
! return exp;
! } while (nfsd_parentdev(&xdev));
=

! return NULL;
}
=

/*
--- 138,215 ----
* Find the parent export entry for a given fs. This function is used
* only by the export syscall to keep the export tree consistent.
*/
+ /* =

+ * We can use this to find exports if we have it look at the first
+ * dentry. This makes it less efficient. <gam3@acm.org>
+ */
static svc_export *
! exp_parent(svc_client *clp, kdev_t dev, struct dentry *dentry)
{
! svc_export *exp;
kdev_t xdev =3D dev;
+ struct dentry *xdentry =3D dentry;
+ struct dentry *ndentry =3D NULL;
+ =

+ if (clp =3D=3D NULL || dentry =3D=3D NULL)
+ return NULL;
=

do {
! xdev =3D dev;
! do {
! exp =3D clp->cl_export[EXPORT_HASH(xdev)];
! if (exp)
! do {
! ndentry =3D exp->ex_dentry;
! if (ndentry =3D=3D xdentry) {
! if (dev =3D=3D xdev)
! dprintk("nfsd: exp_parent submount over mount.\n");
! else
! dprintk("nfsd: exp_parent found.\n");
! goto out;
! }
! } while (NULL !=3D (exp =3D exp->ex_next));
! } while (nfsd_parentdev(&xdev));
! /* It should be possible to move this to the top of this loop */
! if (xdentry =3D=3D xdentry->d_parent) {
! break;
! }
! } while ((xdentry =3D xdentry->d_parent));
! exp =3D NULL;
! out:
! return exp;
! }
=

! /*
! * Find the child export entry for a given fs. This function is used
! * only by the export syscall to keep the export tree consistent.
! */
! static svc_export *
! exp_child(svc_client *clp, kdev_t dev, struct dentry *dentry)
! {
! svc_export *exp;
! struct dentry *xdentry =3D dentry;
! struct dentry *ndentry =3D NULL;
! =

! if (clp =3D=3D NULL || dentry =3D=3D NULL)
! return NULL;
! =

! exp =3D clp->cl_export[EXPORT_HASH(dev)];
! if (exp)
! do {
! ndentry =3D exp->ex_dentry;
! if (ndentry)
! while ((ndentry =3D ndentry->d_parent)) {
! if (ndentry =3D=3D xdentry) {
! dprintk("nfsd: exp_child mount under submount.\n");
! goto out;
! }
! if (ndentry =3D=3D ndentry->d_parent)
! break;
! }
! } while (NULL !=3D (exp =3D exp->ex_next));
! exp =3D NULL;
! out:
! return exp;
}
=

/*
***************
*** 160,168 ****
ino_t ino;
=

/* Consistency check */
if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
!exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
! return -EINVAL;
=

dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
nxp->ex_client, nxp->ex_path,
--- 228,237 ----
ino_t ino;
=

/* Consistency check */
+ err =3D -EINVAL;
if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
!exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
! goto out;
=

dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
nxp->ex_client, nxp->ex_path,
***************
*** 183,197 ****
* If there's already an export for this file, assume this
* is just a flag update.
*/
! if ((exp =3D exp_find(clp, dev)) !=3D NULL) {
! /* Ensure there's only one export per FS. */
! err =3D -EPERM;
! if (exp->ex_ino =3D=3D ino) {
! exp->ex_flags =3D nxp->ex_flags;
! exp->ex_anon_uid =3D nxp->ex_anon_uid;
! exp->ex_anon_gid =3D nxp->ex_anon_gid;
! err =3D 0;
! }
goto out_unlock;
}
=

--- 252,262 ----
* If there's already an export for this file, assume this
* is just a flag update.
*/
! if ((exp =3D exp_get(clp, dev, ino)) !=3D NULL) {
! exp->ex_flags =3D nxp->ex_flags;
! exp->ex_anon_uid =3D nxp->ex_anon_uid;
! exp->ex_anon_gid =3D nxp->ex_anon_gid;
! err =3D 0;
goto out_unlock;
}
=

***************
*** 203,234 ****
=

err =3D -ENOENT;
inode =3D dentry->d_inode;
! if(!inode)
goto finish;
err =3D -EINVAL;
! if(inode->i_dev !=3D dev || inode->i_ino !=3D nxp->ex_ino) {
! =

printk(KERN_DEBUG "exp_export: i_dev =3D %x, dev =3D %x\n",
inode->i_dev, dev); =

/* I'm just being paranoid... */
goto finish;
}
=

! /* We currently export only dirs. */
err =3D -ENOTDIR;
! if (!S_ISDIR(inode->i_mode))
goto finish;
=

- /* If this is a sub-export, must be root of FS */
err =3D -EINVAL;
! if ((parent =3D exp_parent(clp, dev)) !=3D NULL) {
! struct super_block *sb =3D inode->i_sb;
! =

! if (inode !=3D sb->s_root->d_inode) {
! #ifdef NFSD_PARANOIA
! printk("exp_export: sub-export %s not root of device %s\n",
! nxp->ex_path, kdevname(sb->s_dev));
! #endif
goto finish;
}
}
--- 268,299 ----
=

err =3D -ENOENT;
inode =3D dentry->d_inode;
! if (!inode)
goto finish;
err =3D -EINVAL;
! if (inode->i_dev !=3D dev || inode->i_ino !=3D nxp->ex_ino) {
printk(KERN_DEBUG "exp_export: i_dev =3D %x, dev =3D %x\n",
inode->i_dev, dev); =

/* I'm just being paranoid... */
goto finish;
}
=

! /* We currently export only dirs and regular files.
! * This is what umountd does.
! */
err =3D -ENOTDIR;
! if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode))
goto finish;
=

err =3D -EINVAL;
! if ((parent =3D exp_child(clp, dev, dentry)) !=3D NULL) {
! dprintk("exp_export: export not valid (Rule 3).\n");
! goto finish;
! }
! /* Is this is a sub-export, must be a proper subset of FS */
! if ((parent =3D exp_parent(clp, dev, dentry)) !=3D NULL) {
! if ((dev =3D parent->ex_dev)) {
! dprintk("exp_export: sub-export not valid (Rule 2).\n");
goto finish;
}
}
***************
*** 366,379 ****
expp =3D clp->cl_export + EXPORT_HASH(nxp->ex_dev);
while ((exp =3D *expp) !=3D NULL) {
if (exp->ex_dev =3D=3D nxp->ex_dev) {
! if (exp->ex_ino !=3D nxp->ex_ino) {
! printk("exp_unexport: ino mismatch, %ld not %ld\n", exp->ex_ino, nxp->e=
x_ino);
break;
! }
! *expp =3D exp->ex_next;
! exp_do_unexport(exp);
! err =3D 0;
! break;
}
expp =3D &(exp->ex_next);
}
--- 431,444 ----
expp =3D clp->cl_export + EXPORT_HASH(nxp->ex_dev);
while ((exp =3D *expp) !=3D NULL) {
if (exp->ex_dev =3D=3D nxp->ex_dev) {
! if (exp->ex_ino =3D=3D nxp->ex_ino) {
! *expp =3D exp->ex_next;
! exp_do_unexport(exp);
! err =3D 0;
break;
! } else {
! printk("exp_unexport: ino mismatch, %ld not %ld\n", exp->ex_ino, nxp->e=
x_ino);
! }
}
expp =3D &(exp->ex_next);
}
***************
*** 390,409 ****
* since its harder to fool a kernel module than a user space program.
*/
int
! exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino, struct knfs_f=
h *f)
{
struct svc_export *exp;
struct dentry *dentry;
struct inode *inode;
struct svc_fh fh;
=

! dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n", clp->cl_ident, dev, ino);
=

! exp =3D exp_get(clp, dev, ino);
if (!exp)
! return -EPERM;
=

- dentry =3D exp->ex_dentry;
inode =3D dentry->d_inode;
if(!inode) {
printk("exp_rootfh: Aieee, NULL d_inode\n");
--- 455,485 ----
* since its harder to fool a kernel module than a user space program.
*/
int
! exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino, char *path, s=
truct knfs_fh *f)
{
struct svc_export *exp;
struct dentry *dentry;
struct inode *inode;
struct svc_fh fh;
+ int err;
=

! if (path) {
! dentry =3D lookup_dentry(path, NULL, 0);
=

! dev =3D dentry->d_inode->i_dev;
! ino =3D dentry->d_inode->i_ino;
! =

! dprintk("nfsd: exp_rootfh(%s [%p] %s:%x/%ld)\n", path, dentry, clp->c=
l_ident, dev, ino);
! exp =3D exp_parent(clp, dev, dentry);
! } else {
! dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n", clp->cl_ident, dev, ino);
! exp =3D exp_get(clp, dev, ino);
! dentry =3D dget(exp->ex_dentry);
! }
! err =3D -EPERM;
if (!exp)
! goto out;
=

inode =3D dentry->d_inode;
if(!inode) {
printk("exp_rootfh: Aieee, NULL d_inode\n");
***************
*** 419,429 ****
* fh must be initialized before calling fh_compose
*/
fh_init(&fh);
! fh_compose(&fh, exp, dget(dentry));
memcpy(f, &fh.fh_handle, sizeof(struct knfs_fh));
fh_put(&fh);
- =

return 0;
}
=

/*
--- 495,508 ----
* fh must be initialized before calling fh_compose
*/
fh_init(&fh);
! fh_compose(&fh, exp, dentry);
memcpy(f, &fh.fh_handle, sizeof(struct knfs_fh));
fh_put(&fh);
return 0;
+ =

+ out:
+ dput(dentry);
+ return err;
}
=

/*
Index: linux/fs/nfsd/nfsctl.c
diff -c linux/fs/nfsd/nfsctl.c:1.1 linux/fs/nfsd/nfsctl.c:1.2
*** linux/fs/nfsd/nfsctl.c:1.1 Thu Sep 10 09:07:46 1998
--- linux/fs/nfsd/nfsctl.c Fri Sep 11 09:40:52 1998
***************
*** 5,10 ****
--- 5,11 ----
*
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
*/
+ #define NFS_GETFH_NEW
=

#include <linux/config.h>
#include <linux/module.h>
***************
*** 47,52 ****
--- 48,54 ----
static int nfsctl_export(struct nfsctl_export *data);
static int nfsctl_unexport(struct nfsctl_export *data);
static int nfsctl_getfh(struct nfsctl_fhparm *, struct knfs_fh *);
+ static int nfsctl_getfd(struct nfsctl_fdparm *, struct knfs_fh *);
/* static int nfsctl_ugidupdate(struct nfsctl_ugidmap *data); */
=

static int initialized =3D 0;
***************
*** 108,113 ****
--- 110,138 ----
#endif
=

static inline int
+ nfsctl_getfd(struct nfsctl_fdparm *data, struct knfs_fh *res)
+ {
+ struct sockaddr_in *sin;
+ struct svc_client *clp;
+ int err =3D 0;
+ =

+ if (data->gd_addr.sa_family !=3D AF_INET)
+ return -EPROTONOSUPPORT;
+ if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
+ return -EINVAL;
+ sin =3D (struct sockaddr_in *)&data->gd_addr;
+ =

+ exp_readlock();
+ if (!(clp =3D exp_getclient(sin)))
+ err =3D -EPERM;
+ else
+ err =3D exp_rootfh(clp, 0, 0, data->gd_path, res);
+ exp_unlock();
+ =

+ return err;
+ }
+ =

+ static inline int
nfsctl_getfh(struct nfsctl_fhparm *data, struct knfs_fh *res)
{
struct sockaddr_in *sin;
***************
*** 124,130 ****
if (!(clp =3D exp_getclient(sin)))
err =3D -EPERM;
else
! err =3D exp_rootfh(clp, to_kdev_t(data->gf_dev), data->gf_ino, res);
exp_unlock();
=

return err;
--- 149,155 ----
if (!(clp =3D exp_getclient(sin)))
err =3D -EPERM;
else
! err =3D exp_rootfh(clp, to_kdev_t(data->gf_dev), data->gf_ino, NULL, =
res);
exp_unlock();
=

return err;
***************
*** 193,198 ****
--- 218,226 ----
#endif
case NFSCTL_GETFH:
err =3D nfsctl_getfh(&arg->ca_getfh, &res->cr_getfh);
+ break;
+ case NFSCTL_GETFD:
+ err =3D nfsctl_getfd(&arg->ca_getfd, &res->cr_getfh);
break;
default:
err =3D -EINVAL;
Index: linux/fs/nfsd/nfsfh.c
diff -c linux/fs/nfsd/nfsfh.c:1.1 linux/fs/nfsd/nfsfh.c:1.3
*** linux/fs/nfsd/nfsfh.c:1.1 Thu Sep 10 09:07:46 1998
--- linux/fs/nfsd/nfsfh.c Mon Sep 28 22:58:32 1998
***************
*** 493,498 ****
--- 493,501 ----
struct fh_entry *fhe;
int i, found =3D (empty =3D=3D NULL) ? 1 : 0;
=

+ if (!dentry)
+ goto out;
+ =

fhe =3D (cache =3D=3D NFSD_FILE_CACHE) ? &filetable[0] : &dirstable[0]=
;
for (i =3D 0; i < NFSD_MAXFH; i++, fhe++) {
if (fhe->dentry =3D=3D dentry) {
***************
*** 504,509 ****
--- 507,513 ----
*empty =3D fhe;
}
}
+ out:
return NULL;
}
=

***************
*** 756,763 ****
=

fhe =3D find_fhe(fh->fh_dcookie, NFSD_FILE_CACHE, NULL);
if (fhe) {
! struct dentry *parent, *dentry =3D fhe->dentry;
! struct inode *inode =3D dentry->d_inode;
if (!inode) {
#ifdef NFSD_PARANOIA
printk("find_dentry_in_fhcache: %s/%s has no inode!\n",
--- 760,771 ----
=

fhe =3D find_fhe(fh->fh_dcookie, NFSD_FILE_CACHE, NULL);
if (fhe) {
! struct dentry *parent, *dentry;
! struct inode *inode;
! =

! dentry =3D fhe->dentry;
! inode =3D dentry->d_inode;
! =

if (!inode) {
#ifdef NFSD_PARANOIA
printk("find_dentry_in_fhcache: %s/%s has no inode!\n",
***************
*** 1019,1025 ****
dprintk("nfsd: fh_verify(exp %x/%u cookie %p)\n",
fh->fh_xdev, fh->fh_xino, fh->fh_dcookie);
=

! if(fhp->fh_dverified)
goto check_type;
/*
* Look up the export entry.
--- 1027,1033 ----
dprintk("nfsd: fh_verify(exp %x/%u cookie %p)\n",
fh->fh_xdev, fh->fh_xino, fh->fh_dcookie);
=

! if (fhp->fh_dverified)
goto check_type;
/*
* Look up the export entry.
***************
*** 1051,1056 ****
--- 1059,1097 ----
dentry =3D find_fh_dentry(fh);
if (!dentry)
goto out;
+ =

+ /*
+ * Security: Check that the export is valid for that dentry
+ */
+ {
+ struct dentry *tdentry =3D dentry;
+ int count =3D 0;
+ =

+ if (fh->fh_dev !=3D fh->fh_xdev) {
+ printk("fh_verify: Security: export on other device (%d, %d).\n",
+ fh->fh_dev, fh->fh_xdev);
+ goto out;
+ }
+ =

+ do {
+ count++;
+ if (exp->ex_dentry =3D=3D tdentry) {
+ error =3D 0;
+ dprintk("fh_verify: %s/%s good export (%d).\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name, count);
+ break;
+ }
+ if (tdentry->d_parent =3D=3D tdentry) {
+ break;
+ }
+ } while ((tdentry =3D tdentry->d_parent));
+ =

+ if (error) {
+ printk("fh_verify: Security: %s/%s bad export (%d).\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name, count);
+ goto out;
+ }
+ }
/*
* Note: it's possible the returned dentry won't be the one in the
* file handle. We can correct the file handle for our use, bu=
t
Index: linux/fs/nfsd/vfs.c
diff -c linux/fs/nfsd/vfs.c:1.1 linux/fs/nfsd/vfs.c:1.5
*** linux/fs/nfsd/vfs.c:1.1 Thu Sep 10 09:07:46 1998
--- linux/fs/nfsd/vfs.c Sun Sep 27 11:19:00 1998
***************
*** 39,44 ****
--- 39,45 ----
#endif
=

#define NFSDDBG_FACILITY NFSDDBG_FILEOP
+ #define NFSD_PARANOIA
=

/* Open mode for nfsd_open */
#define OPEN_READ 0
***************
*** 168,180 ****
if (IS_ERR(dchild))
goto out_nfserr;
/*
! * Make sure we haven't crossed a mount point ...
*/
if (dchild->d_sb !=3D dparent->d_sb) {
! #ifdef NFSD_PARANOIA
! printk("nfsd_lookup: %s/%s crossed mount point!\n", dparent->d_name.nam=
e, name);
! #endif
! goto out_dput;
}
=

/*
--- 169,187 ----
if (IS_ERR(dchild))
goto out_nfserr;
/*
! * check if we have crossed a mount point ...
*/
if (dchild->d_sb !=3D dparent->d_sb) {
! struct dentry *tdentry;
! tdentry =3D dchild->d_covers;
! if (tdentry =3D=3D dchild)
! goto out_dput;
! dput(dchild);
! dchild =3D dget(tdentry);
! if (dchild->d_sb !=3D dparent->d_sb) {
! printk("nfsd_lookup: %s/%s crossed mount point!\n", dparent->d_name.nam=
e, dchild->d_name.name);
! goto out_dput;
! }
}
=

/*
***************
*** 416,423 ****
* N.B. After this call fhp needs an fh_put
*/
int
! nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, ch=
ar *buf,
! unsigned long *count)
{
struct raparms *ra;
mm_segment_t oldfs;
--- 423,430 ----
* N.B. After this call fhp needs an fh_put
*/
int
! nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
! char *buf, unsigned long *count)
{
struct raparms *ra;
mm_segment_t oldfs;
***************
*** 1224,1229 ****
--- 1231,1237 ----
if (acc =3D=3D MAY_NOP)
return 0;
=

+ =

/*
dprintk("nfsd: permission 0x%x%s%s%s%s%s mode 0%o%s%s%s\n",
acc,
***************
*** 1239,1244 ****
--- 1247,1259 ----
dprintk(" owner %d/%d user %d/%d\n",
inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
*/
+ =

+ #ifndef CONFIG_NFSD_SUN
+ if (dentry->d_mounts !=3D dentry) {
+ dprintk("Hiding under the cover.\n");
+ return nfserr_perm;
+ }
+ #endif
=

if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) {
if (EX_RDONLY(exp) || IS_RDONLY(inode))
Index: linux/include/linux/nfsd/export.h
diff -c linux/include/linux/nfsd/export.h:1.1 linux/include/linux/nfsd/ex=
port.h:1.2
*** linux/include/linux/nfsd/export.h:1.1 Thu Sep 10 09:08:46 1998
--- linux/include/linux/nfsd/export.h Fri Sep 11 09:40:56 1998
***************
*** 86,91 ****
--- 86,92 ----
void exp_putclient(struct svc_client *clp);
struct svc_export * exp_get(struct svc_client *clp, kdev_t dev, ino_t i=
no);
int exp_rootfh(struct svc_client *, kdev_t, ino_t,
+ char *path,
struct knfs_fh *);
int nfserrno(int errno);
void exp_nlmdetach(void);
Index: linux/include/linux/nfsd/syscall.h
diff -c linux/include/linux/nfsd/syscall.h:1.1 linux/include/linux/nfsd/s=
yscall.h:1.2
*** linux/include/linux/nfsd/syscall.h:1.1 Thu Sep 10 09:08:46 1998
--- linux/include/linux/nfsd/syscall.h Fri Sep 11 09:40:56 1998
***************
*** 32,39 ****
#define NFSCTL_EXPORT 3 /* export a file system. */
#define NFSCTL_UNEXPORT 4 /* unexport a file system. */
#define NFSCTL_UGIDUPDATE 5 /* update a client's uid/gid map. */
! #define NFSCTL_GETFH 6 /* get an fh (used by mountd) */
! =

=

/* SVC */
struct nfsctl_svc {
--- 32,39 ----
#define NFSCTL_EXPORT 3 /* export a file system. */
#define NFSCTL_UNEXPORT 4 /* unexport a file system. */
#define NFSCTL_UGIDUPDATE 5 /* update a client's uid/gid map. */
! #define NFSCTL_GETFH 6 /* get an fh by ino (used by mountd) */
! #define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */
=

/* SVC */
struct nfsctl_svc {
***************
*** 81,86 ****
--- 81,93 ----
int gf_version;
};
=

+ /* GETFD */
+ struct nfsctl_fdparm {
+ struct sockaddr gd_addr;
+ char gd_path[NFS_MAXPATHLEN+1];
+ int gd_version;
+ };
+ =

/*
* This is the argument union.
*/
***************
*** 92,97 ****
--- 99,105 ----
struct nfsctl_export u_export;
struct nfsctl_uidmap u_umap;
struct nfsctl_fhparm u_getfh;
+ struct nfsctl_fdparm u_getfd;
unsigned int u_debug;
} u;
#define ca_svc u.u_svc
***************
*** 99,104 ****
--- 107,113 ----
#define ca_export u.u_export
#define ca_umap u.u_umap
#define ca_getfh u.u_getfh
+ #define ca_getfd u.u_getfd
#define ca_authd u.u_authd
#define ca_debug u.u_debug
};

--==_Exmh_-14249306240--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/