updated patch for 2.1.78 nfs client

Bill Hawes (whawes@star.net)
Sun, 11 Jan 1998 12:55:15 -0500


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

The attached patch against 2.1.78 makes some additional changes to the
NFS client code. In write.c, I've moved the structure definitions for
the nfs write requests into nfs_fs.h, so that it can be used outside of
nfs. The writeback requests also set a new flag in the RPC task
structure so that they can be more easily identified.

In nfs_fs_sb.h I've removed the large buffer area for the host name and
now allocate a buffer in nfs_read_super. This reduces the size of the
NFS superblock from being the second-largest to be one of the smallest.

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

--- linux-2.1.78/include/linux/nfs_fs.h.old Tue Jan 6 12:01:32 1998
+++ linux-2.1.78/include/linux/nfs_fs.h Sun Jan 11 13:33:27 1998
@@ -13,7 +13,7 @@
#include <linux/sched.h>
#include <linux/in.h>

-#include <linux/sunrpc/debug.h>
+#include <linux/sunrpc/sched.h>
#include <linux/nfs.h>
#include <linux/nfs_mount.h>

@@ -78,8 +78,6 @@

#define NFS_FLAGS(inode) ((inode)->u.nfs_i.flags)
#define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATE)
-
-#define NFS_RENAMED_DIR(inode) ((inode)->u.nfs_i.silly_inode)
#define NFS_WRITEBACK(inode) ((inode)->u.nfs_i.writeback)

/*
@@ -90,6 +88,46 @@
#ifdef __KERNEL__

/*
+ * This struct describes a file region to be written.
+ * It's kind of a pity we have to keep all these lists ourselves, rather
+ * than sticking an extra pointer into struct page.
+ */
+struct nfs_wreq {
+ struct rpc_listitem wb_list; /* linked list of req's */
+ struct rpc_task wb_task; /* RPC task */
+ struct dentry * wb_dentry; /* dentry referenced */
+ struct inode * wb_inode; /* inode referenced */
+ struct page * wb_page; /* page to be written */
+ unsigned int wb_offset; /* offset within page */
+ unsigned int wb_bytes; /* dirty range */
+ pid_t wb_pid; /* owner process */
+ unsigned short wb_flags; /* status flags */
+
+ struct nfs_writeargs * wb_args; /* NFS RPC stuff */
+ struct nfs_fattr * wb_fattr; /* file attributes */
+};
+#define wb_status wb_task.tk_status
+
+#define WB_NEXT(req) ((struct nfs_wreq *) ((req)->wb_list.next))
+
+/*
+ * Various flags for wb_flags
+ */
+#define NFS_WRITE_WANTLOCK 0x0001 /* needs to lock page */
+#define NFS_WRITE_LOCKED 0x0002 /* holds lock on page */
+#define NFS_WRITE_CANCELLED 0x0004 /* has been cancelled */
+#define NFS_WRITE_UNCOMMITTED 0x0008 /* written but uncommitted (NFSv3) */
+#define NFS_WRITE_INVALIDATE 0x0010 /* invalidate after write */
+#define NFS_WRITE_INPROGRESS 0x0020 /* RPC call in progress */
+
+#define WB_WANTLOCK(req) ((req)->wb_flags & NFS_WRITE_WANTLOCK)
+#define WB_HAVELOCK(req) ((req)->wb_flags & NFS_WRITE_LOCKED)
+#define WB_CANCELLED(req) ((req)->wb_flags & NFS_WRITE_CANCELLED)
+#define WB_UNCOMMITTED(req) ((req)->wb_flags & NFS_WRITE_UNCOMMITTED)
+#define WB_INVALIDATE(req) ((req)->wb_flags & NFS_WRITE_INVALIDATE)
+#define WB_INPROGRESS(req) ((req)->wb_flags & NFS_WRITE_INPROGRESS)
+
+/*
* linux/fs/nfs/proc.c
*/
extern int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
@@ -171,6 +209,7 @@
* linux/fs/nfs/write.c
*/
extern int nfs_writepage(struct dentry *, struct page *);
+extern int nfs_find_dentry_request(struct inode *, struct dentry *);
extern int nfs_check_failed_request(struct inode *);
extern int nfs_check_error(struct inode *);
extern int nfs_flush_dirty_pages(struct inode *, pid_t, off_t, off_t);
--- linux-2.1.78/include/linux/nfs_fs_sb.h.old Tue Jan 6 12:00:52 1998
+++ linux-2.1.78/include/linux/nfs_fs_sb.h Sun Jan 11 13:08:12 1998
@@ -5,8 +5,7 @@
#include <linux/in.h>

