patch-2.4.0-test12 linux/fs/nfs/write.c

Next file: linux/fs/ntfs/fs.c
Previous file: linux/fs/nfs/symlink.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test11/linux/fs/nfs/write.c linux/fs/nfs/write.c
@@ -77,7 +77,7 @@
  */
 struct nfs_write_data {
 	struct rpc_task		task;
-	struct dentry		*dentry;
+	struct inode		*inode;
 	struct rpc_cred		*cred;
 	struct nfs_writeargs	args;		/* argument struct */
 	struct nfs_writeres	res;		/* result struct */
@@ -89,7 +89,8 @@
 /*
  * Local function declarations
  */
-static struct nfs_page * nfs_update_request(struct file*, struct page *page,
+static struct nfs_page * nfs_update_request(struct file*, struct inode *,
+					    struct page *,
 					    unsigned int, unsigned int);
 static void	nfs_strategy(struct inode *inode);
 static void	nfs_writeback_done(struct rpc_task *);
@@ -167,11 +168,10 @@
  * Offset is the data offset within the page.
  */
 static int
-nfs_writepage_sync(struct file *file, struct page *page,
+nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page,
 		   unsigned int offset, unsigned int count)
 {
-	struct dentry	*dentry = file->f_dentry;
-	struct inode	*inode = dentry->d_inode;
+	struct rpc_cred	*cred = NULL;
 	loff_t		base;
 	unsigned int	wsize = NFS_SERVER(inode)->wsize;
 	int		result, refresh = 0, written = 0, flags;
@@ -179,9 +179,13 @@
 	struct nfs_fattr fattr;
 	struct nfs_writeverf verf;
 
+
+	if (file)
+		cred = nfs_file_cred(file);
+
 	lock_kernel();
-	dprintk("NFS:      nfs_writepage_sync(%s/%s %d@%Ld)\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name,
+	dprintk("NFS:      nfs_writepage_sync(%x/%Ld %d@%Ld)\n",
+		inode->i_dev, (long long)NFS_FILEID(inode),
 		count, (long long)(page_offset(page) + offset));
 
 	buffer = kmap(page) + offset;
@@ -193,7 +197,7 @@
 		if (count < wsize && !IS_SWAPFILE(inode))
 			wsize = count;
 
-		result = NFS_PROTO(inode)->write(file, &fattr, flags,
+		result = NFS_PROTO(inode)->write(inode, cred, &fattr, flags,
 						 base, wsize, buffer, &verf);
 		nfs_write_attributes(inode, &fattr);
 
@@ -229,18 +233,18 @@
 }
 
 static int
-nfs_writepage_async(struct file *file, struct page *page,
+nfs_writepage_async(struct file *file, struct inode *inode, struct page *page,
 		    unsigned int offset, unsigned int count)
 {
 	struct nfs_page	*req;
 	int		status;
 
-	req = nfs_update_request(file, page, offset, count);
+	req = nfs_update_request(file, inode, page, offset, count);
 	status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
 	if (status < 0)
 		goto out;
 	nfs_release_request(req);
-	nfs_strategy(file->f_dentry->d_inode);
+	nfs_strategy(inode);
  out:
 	return status;
 }
@@ -249,33 +253,48 @@
  * Write an mmapped page to the server.
  */
 int
-nfs_writepage(struct file *file, struct page *page)
+nfs_writepage(struct page *page)
 {
-	struct inode *inode = file->f_dentry->d_inode;
-	unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+	struct inode *inode;
+	unsigned long end_index;
 	unsigned offset = PAGE_CACHE_SIZE;
 	int err;
+	struct address_space *mapping = page->mapping;
+
+	if (!mapping)
+		BUG();
+	inode = (struct inode *)mapping->host;
+	if (!inode)
+		BUG();
+	end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+
+	/* Ensure we've flushed out any previous writes */
+	nfs_wb_page(inode,page);
 
 	/* easy case */
 	if (page->index < end_index)
 		goto do_it;
 	/* things got complicated... */
 	offset = inode->i_size & (PAGE_CACHE_SIZE-1);
+
 	/* OK, are we completely out? */
+	err = -EIO;
 	if (page->index >= end_index+1 || !offset)
-		return -EIO;
+		goto out;
 do_it:
 	if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) {
-		err = nfs_writepage_async(file, page, 0, offset);
+		err = nfs_writepage_async(NULL, inode, page, 0, offset);
 		if (err >= 0)
 			goto out_ok;
 	}
-	err = nfs_writepage_sync(file, page, 0, offset); 
-	if ( err == offset)
-		goto out_ok;
+	err = nfs_writepage_sync(NULL, inode, page, 0, offset); 
+	if ( err == offset) {
+out_ok:
+		err = 0;
+	}
+out:
+	UnlockPage(page);
 	return err; 
- out_ok:
-	return 0;
 }
 
 /*
@@ -315,6 +334,8 @@
 		return;
 	if (!NFS_WBACK_BUSY(req))
 		printk(KERN_ERR "NFS: unlocked request attempted hashed!\n");
+	if (list_empty(&inode->u.nfs_i.writeback))
+		atomic_inc(&inode->i_count);
 	inode->u.nfs_i.npages++;
 	list_add(&req->wb_hash, &inode->u.nfs_i.writeback);
 	req->wb_count++;
@@ -334,12 +355,14 @@
 	}
 	if (!NFS_WBACK_BUSY(req))
 		printk(KERN_ERR "NFS: unlocked request attempted unhashed!\n");
-	inode = req->wb_dentry->d_inode;
+	inode = req->wb_inode;
 	list_del(&req->wb_hash);
 	INIT_LIST_HEAD(&req->wb_hash);
 	inode->u.nfs_i.npages--;
 	if ((inode->u.nfs_i.npages == 0) != list_empty(&inode->u.nfs_i.writeback))
 		printk(KERN_ERR "NFS: desynchronized value of nfs_i.npages.\n");
+	if (list_empty(&inode->u.nfs_i.writeback))
+		iput(inode);
 	if (!nfs_have_writebacks(inode) && !nfs_have_read(inode))
 		inode_remove_flushd(inode);
 	spin_unlock(&nfs_wreq_lock);
@@ -422,7 +445,7 @@
 static inline void
 nfs_mark_request_dirty(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_dentry->d_inode;
+	struct inode *inode = req->wb_inode;
 
 	spin_lock(&nfs_wreq_lock);
 	if (list_empty(&req->wb_list)) {
@@ -443,7 +466,7 @@
 static inline int
 nfs_dirty_request(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_dentry->d_inode;
+	struct inode *inode = req->wb_inode;
 	return !list_empty(&req->wb_list) && req->wb_list_head == &inode->u.nfs_i.dirty;
 }
 
@@ -454,7 +477,7 @@
 static inline void
 nfs_mark_request_commit(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_dentry->d_inode;
+	struct inode *inode = req->wb_inode;
 
 	spin_lock(&nfs_wreq_lock);
 	if (list_empty(&req->wb_list)) {
@@ -477,11 +500,10 @@
  * when we reach the hard limit on the number of dirty pages.
  * It should be safe to sleep here.
  */
-struct nfs_page *nfs_create_request(struct file *file, struct page *page,
+struct nfs_page *nfs_create_request(struct file *file, struct inode *inode,
+				    struct page *page,
 				    unsigned int offset, unsigned int count)
 {
-	struct dentry		*dentry = file->f_dentry;
-	struct inode		*inode = dentry->d_inode;
 	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
 	struct nfs_page		*req = NULL;
 	long			timeout;
@@ -533,9 +555,15 @@
 	req->wb_offset  = offset;
 	req->wb_bytes   = count;
 	req->wb_file    = file;
-	get_file(file);
-	req->wb_dentry  = dentry;
-	req->wb_cred	= nfs_file_cred(file);
+
+	/* If we have a struct file, use its cached credentials
+	 * else cache the current process' credentials. */
+	if (file) {
+		get_file(file);
+		req->wb_cred	= nfs_file_cred(file);
+	} else
+		req->wb_cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+	req->wb_inode   = inode;
 	req->wb_count   = 1;
 
 	/* register request's existence */
@@ -554,7 +582,7 @@
 void
 nfs_release_request(struct nfs_page *req)
 {
-	struct inode		*inode = req->wb_dentry->d_inode;
+	struct inode		*inode = req->wb_inode;
 	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
 	struct page		*page = req->wb_page;
 
@@ -576,7 +604,11 @@
 	if (NFS_WBACK_BUSY(req))
 		printk(KERN_ERR "NFS: Request released while still locked!\n");
 
-	fput(req->wb_file);
+	/* Release struct file or cached credential */
+	if (req->wb_file)
+		fput(req->wb_file);
+	else
+		rpcauth_releasecred(NFS_CLIENT(inode)->cl_auth, req->wb_cred);
 	page_cache_release(page);
 	nfs_page_free(req);
 	/* wake up anyone waiting to allocate a request */
@@ -599,7 +631,7 @@
 static int
 nfs_wait_on_request(struct nfs_page *req)
 {
-	struct inode	*inode = req->wb_dentry->d_inode;
+	struct inode	*inode = req->wb_inode;
         struct rpc_clnt	*clnt = NFS_CLIENT(inode);
 
 	if (!NFS_WBACK_BUSY(req))
@@ -814,10 +846,9 @@
  * Note: Should always be called with the Page Lock held!
  */
 static struct nfs_page *
-nfs_update_request(struct file* file, struct page *page,
+nfs_update_request(struct file* file, struct inode *inode, struct page *page,
 		   unsigned int offset, unsigned int bytes)
 {
-	struct inode		*inode = file->f_dentry->d_inode;
 	struct nfs_page		*req, *new = NULL;
 	unsigned long		rqend, end;
 
@@ -857,7 +888,7 @@
 		 */
 		if (inode->u.nfs_i.npages >= MAX_REQUEST_SOFT)
 			nfs_wb_file(inode, file);
-		new = nfs_create_request(file, page, offset, bytes);
+		new = nfs_create_request(file, inode, page, offset, bytes);
 		if (!new)
 			return ERR_PTR(-ENOMEM);
 		/* If the region is locked, adjust the timeout */
@@ -995,7 +1026,7 @@
 	 * page synchronously.
 	 */
 	if (NFS_SERVER(inode)->wsize < PAGE_SIZE)
-		return nfs_writepage_sync(file, page, offset, count);
+		return nfs_writepage_sync(file, inode, page, offset, count);
 
 	/*
 	 * Try to find an NFS request corresponding to this page
@@ -1004,7 +1035,7 @@
 	 * it out now.
 	 */
 	do {
-		req = nfs_update_request(file, page, offset, count);
+		req = nfs_update_request(file, inode, page, offset, count);
 		status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
 		if (status != -EBUSY)
 			break;
@@ -1068,9 +1099,9 @@
 		data->args.nriov++;
 	}
 	req = nfs_list_entry(data->pages.next);
-	data->dentry = req->wb_dentry;
+	data->inode = req->wb_inode;
 	data->cred = req->wb_cred;
-	data->args.fh     = NFS_FH(req->wb_dentry);
+	data->args.fh     = NFS_FH(req->wb_inode);
 	data->args.offset = page_offset(req->wb_page) + req->wb_offset;
 	data->args.count  = count;
 	data->res.fattr   = &data->fattr;
@@ -1088,9 +1119,8 @@
  * that has been written but not committed.
  */
 static int
-nfs_flush_one(struct list_head *head, struct dentry *dentry, int how)
+nfs_flush_one(struct list_head *head, struct inode *inode, int how)
 {
-	struct inode            *inode = dentry->d_inode;
 	struct rpc_clnt 	*clnt = NFS_CLIENT(inode);
 	struct nfs_write_data	*data;
 	struct rpc_task		*task;
@@ -1134,10 +1164,10 @@
 	msg.rpc_resp = &data->res;
 	msg.rpc_cred = data->cred;
 
-	dprintk("NFS: %4d initiated write call (req %s/%s count %d nriov %d)\n",
+	dprintk("NFS: %4d initiated write call (req %x/%Ld count %d nriov %d)\n",
 		task->tk_pid, 
-		dentry->d_parent->d_name.name,
-		dentry->d_name.name,
+		inode->i_dev,
+		(long long)NFS_FILEID(inode),
 		data->args.count, data->args.nriov);
 
 	rpc_clnt_sigmask(clnt, &oldset);
@@ -1167,7 +1197,7 @@
 	while (!list_empty(head)) {
 		pages += nfs_coalesce_requests(head, &one_request, wpages);
 		req = nfs_list_entry(one_request.next);
-		error = nfs_flush_one(&one_request, req->wb_dentry, how);
+		error = nfs_flush_one(&one_request, req->wb_inode, how);
 		if (error < 0)
 			break;
 	}
@@ -1193,8 +1223,7 @@
 	struct nfs_write_data	*data = (struct nfs_write_data *) task->tk_calldata;
 	struct nfs_writeargs	*argp = &data->args;
 	struct nfs_writeres	*resp = &data->res;
-	struct dentry		*dentry = data->dentry;
-	struct inode		*inode = dentry->d_inode;
+	struct inode		*inode = data->inode;
 	struct nfs_page		*req;
 	struct page		*page;
 
@@ -1249,9 +1278,9 @@
 
 		kunmap(page);
 
-		dprintk("NFS: write (%s/%s %d@%Ld)",
-			req->wb_dentry->d_parent->d_name.name,
-			req->wb_dentry->d_name.name,
+		dprintk("NFS: write (%x/%Ld %d@%Ld)",
+			req->wb_inode->i_dev,
+			(long long)NFS_FILEID(req->wb_inode),
 			req->wb_bytes,
 			(long long)(page_offset(page) + req->wb_offset));
 
@@ -1292,7 +1321,6 @@
 nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
 {
 	struct nfs_page		*first, *last;
-	struct dentry		*dentry;
 	struct inode		*inode;
 	loff_t			start, end, len;
 
@@ -1303,8 +1331,7 @@
 	INIT_LIST_HEAD(head);
 	first = nfs_list_entry(data->pages.next);
 	last = nfs_list_entry(data->pages.prev);
-	dentry = first->wb_dentry;
-	inode = dentry->d_inode;
+	inode = first->wb_inode;
 
 	/*
 	 * Determine the offset range of requests in the COMMIT call.
@@ -1317,9 +1344,9 @@
 	if (end >= inode->i_size || len < 0 || len > (~((u32)0) >> 1))
 		len = 0;
 
-	data->dentry	  = dentry;
+	data->inode	  = inode;
 	data->cred	  = first->wb_cred;
-	data->args.fh     = NFS_FH(dentry);
+	data->args.fh     = NFS_FH(inode);
 	data->args.offset = start;
 	data->res.count   = data->args.count = (u32)len;
 	data->res.fattr   = &data->fattr;
@@ -1352,7 +1379,7 @@
 	/* Set up the argument struct */
 	nfs_commit_rpcsetup(head, data);
 	req = nfs_list_entry(data->pages.next);
-	clnt = NFS_CLIENT(req->wb_dentry->d_inode);
+	clnt = NFS_CLIENT(req->wb_inode);
 
 	rpc_init_task(task, clnt, nfs_commit_done, flags);
 	task->tk_calldata = data;
@@ -1389,8 +1416,7 @@
 	struct nfs_write_data	*data = (struct nfs_write_data *)task->tk_calldata;
 	struct nfs_writeres	*resp = &data->res;
 	struct nfs_page		*req;
-	struct dentry		*dentry = data->dentry;
-	struct inode		*inode = dentry->d_inode;
+	struct inode		*inode = data->inode;
 
         dprintk("NFS: %4d nfs_commit_done (status %d)\n",
                                 task->tk_pid, task->tk_status);
@@ -1400,9 +1426,9 @@
 		req = nfs_list_entry(data->pages.next);
 		nfs_list_remove_request(req);
 
-		dprintk("NFS: commit (%s/%s %d@%Ld)",
-			req->wb_dentry->d_parent->d_name.name,
-			req->wb_dentry->d_name.name,
+		dprintk("NFS: commit (%x/%Ld %d@%Ld)",
+			req->wb_inode->i_dev,
+			(long long)NFS_FILEID(req->wb_inode),
 			req->wb_bytes,
 			(long long)(page_offset(req->wb_page) + req->wb_offset));
 		if (task->tk_status < 0) {

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)