patch for 2.1.78 knfsd

Bill Hawes (whawes@star.net)
Sun, 11 Jan 1998 13:07:48 -0500


This is a multi-part message in MIME format.
--------------9E1F668E190354DA0991AC58
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

The attached patch (slightly updated) for 2.1.78 knfsd fixes a couple of
reported problems with certain clients. The nfs create procedure wasn't
truncating the file properly when called for an existing file, and the
setattr procedure was ignoring other attributes after a size change.

The patch also adds a fill_inode function for the nfsd sysctl and stat
routines; this is used to increment and decrement the module counts so
that the module can't be unloaded while a /proc inode refers to it.

I've removed the briefly-added "xyzzx" debugging toggle, as it's easier
to just use the /proc/sys/sunrpc/nfsd_debug sysctl variable for
debugging control.

Regards,
Bill
--------------9E1F668E190354DA0991AC58
Content-Type: text/plain; charset=us-ascii; name="nfsd_78-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="nfsd_78-patch"

--- linux-2.1.78/include/linux/nfsd/nfsfh.h.old Tue Jan 6 12:15:39 1998
+++ linux-2.1.78/include/linux/nfsd/nfsfh.h Sun Jan 11 13:21:53 1998
@@ -70,6 +70,8 @@
* Shorthand for dprintk()'s
*/
#define SVCFH_DENTRY(f) ((f)->fh_dentry)
+#define SVCFH_INO(f) ((f)->fh_handle.fh_ino)
+#define SVCFH_DEV(f) ((f)->fh_handle.fh_dev)

/*
* Function prototypes
--- linux-2.1.78/include/linux/nfsd/nfsd.h.old Fri Jan 9 12:55:13 1998
+++ linux-2.1.78/include/linux/nfsd/nfsd.h Sun Jan 11 13:22:09 1998
@@ -111,6 +111,9 @@
int nfsd_notify_change(struct inode *, struct iattr *);
int nfsd_permission(struct svc_export *, struct dentry *, int);

+/* nfsd/nfsctl.c */
+void nfsd_modcount(struct inode *, int);
+
/*
* lockd binding
*/
--- linux-2.1.78/fs/nfsd/vfs.c.old Tue Jan 6 11:39:08 1998
+++ linux-2.1.78/fs/nfsd/vfs.c Fri Jan 9 13:43:04 1998
@@ -190,20 +190,24 @@
inode = dentry->d_inode;

/* The size case is special... */
- if ((iap->ia_valid & ATTR_SIZE) && S_ISREG(inode->i_mode)) {
+ if (iap->ia_valid & ATTR_SIZE) {
+if (!S_ISREG(inode->i_mode))
+printk("nfsd_setattr: size change??\n");
if (iap->ia_size < inode->i_size) {
err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC);
if (err != 0)
goto out;
}
- if ((err = get_write_access(inode)) != 0)
- return nfserrno(-err);
+ err = get_write_access(inode);
+ if (err)
+ goto out_nfserr;
+ /* N.B. Should we update the inode cache here? */
inode->i_size = iap->ia_size;
if (inode->i_op && inode->i_op->truncate)
inode->i_op->truncate(inode);
mark_inode_dirty(inode);
put_write_access(inode);
- iap->ia_valid &= ATTR_SIZE;
+ iap->ia_valid &= ~ATTR_SIZE;
iap->ia_valid |= ATTR_MTIME;
iap->ia_mtime = CURRENT_TIME;
}
@@ -232,13 +236,17 @@
iap->ia_ctime = CURRENT_TIME;
err = notify_change(dentry, iap);
if (err)
- return nfserrno(-err);
+ goto out_nfserr;
if (EX_ISSYNC(fhp->fh_export))
write_inode_now(inode);
}
err = 0;
out:
return err;
+
+out_nfserr:
+ err = nfserrno(-err);
+ goto out;
}