/*
- * NFS client parameters
- * Part of this is duplicated in rpc_clnt and is therefore obsolete.
+ * NFS client parameters stored in the superblock.
*/
struct nfs_server {
struct rpc_clnt * client; /* RPC client handle */
@@ -18,7 +17,7 @@
unsigned int acregmax;
unsigned int acdirmin;
unsigned int acdirmax;
- char hostname[256]; /* remote hostname */
+ char * hostname; /* remote hostname */
};

/*
--- linux-2.1.78/fs/nfs/inode.c.old Tue Jan 6 11:39:08 1998
+++ linux-2.1.78/fs/nfs/inode.c Sun Jan 11 13:42:47 1998
@@ -138,6 +138,7 @@
*/
nfs_invalidate_dircache_sb(sb);

+ kfree(server->hostname);
sb->s_dev = 0;
unlock_super(sb);
MOD_DEC_USE_COUNT;
@@ -222,6 +223,10 @@
server->acregmax = data->acregmax*HZ;
server->acdirmin = data->acdirmin*HZ;
server->acdirmax = data->acdirmax*HZ;
+
+ server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
+ if (!server->hostname)
+ goto out_unlock;
strcpy(server->hostname, data->hostname);

/* Which protocol do we use? */
@@ -308,6 +313,7 @@

out_no_xprt:
printk("NFS: cannot create RPC transport.\n");
+ kfree(server->hostname);
out_unlock:
unlock_super(sb);
goto out_fail;
--- linux-2.1.78/fs/nfs/dir.c.old Tue Jan 6 11:39:07 1998
+++ linux-2.1.78/fs/nfs/dir.c Wed Jan 7 18:09:22 1998
@@ -35,6 +35,7 @@
extern void nfs_renew_times(struct dentry *);

#define NFS_PARANOIA 1
+/* #define NFS_DEBUG_VERBOSE 1 */

/*
* Head for a dircache entry. Currently still very simple; when
@@ -458,6 +459,28 @@
}

/*
+ * Called to free the inode from the dentry. We must flush
+ * any pending writes for this dentry before freeing the inode.
+ */
+static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
+{
+ if (NFS_WRITEBACK(inode)) {
+#ifdef NFS_PARANOIA
+printk("nfs_dentry_iput: pending writes for %s/%s, i_count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_count);
+#endif
+ while (nfs_find_dentry_request(inode, dentry)) {
+#ifdef NFS_PARANOIA
+printk("nfs_dentry_iput: flushing %s/%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ nfs_flush_dirty_pages(inode, 0, 0, 0);
+ }
+ }
+ iput(inode);
+}
+
+/*
* Called when the dentry is being freed to release private memory.
*/
static void nfs_dentry_release(struct dentry *dentry)
@@ -471,9 +494,53 @@
NULL, /* d_hash */
NULL, /* d_compare */
nfs_dentry_delete, /* d_delete(struct dentry *) */
+ nfs_dentry_iput, /* d_iput(struct dentry *, struct inode *) */
nfs_dentry_release /* d_release(struct dentry *) */
};

+#ifdef NFS_PARANOIA
+/*
+ * Display all dentries holding the specified inode.
+ */
+static void show_dentry(struct inode * inode)
+{
+ struct dentry *parent = inode->i_sb->s_root;
+ struct dentry *this_parent = parent;
+ struct list_head *next;
+
+repeat:
+ next = this_parent->d_subdirs.next;
+resume:
+ while (next != &this_parent->d_subdirs) {
+ struct list_head *tmp = next;
+ struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
+ next = tmp->next;
+ if (dentry->d_inode == inode) {
+ int unhashed = list_empty(&dentry->d_hash);
+ printk("show_dentry: %s/%s, d_count=%d%s\n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name, dentry->d_count,
+ unhashed ? "(unhashed)" : "");
+ }
+ /*
+ * Descend a level if the d_subdirs list is non-empty.
+ */
+ if (!list_empty(&dentry->d_subdirs)) {
+ this_parent = dentry;
+ goto repeat;
+ }
+ }
+ /*
+ * All done at this level ... ascend and resume the search.
+ */
+ if (this_parent != parent) {
+ next = this_parent->d_child.next;
+ this_parent = this_parent->d_parent;
+ goto resume;
+ }
+}
+#endif
+
/*
* Whenever a lookup succeeds, we know the parent directories
* are all valid, so we want to update the dentry timestamps.
@@ -531,10 +598,12 @@
inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);
if (inode) {
#ifdef NFS_PARANOIA
-if (inode->i_count > (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink))
+if (inode->i_count > (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink)) {
printk("nfs_lookup: %s/%s ino=%ld in use, count=%d, nlink=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
inode->i_ino, inode->i_count, inode->i_nlink);
+show_dentry(inode);
+}
#endif
no_entry:
d_add(dentry, inode);
@@ -564,10 +633,12 @@
inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
if (inode) {
#ifdef NFS_PARANOIA
-if (inode->i_count > (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink))
+if (inode->i_count > (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink)) {
printk("nfs_instantiate: %s/%s ino=%ld in use, count=%d, nlink=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
inode->i_ino, inode->i_count, inode->i_nlink);
+show_dentry(inode);
+}
#endif
d_instantiate(dentry, inode);
nfs_renew_times(dentry);
@@ -682,10 +753,6 @@
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;

- nfs_invalidate_dircache(dir);
- error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
- dentry->d_name.name, &sattr, &fhandle, &fattr);
-
/*
* Always drop the dentry, we can't always depend on
* the fattr returned by the server (AIX seems to be
@@ -693,6 +760,9 @@
* depending on potentially bogus information.
*/
d_drop(dentry);
+ nfs_invalidate_dircache(dir);
+ error = nfs_proc_mkdir(NFS_DSERVER(dentry), NFS_FH(dentry->d_parent),
+ dentry->d_name.name, &sattr, &fhandle, &fattr);
out:
return error;
}
--- linux-2.1.78/fs/nfs/write.c.old Tue Jan 6 11:39:08 1998
+++ linux-2.1.78/fs/nfs/write.c Sat Jan 10 15:36:37 1998
@@ -52,6 +52,7 @@
#include <linux/malloc.h>
#include <linux/swap.h>
#include <linux/pagemap.h>
+
#include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h>
#include <asm/uaccess.h>
@@ -66,52 +67,13 @@
*/
#define IS_SOFT 0

