/* * This is the callback from RPC telling us whether a reply was * received or some error occurred (timeout or socket shutdown). */ static void nfs_readpage_result(struct rpc_task *task) { struct nfs_rreq *req = (struct nfs_rreq *) task->tk_calldata; struct page *page = req->ra_page; unsigned long address = page_address(page); int result = task->tk_status; static int succ = 0, fail = 0; dprintk("NFS: %4d received callback for page %lx, result %d\n", task->tk_pid, address, result); if (result >= 0) { result = req->ra_res.count; if (result < PAGE_SIZE) { memset((char *) address + result, 0, PAGE_SIZE - result); } nfs_refresh_inode(req->ra_inode, &req->ra_fattr); set_bit(PG_uptodate, &page->flags); succ++; } else { set_bit(PG_error, &page->flags); fail++; dprintk("NFS: %d successful reads, %d failures\n", succ, fail); } /* N.B. Use nfs_unlock_page here? */ clear_bit(PG_locked, &page->flags); wake_up(&page->wait); free_page(address); rpc_release_task(task); kfree(req); }
struct inode *nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_fattr newfattr; int error; struct inode *inode; if (!sb) { printk("nfs_fhget: super block is NULL\n"); return NULL; } if (!fattr) { error = nfs_proc_getattr(&sb->u.nfs_sb.s_server, fhandle, &newfattr); if (error) { printk("nfs_fhget: getattr error = %d\n", -error); return NULL; } fattr = &newfattr; } if (!(inode = iget(sb, fattr->fileid))) { printk("nfs_fhget: iget failed\n"); return NULL; } if (inode->i_dev == sb->s_dev) { if (inode->i_ino != fattr->fileid) { printk("nfs_fhget: unexpected inode from iget\n"); return inode; } *NFS_FH(inode) = *fhandle; nfs_refresh_inode(inode, fattr); } return inode; }
static int nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr, dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr) { struct nfs_fattr dir_attr; struct nfs3_mknodargs arg = { NFS_FH(dir), name->name, name->len, 0, sattr, rdev }; struct nfs3_diropres res = { &dir_attr, fh, fattr }; int status; switch (sattr->ia_mode & S_IFMT) { case S_IFBLK: arg.type = NF3BLK; break; case S_IFCHR: arg.type = NF3CHR; break; case S_IFIFO: arg.type = NF3FIFO; break; case S_IFSOCK: arg.type = NF3SOCK; break; default: return -EINVAL; } dprintk("NFS call mknod %s %x\n", name->name, rdev); dir_attr.valid = 0; fattr->valid = 0; status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply mknod: %d\n", status); return status; }
/* * The READDIR implementation is somewhat hackish - we pass the user buffer * to the encode function, which installs it in the receive iovec. * The decode function itself doesn't perform any decoding, it just makes * sure the reply is syntactically correct. * * Also note that this implementation handles both plain readdir and * readdirplus. */ static int nfs3_proc_readdir(struct inode *dir, struct rpc_cred *cred, u64 cookie, void *entry, unsigned int size, int plus) { struct nfs_fattr dir_attr; struct nfs3_readdirargs arg = { NFS_FH(dir), cookie, {0, 0}, 0, 0, 0 }; struct nfs3_readdirres res = { &dir_attr, 0, 0, 0, 0 }; struct rpc_message msg = { NFS3PROC_READDIR, &arg, &res, cred }; u32 *verf = NFS_COOKIEVERF(dir); int status; arg.buffer = entry; arg.bufsiz = size; arg.verf[0] = verf[0]; arg.verf[1] = verf[1]; arg.plus = plus; res.buffer = entry; res.bufsiz = size; res.verf = verf; res.plus = plus; if (plus) msg.rpc_proc = NFS3PROC_READDIRPLUS; dprintk("NFS call readdir%s %d\n", plus? "plus" : "", (unsigned int) cookie); dir_attr.valid = 0; status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply readdir: %d\n", status); return status; }
/* * Fill in inode information from the fattr. */ static void nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr) { /* * Check whether the mode has been set, as we only want to * do this once. (We don't allow inodes to change types.) */ if (inode->i_mode == 0) { inode->i_mode = fattr->mode; if (S_ISREG(inode->i_mode)) inode->i_op = &nfs_file_inode_operations; else if (S_ISDIR(inode->i_mode)) inode->i_op = &nfs_dir_inode_operations; else if (S_ISLNK(inode->i_mode)) inode->i_op = &nfs_symlink_inode_operations; else if (S_ISCHR(inode->i_mode)) { inode->i_op = &chrdev_inode_operations; inode->i_rdev = to_kdev_t(fattr->rdev); } else if (S_ISBLK(inode->i_mode)) { inode->i_op = &blkdev_inode_operations; inode->i_rdev = to_kdev_t(fattr->rdev); } else if (S_ISFIFO(inode->i_mode)) init_fifo(inode); else inode->i_op = NULL; /* * Preset the size and mtime, as there's no need * to invalidate the caches. */ inode->i_size = fattr->size; inode->i_mtime = fattr->mtime.seconds; NFS_OLDMTIME(inode) = fattr->mtime.seconds; } nfs_refresh_inode(inode, fattr); }
static inline int nfs_direct_read_rpc(struct file *file, struct nfs_readargs *arg) { int result; struct inode * inode = file->f_dentry->d_inode; struct nfs_fattr fattr; struct rpc_message msg; struct nfs_readres res = { &fattr, arg->count, 0 }; #ifdef CONFIG_NFS_V3 msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_READ : NFSPROC_READ; #else msg.rpc_proc = NFSPROC_READ; #endif msg.rpc_argp = arg; msg.rpc_resp = &res; lock_kernel(); msg.rpc_cred = nfs_file_cred(file); fattr.valid = 0; result = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); nfs_refresh_inode(inode, &fattr); unlock_kernel(); return result; }
static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data) { if (nfs3_async_handle_jukebox(task, data->inode)) return -EAGAIN; nfs_refresh_inode(data->inode, data->res.fattr); return 0; }
static int nfs3_proc_access(struct inode *inode, int mode, int ruid) { struct nfs_fattr fattr; struct nfs3_accessargs arg = { NFS_FH(inode), 0 }; struct nfs3_accessres res = { &fattr, 0 }; int status, flags; dprintk("NFS call access\n"); fattr.valid = 0; if (mode & MAY_READ) arg.access |= NFS3_ACCESS_READ; if (S_ISDIR(inode->i_mode)) { if (mode & MAY_WRITE) arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE; if (mode & MAY_EXEC) arg.access |= NFS3_ACCESS_LOOKUP; } else { if (mode & MAY_WRITE) arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND; if (mode & MAY_EXEC) arg.access |= NFS3_ACCESS_EXECUTE; } flags = (ruid) ? RPC_CALL_REALUID : 0; status = rpc_call(NFS_CLIENT(inode), NFS3PROC_ACCESS, &arg, &res, flags); nfs_refresh_inode(inode, &fattr); dprintk("NFS reply access\n"); if (status == 0 && (arg.access & res.access) != arg.access) status = -EACCES; return status; }
/* * This is called every time the dcache has a lookup hit, * and we should check whether we can really trust that * lookup. * * NOTE! The hit can be a negative hit too, don't assume * we have an inode! * * If the parent directory is seen to have changed, we throw out the * cached dentry and do a new lookup. */ static int nfs_lookup_revalidate(struct dentry * dentry, int flags) { struct inode *dir; struct inode *inode; int error; struct nfs_fh fhandle; struct nfs_fattr fattr; lock_kernel(); dir = dentry->d_parent->d_inode; inode = dentry->d_inode; if (!inode) { if (nfs_neg_need_reval(dir, dentry)) goto out_bad; goto out_valid; } if (is_bad_inode(inode)) { dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n", dentry->d_parent->d_name.name, dentry->d_name.name); goto out_bad; } /* Force a full look up iff the parent directory has changed */ if (nfs_check_verifier(dir, dentry)) { if (nfs_lookup_verify_inode(inode, flags)) goto out_bad; goto out_valid; } if (NFS_STALE(inode)) goto out_bad; error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); if (error) goto out_bad; if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0) goto out_bad; if ((error = nfs_refresh_inode(inode, &fattr)) != 0) goto out_bad; nfs_renew_times(dentry); out_valid: unlock_kernel(); return 1; out_bad: NFS_CACHEINV(dir); if (inode && S_ISDIR(inode->i_mode)) { /* Purge readdir caches. */ nfs_zap_caches(inode); /* If we have submounts, don't unhash ! */ if (have_submounts(dentry)) goto out_valid; shrink_dcache_parent(dentry); } d_drop(dentry); unlock_kernel(); return 0; }
static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, struct posix_acl *dfacl) { struct nfs_server *server = NFS_SERVER(inode); struct nfs_fattr fattr; struct page *pages[NFSACL_MAXPAGES] = { }; struct nfs3_setaclargs args = { .inode = inode, .mask = NFS_ACL, .acl_access = acl, .pages = pages, }; int status, count; status = -EOPNOTSUPP; if (!nfs_server_capable(inode, NFS_CAP_ACLS)) goto out; /* We are doing this here, because XDR marshalling can only return -ENOMEM. */ status = -ENOSPC; if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES) goto out; if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES) goto out; if (S_ISDIR(inode->i_mode)) { args.mask |= NFS_DFACL; args.acl_default = dfacl; } dprintk("NFS call setacl\n"); nfs_begin_data_update(inode); status = rpc_call(server->client_acl, ACLPROC3_SETACL, &args, &fattr, 0); spin_lock(&inode->i_lock); NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS; spin_unlock(&inode->i_lock); nfs_end_data_update(inode); dprintk("NFS reply setacl: %d\n", status); /* pages may have been allocated at the xdr layer. */ for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++) __free_page(args.pages[count]); switch (status) { case 0: status = nfs_refresh_inode(inode, &fattr); break; case -EPFNOSUPPORT: case -EPROTONOSUPPORT: dprintk("NFS_V3_ACL SETACL RPC not supported" "(will not retry)\n"); server->caps &= ~NFS_CAP_ACLS; case -ENOTSUPP: status = -EOPNOTSUPP; } out: return status; }
/* * Read a page synchronously. */ static int nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page) { struct nfs_rreq rqst; unsigned long offset = page->offset; char *buffer = (char *) page_address(page); int rsize = NFS_SERVER(inode)->rsize; int result, refresh = 0; int count = PAGE_SIZE; int flags = IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0; dprintk("NFS: nfs_readpage_sync(%p)\n", page); clear_bit(PG_error, &page->flags); do { if (count < rsize) rsize = count; dprintk("NFS: nfs_proc_read(%s, (%s/%s), %ld, %d, %p)\n", NFS_SERVER(inode)->hostname, dentry->d_parent->d_name.name, dentry->d_name.name, offset, rsize, buffer); /* Set up arguments and perform rpc call */ nfs_readreq_setup(&rqst, NFS_FH(dentry), offset, buffer, rsize); result = rpc_call(NFS_CLIENT(inode), NFSPROC_READ, &rqst.ra_args, &rqst.ra_res, flags); /* * Even if we had a partial success we can't mark the page * cache valid. */ if (result < 0) { if (result == -EISDIR) result = -EINVAL; goto io_error; } refresh = 1; count -= result; offset += result; buffer += result; if (result < rsize) /* NFSv2ism */ break; } while (count); memset(buffer, 0, count); set_bit(PG_uptodate, &page->flags); result = 0; io_error: /* Note: we don't refresh if the call returned error */ if (refresh && result >= 0) nfs_refresh_inode(inode, &rqst.ra_fattr); /* N.B. Use nfs_unlock_page here? */ clear_bit(PG_locked, &page->flags); wake_up(&page->wait); return result; }
static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data) { if (nfs3_async_handle_jukebox(task, data->inode)) return -EAGAIN; nfs_invalidate_atime(data->inode); nfs_refresh_inode(data->inode, &data->fattr); return 0; }
static int nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) { struct nfs_fattr dir_attr, fattr; struct nfs3_linkargs arg = { NFS_FH(inode), NFS_FH(dir), name->name, name->len }; struct nfs3_linkres res = { &dir_attr, &fattr }; int status; dprintk("NFS call link %s\n", name->name); dir_attr.valid = 0; fattr.valid = 0; status = rpc_call(NFS_CLIENT(inode), NFS3PROC_LINK, &arg, &res, 0); nfs_refresh_inode(dir, &dir_attr); nfs_refresh_inode(inode, &fattr); dprintk("NFS reply link: %d\n", status); return status; }
/* * This is the callback from nfsiod telling us whether a reply was * received or some error occurred (timeout or socket shutdown). */ static int nfsiod_read_result(int result, struct nfsiod_req *req) { struct nfs_server *server = NFS_SERVER(req->rq_inode); struct page *page = req->rq_page; static int succ = 0, fail = 0; int i; dprintk("BIO: received callback for page %p, result %d\n", page, result); if (result >= 0) { struct nfs_fattr fattr; result = nfs_proc_read_reply(&req->rq_rpcreq, &fattr); if (result >= 0) { nfs_refresh_inode(req->rq_inode, &fattr); if (result < PAGE_SIZE) memset((u8 *) page_address(page)+result, 0, PAGE_SIZE-result); } } else if (result == -ETIMEDOUT && !(server->flags & NFS_MOUNT_SOFT)) { /* XXX: Theoretically, we'd have to increment the initial * timeo here; but I'm not going to bother with this now * because this old nfsiod stuff will soon die anyway. */ result = -EAGAIN; } if (result == -EAGAIN && req->rq_retries--) { dprintk("BIO: retransmitting request.\n"); memset(&req->rq_rpcreq, 0, sizeof(struct rpc_ioreq)); while (rpc_reserve(server->rsock, &req->rq_rpcreq, 1) < 0) schedule(); current->fsuid = req->rq_fsuid; current->fsgid = req->rq_fsgid; for (i = 0; i < NGROUPS; i++) current->groups[i] = req->rq_groups[i]; nfsiod_read_setup(req); return 0; } if (result >= 0) { set_bit(PG_uptodate, &page->flags); succ++; } else { dprintk("BIO: %d successful reads, %d failures\n", succ, fail); set_bit(PG_error, &page->flags); fail++; } clear_bit(PG_locked, &page->flags); wake_up(&page->wait); free_page(page_address(page)); return 1; }
/* * This function will be used to simulate weak cache consistency * under NFSv2 when the NFSv3 attribute patch is included. * For the moment, we just call nfs_refresh_inode(). */ static __inline__ int nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr) { if ((fattr->valid & NFS_ATTR_FATTR) && !(fattr->valid & NFS_ATTR_WCC)) { fattr->pre_size = NFS_CACHE_ISIZE(inode); fattr->pre_mtime = NFS_CACHE_MTIME(inode); fattr->pre_ctime = NFS_CACHE_CTIME(inode); fattr->valid |= NFS_ATTR_WCC; } return nfs_refresh_inode(inode, fattr); }
static void nfs3_proc_unlink_done(struct dentry *dir, struct rpc_message *msg) { struct nfs_fattr *dir_attr; if (msg->rpc_argp) { dir_attr = (struct nfs_fattr*)msg->rpc_resp; nfs_refresh_inode(dir->d_inode, dir_attr); kfree(msg->rpc_argp); } }
static int nfs3_commit_done(struct rpc_task *task, struct nfs_commit_data *data) { zql_control_test(NFS_SERVER(data->inode)); if (data->commit_done_cb != NULL) return data->commit_done_cb(task, data); if (nfs3_async_handle_jukebox(task, data->inode)) return -EAGAIN; nfs_refresh_inode(data->inode, data->res.fattr); return 0; }
static int nfs3_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr) { struct inode *inode = hdr->inode; if (nfs3_async_handle_jukebox(task, inode)) return -EAGAIN; nfs_invalidate_atime(inode); nfs_refresh_inode(inode, &hdr->fattr); return 0; }
static int nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, struct inode *new_dir, struct qstr *new_name) { struct nfs_fattr old_dir_attr, new_dir_attr; struct nfs3_renameargs arg = { NFS_FH(old_dir), old_name->name, old_name->len, NFS_FH(new_dir), new_name->name, new_name->len }; struct nfs3_renameres res = { &old_dir_attr, &new_dir_attr }; int status; dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); old_dir_attr.valid = 0; new_dir_attr.valid = 0; status = rpc_call(NFS_CLIENT(old_dir), NFS3PROC_RENAME, &arg, &res, 0); nfs_refresh_inode(old_dir, &old_dir_attr); nfs_refresh_inode(new_dir, &new_dir_attr); dprintk("NFS reply rename: %d\n", status); return status; }
static int nfs3_proc_rmdir(struct inode *dir, struct qstr *name) { struct nfs_fattr dir_attr; struct nfs3_diropargs arg = { NFS_FH(dir), name->name, name->len }; int status; dprintk("NFS call rmdir %s\n", name->name); dir_attr.valid = 0; status = rpc_call(NFS_CLIENT(dir), NFS3PROC_RMDIR, &arg, &dir_attr, 0); nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply rmdir: %d\n", status); return status; }
static int nfs_file_write(struct inode *inode, struct file *file, char *buf, int count) { int result; int hunk; int i; int n; struct nfs_fattr fattr; char *data; int pos; if (!inode) { printk("nfs_file_write: inode = NULL\n"); return -EINVAL; } if (!S_ISREG(inode->i_mode)) { printk("nfs_file_write: write to non-file, mode %07o\n", inode->i_mode); return -EINVAL; } if (count <= 0) return 0; pos = file->f_pos; if (file->f_flags & O_APPEND) pos = inode->i_size; n = NFS_SERVER(inode)->wsize; data = (char *) kmalloc(n, GFP_KERNEL); for (i = 0; i < count; i += n) { hunk = count - i; if (hunk >= n) hunk = n; memcpy_fromfs(data, buf, hunk); result = nfs_proc_write(NFS_SERVER(inode), NFS_FH(inode), pos, hunk, data, &fattr); if (result < 0) { kfree_s(data, n); return result; } pos += hunk; buf += hunk; if (hunk < n) { i += hunk; break; } } file->f_pos = pos; kfree_s(data, n); nfs_refresh_inode(inode, &fattr); return i; }
static int nfs_file_read(struct inode *inode, struct file *file, char *buf, int count) { int result; int hunk; int i; int n; struct nfs_fattr fattr; char *data; off_t pos; if (!inode) { printk("nfs_file_read: inode = NULL\n"); return -EINVAL; } if (!S_ISREG(inode->i_mode)) { printk("nfs_file_read: read from non-file, mode %07o\n", inode->i_mode); return -EINVAL; } pos = file->f_pos; if (file->f_pos + count > inode->i_size) count = inode->i_size - pos; if (count <= 0) return 0; n = NFS_SERVER(inode)->rsize; data = (char *) kmalloc(n, GFP_KERNEL); for (i = 0; i < count; i += n) { hunk = count - i; if (hunk > n) hunk = n; result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode), pos, hunk, data, &fattr); if (result < 0) { kfree_s(data, n); return result; } memcpy_tofs(buf, data, result); pos += result; buf += result; if (result < n) { i += result; break; } } file->f_pos = pos; kfree_s(data, n); nfs_refresh_inode(inode, &fattr); return i; }
static inline int do_read_nfs_sync(struct inode * inode, struct page * page) { struct nfs_fattr fattr; int result, refresh = 0; int count = PAGE_SIZE; int rsize = NFS_SERVER(inode)->rsize; char *buf = (char *) page_address(page); unsigned long pos = page->offset; dprintk("NFS: do_read_nfs_sync(%p)\n", page); set_bit(PG_locked, &page->flags); clear_bit(PG_error, &page->flags); do { if (count < rsize) rsize = count; result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode), pos, rsize, buf, &fattr); dprintk("nfs_proc_read(%s, (%x,%lx), %ld, %d, %p) = %d\n", NFS_SERVER(inode)->hostname, inode->i_dev, inode->i_ino, pos, rsize, buf, result); /* * Even if we had a partial success we can't mark the page * cache valid. */ if (result < 0) goto io_error; refresh = 1; count -= result; pos += result; buf += result; if (result < rsize) break; } while (count); memset(buf, 0, count); set_bit(PG_uptodate, &page->flags); result = 0; io_error: if (refresh) nfs_refresh_inode(inode, &fattr); clear_bit(PG_locked, &page->flags); wake_up(&page->wait); return result; }
static int nfs3_proc_remove(struct inode *dir, struct qstr *name) { struct nfs_fattr dir_attr; struct nfs3_diropargs arg = { NFS_FH(dir), name->name, name->len }; struct rpc_message msg = { NFS3PROC_REMOVE, &arg, &dir_attr, NULL }; int status; dprintk("NFS call remove %s\n", name->name); dir_attr.valid = 0; status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply remove: %d\n", status); return status; }
static int nfs3_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr) { struct inode *inode = hdr->inode; zql_control_test(NFS_SERVER(inode)); if (hdr->pgio_done_cb != NULL) return hdr->pgio_done_cb(task, hdr); if (nfs3_async_handle_jukebox(task, inode)) return -EAGAIN; nfs_invalidate_atime(inode); nfs_refresh_inode(inode, &hdr->fattr); return 0; }
/* * Fill in the supplied page for mmap */ static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area, unsigned long address, unsigned long page, int no_share) { struct inode * inode = area->vm_inode; unsigned int clear; unsigned long tmp; int n; int i; int pos; struct nfs_fattr fattr; address &= PAGE_MASK; pos = address - area->vm_start + area->vm_offset; clear = 0; if (address + PAGE_SIZE > area->vm_end) { clear = address + PAGE_SIZE - area->vm_end; } n = NFS_SERVER(inode)->rsize; /* what we can read in one go */ for (i = 0; i < (PAGE_SIZE - clear); i += n) { int hunk, result; hunk = PAGE_SIZE - i; if (hunk > n) hunk = n; result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode), pos, hunk, (char *) (page + i), &fattr, 0); if (result < 0) break; pos += result; if (result < n) { i += result; break; } } #ifdef doweneedthishere nfs_refresh_inode(inode, &fattr); #endif tmp = page + PAGE_SIZE; while (clear--) { *(char *)--tmp = 0; } return page; }
static int nfs3_proc_readlink(struct inode *inode, void *buffer, unsigned int buflen) { struct nfs_fattr fattr; struct nfs3_readlinkargs args = { NFS_FH(inode), buffer, buflen }; struct nfs3_readlinkres res = { &fattr, buffer, buflen }; int status; dprintk("NFS call readlink\n"); fattr.valid = 0; status = rpc_call(NFS_CLIENT(inode), NFS3PROC_READLINK, &args, &res, 0); nfs_refresh_inode(inode, &fattr); dprintk("NFS reply readlink: %d\n", status); return status; }
static int nfs3_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_fattr dir_attr; struct nfs3_mkdirargs arg = { NFS_FH(dir), name->name, name->len, sattr }; struct nfs3_diropres res = { &dir_attr, fhandle, fattr }; int status; dprintk("NFS call mkdir %s\n", name->name); dir_attr.valid = 0; fattr->valid = 0; status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply mkdir: %d\n", status); return status; }
static int nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_fattr dir_attr; struct nfs3_symlinkargs arg = { NFS_FH(dir), name->name, name->len, path->name, path->len, sattr }; struct nfs3_diropres res = { &dir_attr, fhandle, fattr }; int status; dprintk("NFS call symlink %s -> %s\n", name->name, path->name); dir_attr.valid = 0; fattr->valid = 0; status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SYMLINK, &arg, &res, 0); nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply symlink: %d\n", status); return status; }
static inline void revalidate_dir(struct nfs_server * server, struct inode * dir) { struct nfs_fattr fattr; if (jiffies - NFS_READTIME(dir) < NFS_ATTRTIMEO(dir)) return; NFS_READTIME(dir) = jiffies; if (nfs_proc_getattr(server, NFS_FH(dir), &fattr) == 0) { nfs_refresh_inode(dir, &fattr); if (fattr.mtime.seconds == NFS_OLDMTIME(dir)) { if ((NFS_ATTRTIMEO(dir) <<= 1) > server->acdirmax) NFS_ATTRTIMEO(dir) = server->acdirmax; return; } NFS_OLDMTIME(dir) = fattr.mtime.seconds; } /* invalidate directory cache here when we _really_ start caching */ }