/*
--- linux-2.1.78/fs/nfsd/nfsfh.c.old Sun Nov 30 11:33:43 1997
+++ linux-2.1.78/fs/nfsd/nfsfh.c Fri Jan 9 15:08:05 1998
@@ -1089,8 +1089,10 @@
{
struct inode * inode = dentry->d_inode;

- dprintk("nfsd: fh_compose(exp %x/%ld dentry %p)\n",
- exp->ex_dev, exp->ex_ino, dentry);
+ dprintk("nfsd: fh_compose(exp %x/%ld %s/%s, ino=%ld)\n",
+ exp->ex_dev, exp->ex_ino,
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ (inode ? inode->i_ino : 0));

/*
* N.B. We shouldn't need to init the fh -- the call to fh_compose
--- linux-2.1.78/fs/nfsd/nfsproc.c.old Sun Nov 30 11:26:24 1997
+++ linux-2.1.78/fs/nfsd/nfsproc.c Sat Jan 10 11:35:03 1998
@@ -56,7 +56,8 @@
nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
struct nfsd_attrstat *resp)
{
- dprintk("nfsd: GETATTR %p\n", SVCFH_DENTRY(&argp->fh));
+ dprintk("nfsd: GETATTR %d/%ld\n",
+ SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh));

fh_copy(&resp->fh, &argp->fh);
RETURN(fh_verify(rqstp, &resp->fh, 0, MAY_NOP));
@@ -70,7 +71,9 @@
nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
struct nfsd_attrstat *resp)
{
- dprintk("nfsd: SETATTR %p\n", SVCFH_DENTRY(&argp->fh));
+ dprintk("nfsd: SETATTR %d/%ld, valid=%x, size=%ld\n",
+ SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh),
+ argp->attrs.ia_valid, (long) argp->attrs.ia_size);

fh_copy(&resp->fh, &argp->fh);
RETURN(nfsd_setattr(rqstp, &resp->fh, &argp->attrs));
@@ -88,7 +91,8 @@
{
int nfserr;

- dprintk("nfsd: LOOKUP %p %s\n", SVCFH_DENTRY(&argp->fh), argp->name);
+ dprintk("nfsd: LOOKUP %d/%ld %s\n",
+ SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh), argp->name);

nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
&resp->fh);
@@ -131,8 +135,8 @@
u32 * buffer;
int nfserr, avail;

- dprintk("nfsd: READ %p %d bytes at %d\n",
- SVCFH_DENTRY(&argp->fh),
+ dprintk("nfsd: READ %d/%ld %d bytes at %d\n",
+ SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh),
argp->count, argp->offset);

/* Obtain buffer pointer for payload. 19 is 1 word for
@@ -168,8 +172,8 @@
{
int nfserr;

- dprintk("nfsd: WRITE %p %d bytes at %d\n",
- SVCFH_DENTRY(&argp->fh),
+ dprintk("nfsd: WRITE %d/%ld %d bytes at %d\n",
+ SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh),
argp->len, argp->offset);

nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
@@ -192,24 +196,21 @@
nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
struct nfsd_diropres *resp)
{
- struct inode *dirp, *inode = NULL;
- struct iattr *attr;
- svc_fh *dirfhp, *newfhp;
+ svc_fh *dirfhp = &argp->fh;
+ svc_fh *newfhp = &resp->fh;
+ struct iattr *attr = &argp->attrs;
+ struct inode *inode = NULL;
int nfserr, type, mode;
int rdonly = 0, exists;
dev_t rdev = NODEV;

- dprintk("nfsd: CREATE %p %s\n", SVCFH_DENTRY(&argp->fh), argp->name);
-
- dirfhp = &argp->fh;
- newfhp = &resp->fh;
- attr = &argp->attrs;
+ dprintk("nfsd: CREATE %d/%ld %s\n",
+ SVCFH_DEV(dirfhp), SVCFH_INO(dirfhp), argp->name);

/* Get the directory inode */
nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_EXEC);
if (nfserr)
goto done; /* must fh_put dirfhp even on error */
- dirp = dirfhp->fh_dentry->d_inode;

/* Check for MAY_WRITE separately. */
nfserr = nfsd_permission(dirfhp->fh_export, dirfhp->fh_dentry,
@@ -247,10 +248,9 @@
}

/* This is for "echo > /dev/null" a la SunOS. Argh. */
- if (rdonly && (!exists || type == S_IFREG)) {
- nfserr = nfserr_rofs;
+ nfserr = nfserr_rofs;
+ if (rdonly && (!exists || type == S_IFREG))
goto done;
- }

attr->ia_valid |= ATTR_MODE;
attr->ia_mode = type | mode;
@@ -292,11 +292,19 @@
nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len,
attr, type, rdev, newfhp);
} else if (type == S_IFREG) {
+ dprintk("nfsd: existing %s, valid=%x, size=%ld\n",
+ argp->name, attr->ia_valid, (long) attr->ia_size);
/* File already exists. We ignore all attributes except
* size, so that creat() behaves exactly like
* open(..., O_CREAT|O_TRUNC|O_WRONLY).
*/
+#if 0
+ /* N.B. What is this doing? ignores size?? */
if ((attr->ia_valid &= ~(ATTR_SIZE)) != 0)
+ nfserr = nfsd_setattr(rqstp, newfhp, attr);
+#endif
+ attr->ia_valid &= ATTR_SIZE;
+ if (attr->ia_valid)
nfserr = nfsd_setattr(rqstp, newfhp, attr);
}

--- linux-2.1.78/fs/nfsd/stats.c.old Sun Nov 30 11:33:43 1997
+++ linux-2.1.78/fs/nfsd/stats.c Fri Jan 9 18:13:30 1998
@@ -75,8 +75,12 @@
{
struct proc_dir_entry *ent;

- if ((ent = svc_proc_register(&nfsd_svcstats)) != 0)
+ if ((ent = svc_proc_register(&nfsd_svcstats)) != 0) {
ent->read_proc = nfsd_proc_read;
+#ifdef MODULE
+ ent->fill_inode = nfsd_modcount;
+#endif
+ }
}

void
--- linux-2.1.78/fs/nfsd/nfsctl.c.old Sun Nov 30 11:26:24 1997
+++ linux-2.1.78/fs/nfsd/nfsctl.c Sat Jan 10 15:53:49 1998
@@ -222,6 +222,21 @@
extern int (*do_nfsservctl)(int, void *, void *);

/*
+ * This is called as the fill_inode function when an inode
+ * is going into (fill = 1) or out of service (fill = 0).
+ *
+ * We use it here to make sure the module can't be unloaded
+ * while a /proc inode is in use.
+ */
+void nfsd_modcount(struct inode *inode, int fill)
+{
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
+}
+
+/*
* Initialize the module
*/
int

--------------9E1F668E190354DA0991AC58--