+#define NFS_PARANOIA 1
#define NFSDBG_FACILITY NFSDBG_PAGECACHE

static void nfs_wback_lock(struct rpc_task *task);
static void nfs_wback_result(struct rpc_task *task);

/*
- * This struct describes a file region to be written.
- * It's kind of a pity we have to keep all these lists ourselves, rather
- * than sticking an extra pointer into struct page.
- */
-struct nfs_wreq {
- struct rpc_listitem wb_list; /* linked list of req's */
- struct rpc_task wb_task; /* RPC task */
- struct dentry * wb_dentry; /* dentry referenced */
- struct inode * wb_inode; /* inode referenced */
- struct page * wb_page; /* page to be written */
- unsigned int wb_offset; /* offset within page */
- unsigned int wb_bytes; /* dirty range */
- pid_t wb_pid; /* owner process */
- unsigned short wb_flags; /* status flags */
-
- struct nfs_writeargs * wb_args; /* NFS RPC stuff */
- struct nfs_fattr * wb_fattr; /* file attributes */
-};
-#define wb_status wb_task.tk_status
-
-#define WB_NEXT(req) ((struct nfs_wreq *) ((req)->wb_list.next))
-
-/*
- * Various flags for wb_flags
- */
-#define NFS_WRITE_WANTLOCK 0x0001 /* needs to lock page */
-#define NFS_WRITE_LOCKED 0x0002 /* holds lock on page */
-#define NFS_WRITE_CANCELLED 0x0004 /* has been cancelled */
-#define NFS_WRITE_UNCOMMITTED 0x0008 /* written but uncommitted (NFSv3) */
-#define NFS_WRITE_INVALIDATE 0x0010 /* invalidate after write */
-#define NFS_WRITE_INPROGRESS 0x0020 /* RPC call in progress */
-
-#define WB_INPROGRESS(req) ((req)->wb_flags & NFS_WRITE_INPROGRESS)
-#define WB_WANTLOCK(req) ((req)->wb_flags & NFS_WRITE_WANTLOCK)
-#define WB_HAVELOCK(req) ((req)->wb_flags & NFS_WRITE_LOCKED)
-#define WB_CANCELLED(req) ((req)->wb_flags & NFS_WRITE_CANCELLED)
-#define WB_UNCOMMITTED(req) ((req)->wb_flags & NFS_WRITE_UNCOMMITTED)
-#define WB_INVALIDATE(req) ((req)->wb_flags & NFS_WRITE_INVALIDATE)
-
-/*
* Cache parameters
*/
#define NFS_WRITEBACK_DELAY (10 * HZ)
@@ -282,6 +244,27 @@
}

/*
+ * Find any requests for the specified dentry.
+ */
+int
+nfs_find_dentry_request(struct inode *inode, struct dentry *dentry)
+{
+ struct nfs_wreq *head, *req;
+ int found = 0;
+
+ req = head = NFS_WRITEBACK(inode);
+ while (req != NULL) {
+ if (req->wb_dentry == dentry) {
+ found = 1;
+ break;
+ }
+ if ((req = WB_NEXT(req)) == head)
+ break;
+ }
+ return found;
+}
+
+/*
* Find a failed write request by pid
*/
static struct nfs_wreq *
@@ -400,7 +383,7 @@
memset(wreq, 0, sizeof(*wreq));

