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
- Lines: 425
- Date:
Wed Dec 6 11:47:26 2000
- Orig file:
v2.4.0-test11/linux/fs/nfs/write.c
- Orig date:
Sun Nov 19 18:44:19 2000
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)