static inline int nfs_direct_write_rpc(struct file *file, struct nfs_writeargs *arg, struct nfs_writeverf *verf) { int result; struct inode *inode = file->f_dentry->d_inode; struct nfs_fattr fattr; struct rpc_message msg; struct nfs_writeres res = { &fattr, verf, 0 }; #ifdef CONFIG_NFS_V3 msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_WRITE : NFSPROC_WRITE; #else msg.rpc_proc = NFSPROC_WRITE; #endif msg.rpc_argp = arg; msg.rpc_resp = &res; lock_kernel(); msg.rpc_cred = get_rpccred(nfs_file_cred(file)); fattr.valid = 0; result = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); nfs_write_attributes(inode, &fattr); put_rpccred(msg.rpc_cred); unlock_kernel(); #ifdef CONFIG_NFS_V3 if (NFS_PROTO(inode)->version == 3) { if (result > 0) { if ((arg->stable == NFS_FILE_SYNC) && (verf->committed != NFS_FILE_SYNC)) { printk(KERN_ERR "%s: server didn't sync stable write request\n", __FUNCTION__); return -EIO; } if (result != arg->count) { printk(KERN_INFO "%s: short write, count=%u, result=%d\n", __FUNCTION__, arg->count, result); } } return result; } else { #endif verf->committed = NFS_FILE_SYNC; /* NFSv2 always syncs data */ if (result == 0) return arg->count; return result; #ifdef CONFIG_NFS_V3 } #endif }
static inline int nfs_direct_commit_rpc(struct inode *inode, loff_t offset, size_t count, struct nfs_writeverf *verf) { int result; struct nfs_fattr fattr; struct nfs_writeargs arg = { NFS_FH(inode), offset, count, 0, 0, NULL }; struct nfs_writeres res = { &fattr, verf, 0 }; struct rpc_message msg = { NFS3PROC_COMMIT, &arg, &res, NULL }; fattr.valid = 0; lock_kernel(); result = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); nfs_write_attributes(inode, &fattr); unlock_kernel(); return result; }
/* * Write a page synchronously. * Offset is the data offset within the page. */ static int nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page, unsigned int offset, unsigned int count) { struct rpc_cred *cred = NULL; loff_t base; unsigned int wsize = NFS_SERVER(inode)->wsize; int result, refresh = 0, written = 0, flags; u8 *buffer; struct nfs_fattr fattr; struct nfs_writeverf verf; if (file) cred = get_rpccred(nfs_file_cred(file)); if (!cred) cred = get_rpccred(NFS_I(inode)->mm_cred); 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; base = page_offset(page) + offset; flags = ((IS_SWAPFILE(inode)) ? NFS_RW_SWAP : 0) | NFS_RW_SYNC; do { if (count < wsize && !IS_SWAPFILE(inode)) wsize = count; result = NFS_PROTO(inode)->write(inode, cred, &fattr, flags, base, wsize, buffer, &verf); nfs_write_attributes(inode, &fattr); if (result < 0) { /* Must mark the page invalid after I/O error */ ClearPageUptodate(page); goto io_error; } if (result != wsize) printk("NFS: short write, wsize=%u, result=%d\n", wsize, result); refresh = 1; buffer += wsize; base += wsize; written += wsize; count -= wsize; /* * If we've extended the file, update the inode * now so we don't invalidate the cache. */ if (base > inode->i_size) inode->i_size = base; } while (count); if (PageError(page)) ClearPageError(page); io_error: kunmap(page); if (cred) put_rpccred(cred); return written? written : result; }