task = &wreq->wb_task;
- rpc_init_task(task, clnt, nfs_wback_result, 0);
+ rpc_init_task(task, clnt, nfs_wback_result, RPC_TASK_NFSWRITE);
task->tk_calldata = wreq;
task->tk_action = nfs_wback_lock;

@@ -612,14 +595,18 @@
/*
* Flush out a dirty page.
*/
-static inline void
+static void
nfs_flush_request(struct nfs_wreq *req)
{
struct page *page = req->wb_page;

- dprintk("NFS: nfs_flush_request(%x/%ld, @%ld)\n",
- page->inode->i_dev, page->inode->i_ino,
- page->offset);
+#ifdef NFS_DEBUG_VERBOSE
+if (req->wb_inode != page->inode)
+printk("NFS: inode %ld no longer has page %p\n", req->wb_inode->i_ino, page);
+#endif
+ dprintk("NFS: nfs_flush_request(%s/%s, @%ld)\n",
+ req->wb_dentry->d_parent->d_name.name,
+ req->wb_dentry->d_name.name, page->offset);

req->wb_flags |= NFS_WRITE_WANTLOCK;
if (!test_and_set_bit(PG_locked, &page->flags)) {
@@ -656,7 +643,7 @@
if (rqoffset < end && offset < rqend
&& (pid == 0 || req->wb_pid == pid)) {
if (!WB_HAVELOCK(req)) {
-#ifdef NFS_PARANOIA
+#ifdef NFS_DEBUG_VERBOSE
printk("nfs_flush: flushing inode=%ld, %d @ %lu\n",
req->wb_inode->i_ino, req->wb_bytes, rqoffset);
#endif
@@ -664,11 +651,6 @@
}
last = req;
}
- } else {
-#ifdef NFS_PARANOIA
-printk("nfs_flush_pages: in progress inode=%ld, %d @ %lu\n",
-req->wb_inode->i_ino, req->wb_bytes, rqoffset);
-#endif
}
if (invalidate)
req->wb_flags |= NFS_WRITE_INVALIDATE;
--- linux-2.1.78/include/linux/dcache.h.old Tue Jan 6 11:39:09 1998
+++ linux-2.1.78/include/linux/dcache.h Tue Jan 6 11:58:23 1998
@@ -71,9 +71,10 @@

struct dentry_operations {
int (*d_revalidate)(struct dentry *);
- int (*d_hash) (struct dentry *,struct qstr *);
- int (*d_compare) (struct dentry *,struct qstr *, struct qstr *);
+ int (*d_hash) (struct dentry *, struct qstr *);
+ int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
void (*d_delete)(struct dentry *);
+ void (*d_iput)(struct dentry *, struct inode *);
void (*d_release)(struct dentry *);
};

--- linux-2.1.78/fs/dcache.c.old Tue Jan 6 11:39:05 1998
+++ linux-2.1.78/fs/dcache.c Wed Jan 7 14:06:56 1998
@@ -59,6 +60,22 @@
}

/*
+ * Release the dentry's inode, using the fileystem
+ * d_iput() operation if defined.
+ */
+static inline void dentry_iput(struct dentry * dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ if (inode) {
+ dentry->d_inode = NULL;
+ if (dentry->d_op && dentry->d_op->d_iput)
+ dentry->d_op->d_iput(dentry, inode);
+ else
+ iput(inode);
+ }
+}
+
+/*
* dput()
*
* This is complicated by the fact that we do not want to put
@@ -104,13 +121,10 @@
list_del(&dentry->d_lru);
}
if (list_empty(&dentry->d_hash)) {
- struct inode *inode = dentry->d_inode;
struct dentry * parent;
+
list_del(&dentry->d_child);
- if (inode) {
- dentry->d_inode = NULL;
- iput(inode);
- }
+ dentry_iput(dentry);
parent = dentry->d_parent;
d_free(dentry);
if (dentry == parent)
@@ -259,12 +273,7 @@

list_del(&dentry->d_hash);
list_del(&dentry->d_child);
- if (dentry->d_inode) {
- struct inode * inode = dentry->d_inode;
-
- dentry->d_inode = NULL;
- iput(inode);
- }
+ dentry_iput(dentry);
parent = dentry->d_parent;
d_free(dentry);
dput(parent);
@@ -636,11 +713,7 @@
* Are we the only user?
*/
if (dentry->d_count == 1) {
- struct inode * inode = dentry->d_inode;
- if (inode) {
- dentry->d_inode = NULL;
- iput(inode);
- }
+ dentry_iput(dentry);
return;
}

--------------102F266CF02D6E4946DE5ADA--