162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/nfs/nfs3proc.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Client-side NFSv3 procedures stubs. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 1997, Olaf Kirch 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/mm.h> 1162306a36Sopenharmony_ci#include <linux/errno.h> 1262306a36Sopenharmony_ci#include <linux/string.h> 1362306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/nfs.h> 1662306a36Sopenharmony_ci#include <linux/nfs3.h> 1762306a36Sopenharmony_ci#include <linux/nfs_fs.h> 1862306a36Sopenharmony_ci#include <linux/nfs_page.h> 1962306a36Sopenharmony_ci#include <linux/lockd/bind.h> 2062306a36Sopenharmony_ci#include <linux/nfs_mount.h> 2162306a36Sopenharmony_ci#include <linux/freezer.h> 2262306a36Sopenharmony_ci#include <linux/xattr.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "iostat.h" 2562306a36Sopenharmony_ci#include "internal.h" 2662306a36Sopenharmony_ci#include "nfs3_fs.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define NFSDBG_FACILITY NFSDBG_PROC 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* A wrapper to handle the EJUKEBOX error messages */ 3162306a36Sopenharmony_cistatic int 3262306a36Sopenharmony_cinfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci int res; 3562306a36Sopenharmony_ci do { 3662306a36Sopenharmony_ci res = rpc_call_sync(clnt, msg, flags); 3762306a36Sopenharmony_ci if (res != -EJUKEBOX) 3862306a36Sopenharmony_ci break; 3962306a36Sopenharmony_ci __set_current_state(TASK_KILLABLE|TASK_FREEZABLE_UNSAFE); 4062306a36Sopenharmony_ci schedule_timeout(NFS_JUKEBOX_RETRY_TIME); 4162306a36Sopenharmony_ci res = -ERESTARTSYS; 4262306a36Sopenharmony_ci } while (!fatal_signal_pending(current)); 4362306a36Sopenharmony_ci return res; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define rpc_call_sync(clnt, msg, flags) nfs3_rpc_wrapper(clnt, msg, flags) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic int 4962306a36Sopenharmony_cinfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci if (task->tk_status != -EJUKEBOX) 5262306a36Sopenharmony_ci return 0; 5362306a36Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_DELAY); 5462306a36Sopenharmony_ci task->tk_status = 0; 5562306a36Sopenharmony_ci rpc_restart_call(task); 5662306a36Sopenharmony_ci rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); 5762306a36Sopenharmony_ci return 1; 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic int 6162306a36Sopenharmony_cido_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle, 6262306a36Sopenharmony_ci struct nfs_fsinfo *info) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct rpc_message msg = { 6562306a36Sopenharmony_ci .rpc_proc = &nfs3_procedures[NFS3PROC_FSINFO], 6662306a36Sopenharmony_ci .rpc_argp = fhandle, 6762306a36Sopenharmony_ci .rpc_resp = info, 6862306a36Sopenharmony_ci }; 6962306a36Sopenharmony_ci int status; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci dprintk("%s: call fsinfo\n", __func__); 7262306a36Sopenharmony_ci nfs_fattr_init(info->fattr); 7362306a36Sopenharmony_ci status = rpc_call_sync(client, &msg, 0); 7462306a36Sopenharmony_ci dprintk("%s: reply fsinfo: %d\n", __func__, status); 7562306a36Sopenharmony_ci if (status == 0 && !(info->fattr->valid & NFS_ATTR_FATTR)) { 7662306a36Sopenharmony_ci msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; 7762306a36Sopenharmony_ci msg.rpc_resp = info->fattr; 7862306a36Sopenharmony_ci status = rpc_call_sync(client, &msg, 0); 7962306a36Sopenharmony_ci dprintk("%s: reply getattr: %d\n", __func__, status); 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci return status; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* 8562306a36Sopenharmony_ci * Bare-bones access to getattr: this is for nfs_get_root/nfs_get_sb 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_cistatic int 8862306a36Sopenharmony_cinfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, 8962306a36Sopenharmony_ci struct nfs_fsinfo *info) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci int status; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci status = do_proc_get_root(server->client, fhandle, info); 9462306a36Sopenharmony_ci if (status && server->nfs_client->cl_rpcclient != server->client) 9562306a36Sopenharmony_ci status = do_proc_get_root(server->nfs_client->cl_rpcclient, fhandle, info); 9662306a36Sopenharmony_ci return status; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* 10062306a36Sopenharmony_ci * One function for each procedure in the NFS protocol. 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_cistatic int 10362306a36Sopenharmony_cinfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, 10462306a36Sopenharmony_ci struct nfs_fattr *fattr, struct inode *inode) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct rpc_message msg = { 10762306a36Sopenharmony_ci .rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR], 10862306a36Sopenharmony_ci .rpc_argp = fhandle, 10962306a36Sopenharmony_ci .rpc_resp = fattr, 11062306a36Sopenharmony_ci }; 11162306a36Sopenharmony_ci int status; 11262306a36Sopenharmony_ci unsigned short task_flags = 0; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* Is this is an attribute revalidation, subject to softreval? */ 11562306a36Sopenharmony_ci if (inode && (server->flags & NFS_MOUNT_SOFTREVAL)) 11662306a36Sopenharmony_ci task_flags |= RPC_TASK_TIMEOUT; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci dprintk("NFS call getattr\n"); 11962306a36Sopenharmony_ci nfs_fattr_init(fattr); 12062306a36Sopenharmony_ci status = rpc_call_sync(server->client, &msg, task_flags); 12162306a36Sopenharmony_ci dprintk("NFS reply getattr: %d\n", status); 12262306a36Sopenharmony_ci return status; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic int 12662306a36Sopenharmony_cinfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, 12762306a36Sopenharmony_ci struct iattr *sattr) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 13062306a36Sopenharmony_ci struct nfs3_sattrargs arg = { 13162306a36Sopenharmony_ci .fh = NFS_FH(inode), 13262306a36Sopenharmony_ci .sattr = sattr, 13362306a36Sopenharmony_ci }; 13462306a36Sopenharmony_ci struct rpc_message msg = { 13562306a36Sopenharmony_ci .rpc_proc = &nfs3_procedures[NFS3PROC_SETATTR], 13662306a36Sopenharmony_ci .rpc_argp = &arg, 13762306a36Sopenharmony_ci .rpc_resp = fattr, 13862306a36Sopenharmony_ci }; 13962306a36Sopenharmony_ci int status; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci dprintk("NFS call setattr\n"); 14262306a36Sopenharmony_ci if (sattr->ia_valid & ATTR_FILE) 14362306a36Sopenharmony_ci msg.rpc_cred = nfs_file_cred(sattr->ia_file); 14462306a36Sopenharmony_ci nfs_fattr_init(fattr); 14562306a36Sopenharmony_ci status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); 14662306a36Sopenharmony_ci if (status == 0) { 14762306a36Sopenharmony_ci nfs_setattr_update_inode(inode, sattr, fattr); 14862306a36Sopenharmony_ci if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) 14962306a36Sopenharmony_ci nfs_zap_acl_cache(inode); 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci dprintk("NFS reply setattr: %d\n", status); 15262306a36Sopenharmony_ci return status; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int 15662306a36Sopenharmony_ci__nfs3_proc_lookup(struct inode *dir, const char *name, size_t len, 15762306a36Sopenharmony_ci struct nfs_fh *fhandle, struct nfs_fattr *fattr, 15862306a36Sopenharmony_ci unsigned short task_flags) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct nfs3_diropargs arg = { 16162306a36Sopenharmony_ci .fh = NFS_FH(dir), 16262306a36Sopenharmony_ci .name = name, 16362306a36Sopenharmony_ci .len = len 16462306a36Sopenharmony_ci }; 16562306a36Sopenharmony_ci struct nfs3_diropres res = { 16662306a36Sopenharmony_ci .fh = fhandle, 16762306a36Sopenharmony_ci .fattr = fattr 16862306a36Sopenharmony_ci }; 16962306a36Sopenharmony_ci struct rpc_message msg = { 17062306a36Sopenharmony_ci .rpc_proc = &nfs3_procedures[NFS3PROC_LOOKUP], 17162306a36Sopenharmony_ci .rpc_argp = &arg, 17262306a36Sopenharmony_ci .rpc_resp = &res, 17362306a36Sopenharmony_ci }; 17462306a36Sopenharmony_ci int status; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci res.dir_attr = nfs_alloc_fattr(); 17762306a36Sopenharmony_ci if (res.dir_attr == NULL) 17862306a36Sopenharmony_ci return -ENOMEM; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci nfs_fattr_init(fattr); 18162306a36Sopenharmony_ci status = rpc_call_sync(NFS_CLIENT(dir), &msg, task_flags); 18262306a36Sopenharmony_ci nfs_refresh_inode(dir, res.dir_attr); 18362306a36Sopenharmony_ci if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) { 18462306a36Sopenharmony_ci msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; 18562306a36Sopenharmony_ci msg.rpc_argp = fhandle; 18662306a36Sopenharmony_ci msg.rpc_resp = fattr; 18762306a36Sopenharmony_ci status = rpc_call_sync(NFS_CLIENT(dir), &msg, task_flags); 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci nfs_free_fattr(res.dir_attr); 19062306a36Sopenharmony_ci dprintk("NFS reply lookup: %d\n", status); 19162306a36Sopenharmony_ci return status; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int 19562306a36Sopenharmony_cinfs3_proc_lookup(struct inode *dir, struct dentry *dentry, 19662306a36Sopenharmony_ci struct nfs_fh *fhandle, struct nfs_fattr *fattr) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci unsigned short task_flags = 0; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Is this is an attribute revalidation, subject to softreval? */ 20162306a36Sopenharmony_ci if (nfs_lookup_is_soft_revalidate(dentry)) 20262306a36Sopenharmony_ci task_flags |= RPC_TASK_TIMEOUT; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci dprintk("NFS call lookup %pd2\n", dentry); 20562306a36Sopenharmony_ci return __nfs3_proc_lookup(dir, dentry->d_name.name, 20662306a36Sopenharmony_ci dentry->d_name.len, fhandle, fattr, 20762306a36Sopenharmony_ci task_flags); 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic int nfs3_proc_lookupp(struct inode *inode, struct nfs_fh *fhandle, 21162306a36Sopenharmony_ci struct nfs_fattr *fattr) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci const char dotdot[] = ".."; 21462306a36Sopenharmony_ci const size_t len = strlen(dotdot); 21562306a36Sopenharmony_ci unsigned short task_flags = 0; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (NFS_SERVER(inode)->flags & NFS_MOUNT_SOFTREVAL) 21862306a36Sopenharmony_ci task_flags |= RPC_TASK_TIMEOUT; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return __nfs3_proc_lookup(inode, dotdot, len, fhandle, fattr, 22162306a36Sopenharmony_ci task_flags); 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry, 22562306a36Sopenharmony_ci const struct cred *cred) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct nfs3_accessargs arg = { 22862306a36Sopenharmony_ci .fh = NFS_FH(inode), 22962306a36Sopenharmony_ci .access = entry->mask, 23062306a36Sopenharmony_ci }; 23162306a36Sopenharmony_ci struct nfs3_accessres res; 23262306a36Sopenharmony_ci struct rpc_message msg = { 23362306a36Sopenharmony_ci .rpc_proc = &nfs3_procedures[NFS3PROC_ACCESS], 23462306a36Sopenharmony_ci .rpc_argp = &arg, 23562306a36Sopenharmony_ci .rpc_resp = &res, 23662306a36Sopenharmony_ci .rpc_cred = cred, 23762306a36Sopenharmony_ci }; 23862306a36Sopenharmony_ci int status = -ENOMEM; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci dprintk("NFS call access\n"); 24162306a36Sopenharmony_ci res.fattr = nfs_alloc_fattr(); 24262306a36Sopenharmony_ci if (res.fattr == NULL) 24362306a36Sopenharmony_ci goto out; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); 24662306a36Sopenharmony_ci nfs_refresh_inode(inode, res.fattr); 24762306a36Sopenharmony_ci if (status == 0) 24862306a36Sopenharmony_ci nfs_access_set_mask(entry, res.access); 24962306a36Sopenharmony_ci nfs_free_fattr(res.fattr); 25062306a36Sopenharmony_ciout: 25162306a36Sopenharmony_ci dprintk("NFS reply access: %d\n", status); 25262306a36Sopenharmony_ci return status; 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic int nfs3_proc_readlink(struct inode *inode, struct page *page, 25662306a36Sopenharmony_ci unsigned int pgbase, unsigned int pglen) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci struct nfs_fattr *fattr; 25962306a36Sopenharmony_ci struct nfs3_readlinkargs args = { 26062306a36Sopenharmony_ci .fh = NFS_FH(inode), 26162306a36Sopenharmony_ci .pgbase = pgbase, 26262306a36Sopenharmony_ci .pglen = pglen, 26362306a36Sopenharmony_ci .pages = &page 26462306a36Sopenharmony_ci }; 26562306a36Sopenharmony_ci struct rpc_message msg = { 26662306a36Sopenharmony_ci .rpc_proc = &nfs3_procedures[NFS3PROC_READLINK], 26762306a36Sopenharmony_ci .rpc_argp = &args, 26862306a36Sopenharmony_ci }; 26962306a36Sopenharmony_ci int status = -ENOMEM; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci dprintk("NFS call readlink\n"); 27262306a36Sopenharmony_ci fattr = nfs_alloc_fattr(); 27362306a36Sopenharmony_ci if (fattr == NULL) 27462306a36Sopenharmony_ci goto out; 27562306a36Sopenharmony_ci msg.rpc_resp = fattr; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); 27862306a36Sopenharmony_ci nfs_refresh_inode(inode, fattr); 27962306a36Sopenharmony_ci nfs_free_fattr(fattr); 28062306a36Sopenharmony_ciout: 28162306a36Sopenharmony_ci dprintk("NFS reply readlink: %d\n", status); 28262306a36Sopenharmony_ci return status; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistruct nfs3_createdata { 28662306a36Sopenharmony_ci struct rpc_message msg; 28762306a36Sopenharmony_ci union { 28862306a36Sopenharmony_ci struct nfs3_createargs create; 28962306a36Sopenharmony_ci struct nfs3_mkdirargs mkdir; 29062306a36Sopenharmony_ci struct nfs3_symlinkargs symlink; 29162306a36Sopenharmony_ci struct nfs3_mknodargs mknod; 29262306a36Sopenharmony_ci } arg; 29362306a36Sopenharmony_ci struct nfs3_diropres res; 29462306a36Sopenharmony_ci struct nfs_fh fh; 29562306a36Sopenharmony_ci struct nfs_fattr fattr; 29662306a36Sopenharmony_ci struct nfs_fattr dir_attr; 29762306a36Sopenharmony_ci}; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic struct nfs3_createdata *nfs3_alloc_createdata(void) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct nfs3_createdata *data; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 30462306a36Sopenharmony_ci if (data != NULL) { 30562306a36Sopenharmony_ci data->msg.rpc_argp = &data->arg; 30662306a36Sopenharmony_ci data->msg.rpc_resp = &data->res; 30762306a36Sopenharmony_ci data->res.fh = &data->fh; 30862306a36Sopenharmony_ci data->res.fattr = &data->fattr; 30962306a36Sopenharmony_ci data->res.dir_attr = &data->dir_attr; 31062306a36Sopenharmony_ci nfs_fattr_init(data->res.fattr); 31162306a36Sopenharmony_ci nfs_fattr_init(data->res.dir_attr); 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci return data; 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic struct dentry * 31762306a36Sopenharmony_cinfs3_do_create(struct inode *dir, struct dentry *dentry, struct nfs3_createdata *data) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci int status; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0); 32262306a36Sopenharmony_ci nfs_post_op_update_inode(dir, data->res.dir_attr); 32362306a36Sopenharmony_ci if (status != 0) 32462306a36Sopenharmony_ci return ERR_PTR(status); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return nfs_add_or_obtain(dentry, data->res.fh, data->res.fattr); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic void nfs3_free_createdata(struct nfs3_createdata *data) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci kfree(data); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci/* 33562306a36Sopenharmony_ci * Create a regular file. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_cistatic int 33862306a36Sopenharmony_cinfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, 33962306a36Sopenharmony_ci int flags) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct posix_acl *default_acl, *acl; 34262306a36Sopenharmony_ci struct nfs3_createdata *data; 34362306a36Sopenharmony_ci struct dentry *d_alias; 34462306a36Sopenharmony_ci int status = -ENOMEM; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci dprintk("NFS call create %pd\n", dentry); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci data = nfs3_alloc_createdata(); 34962306a36Sopenharmony_ci if (data == NULL) 35062306a36Sopenharmony_ci goto out; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_CREATE]; 35362306a36Sopenharmony_ci data->arg.create.fh = NFS_FH(dir); 35462306a36Sopenharmony_ci data->arg.create.name = dentry->d_name.name; 35562306a36Sopenharmony_ci data->arg.create.len = dentry->d_name.len; 35662306a36Sopenharmony_ci data->arg.create.sattr = sattr; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci data->arg.create.createmode = NFS3_CREATE_UNCHECKED; 35962306a36Sopenharmony_ci if (flags & O_EXCL) { 36062306a36Sopenharmony_ci data->arg.create.createmode = NFS3_CREATE_EXCLUSIVE; 36162306a36Sopenharmony_ci data->arg.create.verifier[0] = cpu_to_be32(jiffies); 36262306a36Sopenharmony_ci data->arg.create.verifier[1] = cpu_to_be32(current->pid); 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl); 36662306a36Sopenharmony_ci if (status) 36762306a36Sopenharmony_ci goto out; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci for (;;) { 37062306a36Sopenharmony_ci d_alias = nfs3_do_create(dir, dentry, data); 37162306a36Sopenharmony_ci status = PTR_ERR_OR_ZERO(d_alias); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (status != -ENOTSUPP) 37462306a36Sopenharmony_ci break; 37562306a36Sopenharmony_ci /* If the server doesn't support the exclusive creation 37662306a36Sopenharmony_ci * semantics, try again with simple 'guarded' mode. */ 37762306a36Sopenharmony_ci switch (data->arg.create.createmode) { 37862306a36Sopenharmony_ci case NFS3_CREATE_EXCLUSIVE: 37962306a36Sopenharmony_ci data->arg.create.createmode = NFS3_CREATE_GUARDED; 38062306a36Sopenharmony_ci break; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci case NFS3_CREATE_GUARDED: 38362306a36Sopenharmony_ci data->arg.create.createmode = NFS3_CREATE_UNCHECKED; 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci case NFS3_CREATE_UNCHECKED: 38762306a36Sopenharmony_ci goto out_release_acls; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci nfs_fattr_init(data->res.dir_attr); 39062306a36Sopenharmony_ci nfs_fattr_init(data->res.fattr); 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (status != 0) 39462306a36Sopenharmony_ci goto out_release_acls; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (d_alias) 39762306a36Sopenharmony_ci dentry = d_alias; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* When we created the file with exclusive semantics, make 40062306a36Sopenharmony_ci * sure we set the attributes afterwards. */ 40162306a36Sopenharmony_ci if (data->arg.create.createmode == NFS3_CREATE_EXCLUSIVE) { 40262306a36Sopenharmony_ci dprintk("NFS call setattr (post-create)\n"); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (!(sattr->ia_valid & ATTR_ATIME_SET)) 40562306a36Sopenharmony_ci sattr->ia_valid |= ATTR_ATIME; 40662306a36Sopenharmony_ci if (!(sattr->ia_valid & ATTR_MTIME_SET)) 40762306a36Sopenharmony_ci sattr->ia_valid |= ATTR_MTIME; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* Note: we could use a guarded setattr here, but I'm 41062306a36Sopenharmony_ci * not sure this buys us anything (and I'd have 41162306a36Sopenharmony_ci * to revamp the NFSv3 XDR code) */ 41262306a36Sopenharmony_ci status = nfs3_proc_setattr(dentry, data->res.fattr, sattr); 41362306a36Sopenharmony_ci nfs_post_op_update_inode(d_inode(dentry), data->res.fattr); 41462306a36Sopenharmony_ci dprintk("NFS reply setattr (post-create): %d\n", status); 41562306a36Sopenharmony_ci if (status != 0) 41662306a36Sopenharmony_ci goto out_dput; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci status = nfs3_proc_setacls(d_inode(dentry), acl, default_acl); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ciout_dput: 42262306a36Sopenharmony_ci dput(d_alias); 42362306a36Sopenharmony_ciout_release_acls: 42462306a36Sopenharmony_ci posix_acl_release(acl); 42562306a36Sopenharmony_ci posix_acl_release(default_acl); 42662306a36Sopenharmony_ciout: 42762306a36Sopenharmony_ci nfs3_free_createdata(data); 42862306a36Sopenharmony_ci dprintk("NFS reply create: %d\n", status); 42962306a36Sopenharmony_ci return status; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic int 43362306a36Sopenharmony_cinfs3_proc_remove(struct inode *dir, struct dentry *dentry) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct nfs_removeargs arg = { 43662306a36Sopenharmony_ci .fh = NFS_FH(dir), 43762306a36Sopenharmony_ci .name = dentry->d_name, 43862306a36Sopenharmony_ci }; 43962306a36Sopenharmony_ci struct nfs_removeres res; 44062306a36Sopenharmony_ci struct rpc_message msg = { 44162306a36Sopenharmony_ci .rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE], 44262306a36Sopenharmony_ci .rpc_argp = &arg, 44362306a36Sopenharmony_ci .rpc_resp = &res, 44462306a36Sopenharmony_ci }; 44562306a36Sopenharmony_ci int status = -ENOMEM; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci dprintk("NFS call remove %pd2\n", dentry); 44862306a36Sopenharmony_ci res.dir_attr = nfs_alloc_fattr(); 44962306a36Sopenharmony_ci if (res.dir_attr == NULL) 45062306a36Sopenharmony_ci goto out; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); 45362306a36Sopenharmony_ci nfs_post_op_update_inode(dir, res.dir_attr); 45462306a36Sopenharmony_ci nfs_free_fattr(res.dir_attr); 45562306a36Sopenharmony_ciout: 45662306a36Sopenharmony_ci dprintk("NFS reply remove: %d\n", status); 45762306a36Sopenharmony_ci return status; 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic void 46162306a36Sopenharmony_cinfs3_proc_unlink_setup(struct rpc_message *msg, 46262306a36Sopenharmony_ci struct dentry *dentry, 46362306a36Sopenharmony_ci struct inode *inode) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE]; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic void nfs3_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci rpc_call_start(task); 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic int 47462306a36Sopenharmony_cinfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct nfs_removeres *res; 47762306a36Sopenharmony_ci if (nfs3_async_handle_jukebox(task, dir)) 47862306a36Sopenharmony_ci return 0; 47962306a36Sopenharmony_ci res = task->tk_msg.rpc_resp; 48062306a36Sopenharmony_ci nfs_post_op_update_inode(dir, res->dir_attr); 48162306a36Sopenharmony_ci return 1; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic void 48562306a36Sopenharmony_cinfs3_proc_rename_setup(struct rpc_message *msg, 48662306a36Sopenharmony_ci struct dentry *old_dentry, 48762306a36Sopenharmony_ci struct dentry *new_dentry) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci msg->rpc_proc = &nfs3_procedures[NFS3PROC_RENAME]; 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic void nfs3_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci rpc_call_start(task); 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic int 49862306a36Sopenharmony_cinfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir, 49962306a36Sopenharmony_ci struct inode *new_dir) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci struct nfs_renameres *res; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (nfs3_async_handle_jukebox(task, old_dir)) 50462306a36Sopenharmony_ci return 0; 50562306a36Sopenharmony_ci res = task->tk_msg.rpc_resp; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci nfs_post_op_update_inode(old_dir, res->old_fattr); 50862306a36Sopenharmony_ci nfs_post_op_update_inode(new_dir, res->new_fattr); 50962306a36Sopenharmony_ci return 1; 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic int 51362306a36Sopenharmony_cinfs3_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci struct nfs3_linkargs arg = { 51662306a36Sopenharmony_ci .fromfh = NFS_FH(inode), 51762306a36Sopenharmony_ci .tofh = NFS_FH(dir), 51862306a36Sopenharmony_ci .toname = name->name, 51962306a36Sopenharmony_ci .tolen = name->len 52062306a36Sopenharmony_ci }; 52162306a36Sopenharmony_ci struct nfs3_linkres res; 52262306a36Sopenharmony_ci struct rpc_message msg = { 52362306a36Sopenharmony_ci .rpc_proc = &nfs3_procedures[NFS3PROC_LINK], 52462306a36Sopenharmony_ci .rpc_argp = &arg, 52562306a36Sopenharmony_ci .rpc_resp = &res, 52662306a36Sopenharmony_ci }; 52762306a36Sopenharmony_ci int status = -ENOMEM; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci dprintk("NFS call link %s\n", name->name); 53062306a36Sopenharmony_ci res.fattr = nfs_alloc_fattr(); 53162306a36Sopenharmony_ci res.dir_attr = nfs_alloc_fattr(); 53262306a36Sopenharmony_ci if (res.fattr == NULL || res.dir_attr == NULL) 53362306a36Sopenharmony_ci goto out; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); 53662306a36Sopenharmony_ci nfs_post_op_update_inode(dir, res.dir_attr); 53762306a36Sopenharmony_ci nfs_post_op_update_inode(inode, res.fattr); 53862306a36Sopenharmony_ciout: 53962306a36Sopenharmony_ci nfs_free_fattr(res.dir_attr); 54062306a36Sopenharmony_ci nfs_free_fattr(res.fattr); 54162306a36Sopenharmony_ci dprintk("NFS reply link: %d\n", status); 54262306a36Sopenharmony_ci return status; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic int 54662306a36Sopenharmony_cinfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, 54762306a36Sopenharmony_ci unsigned int len, struct iattr *sattr) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct nfs3_createdata *data; 55062306a36Sopenharmony_ci struct dentry *d_alias; 55162306a36Sopenharmony_ci int status = -ENOMEM; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (len > NFS3_MAXPATHLEN) 55462306a36Sopenharmony_ci return -ENAMETOOLONG; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci dprintk("NFS call symlink %pd\n", dentry); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci data = nfs3_alloc_createdata(); 55962306a36Sopenharmony_ci if (data == NULL) 56062306a36Sopenharmony_ci goto out; 56162306a36Sopenharmony_ci data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK]; 56262306a36Sopenharmony_ci data->arg.symlink.fromfh = NFS_FH(dir); 56362306a36Sopenharmony_ci data->arg.symlink.fromname = dentry->d_name.name; 56462306a36Sopenharmony_ci data->arg.symlink.fromlen = dentry->d_name.len; 56562306a36Sopenharmony_ci data->arg.symlink.pages = &page; 56662306a36Sopenharmony_ci data->arg.symlink.pathlen = len; 56762306a36Sopenharmony_ci data->arg.symlink.sattr = sattr; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci d_alias = nfs3_do_create(dir, dentry, data); 57062306a36Sopenharmony_ci status = PTR_ERR_OR_ZERO(d_alias); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (status == 0) 57362306a36Sopenharmony_ci dput(d_alias); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci nfs3_free_createdata(data); 57662306a36Sopenharmony_ciout: 57762306a36Sopenharmony_ci dprintk("NFS reply symlink: %d\n", status); 57862306a36Sopenharmony_ci return status; 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cistatic int 58262306a36Sopenharmony_cinfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci struct posix_acl *default_acl, *acl; 58562306a36Sopenharmony_ci struct nfs3_createdata *data; 58662306a36Sopenharmony_ci struct dentry *d_alias; 58762306a36Sopenharmony_ci int status = -ENOMEM; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci dprintk("NFS call mkdir %pd\n", dentry); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci data = nfs3_alloc_createdata(); 59262306a36Sopenharmony_ci if (data == NULL) 59362306a36Sopenharmony_ci goto out; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl); 59662306a36Sopenharmony_ci if (status) 59762306a36Sopenharmony_ci goto out; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR]; 60062306a36Sopenharmony_ci data->arg.mkdir.fh = NFS_FH(dir); 60162306a36Sopenharmony_ci data->arg.mkdir.name = dentry->d_name.name; 60262306a36Sopenharmony_ci data->arg.mkdir.len = dentry->d_name.len; 60362306a36Sopenharmony_ci data->arg.mkdir.sattr = sattr; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci d_alias = nfs3_do_create(dir, dentry, data); 60662306a36Sopenharmony_ci status = PTR_ERR_OR_ZERO(d_alias); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (status != 0) 60962306a36Sopenharmony_ci goto out_release_acls; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (d_alias) 61262306a36Sopenharmony_ci dentry = d_alias; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci status = nfs3_proc_setacls(d_inode(dentry), acl, default_acl); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci dput(d_alias); 61762306a36Sopenharmony_ciout_release_acls: 61862306a36Sopenharmony_ci posix_acl_release(acl); 61962306a36Sopenharmony_ci posix_acl_release(default_acl); 62062306a36Sopenharmony_ciout: 62162306a36Sopenharmony_ci nfs3_free_createdata(data); 62262306a36Sopenharmony_ci dprintk("NFS reply mkdir: %d\n", status); 62362306a36Sopenharmony_ci return status; 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic int 62762306a36Sopenharmony_cinfs3_proc_rmdir(struct inode *dir, const struct qstr *name) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci struct nfs_fattr *dir_attr; 63062306a36Sopenharmony_ci struct nfs3_diropargs arg = { 63162306a36Sopenharmony_ci .fh = NFS_FH(dir), 63262306a36Sopenharmony_ci .name = name->name, 63362306a36Sopenharmony_ci .len = name->len 63462306a36Sopenharmony_ci }; 63562306a36Sopenharmony_ci struct rpc_message msg = { 63662306a36Sopenharmony_ci .rpc_proc = &nfs3_procedures[NFS3PROC_RMDIR], 63762306a36Sopenharmony_ci .rpc_argp = &arg, 63862306a36Sopenharmony_ci }; 63962306a36Sopenharmony_ci int status = -ENOMEM; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci dprintk("NFS call rmdir %s\n", name->name); 64262306a36Sopenharmony_ci dir_attr = nfs_alloc_fattr(); 64362306a36Sopenharmony_ci if (dir_attr == NULL) 64462306a36Sopenharmony_ci goto out; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci msg.rpc_resp = dir_attr; 64762306a36Sopenharmony_ci status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); 64862306a36Sopenharmony_ci nfs_post_op_update_inode(dir, dir_attr); 64962306a36Sopenharmony_ci nfs_free_fattr(dir_attr); 65062306a36Sopenharmony_ciout: 65162306a36Sopenharmony_ci dprintk("NFS reply rmdir: %d\n", status); 65262306a36Sopenharmony_ci return status; 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci/* 65662306a36Sopenharmony_ci * The READDIR implementation is somewhat hackish - we pass the user buffer 65762306a36Sopenharmony_ci * to the encode function, which installs it in the receive iovec. 65862306a36Sopenharmony_ci * The decode function itself doesn't perform any decoding, it just makes 65962306a36Sopenharmony_ci * sure the reply is syntactically correct. 66062306a36Sopenharmony_ci * 66162306a36Sopenharmony_ci * Also note that this implementation handles both plain readdir and 66262306a36Sopenharmony_ci * readdirplus. 66362306a36Sopenharmony_ci */ 66462306a36Sopenharmony_cistatic int nfs3_proc_readdir(struct nfs_readdir_arg *nr_arg, 66562306a36Sopenharmony_ci struct nfs_readdir_res *nr_res) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci struct inode *dir = d_inode(nr_arg->dentry); 66862306a36Sopenharmony_ci struct nfs3_readdirargs arg = { 66962306a36Sopenharmony_ci .fh = NFS_FH(dir), 67062306a36Sopenharmony_ci .cookie = nr_arg->cookie, 67162306a36Sopenharmony_ci .plus = nr_arg->plus, 67262306a36Sopenharmony_ci .count = nr_arg->page_len, 67362306a36Sopenharmony_ci .pages = nr_arg->pages 67462306a36Sopenharmony_ci }; 67562306a36Sopenharmony_ci struct nfs3_readdirres res = { 67662306a36Sopenharmony_ci .verf = nr_res->verf, 67762306a36Sopenharmony_ci .plus = nr_arg->plus, 67862306a36Sopenharmony_ci }; 67962306a36Sopenharmony_ci struct rpc_message msg = { 68062306a36Sopenharmony_ci .rpc_proc = &nfs3_procedures[NFS3PROC_READDIR], 68162306a36Sopenharmony_ci .rpc_argp = &arg, 68262306a36Sopenharmony_ci .rpc_resp = &res, 68362306a36Sopenharmony_ci .rpc_cred = nr_arg->cred, 68462306a36Sopenharmony_ci }; 68562306a36Sopenharmony_ci int status = -ENOMEM; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (nr_arg->plus) 68862306a36Sopenharmony_ci msg.rpc_proc = &nfs3_procedures[NFS3PROC_READDIRPLUS]; 68962306a36Sopenharmony_ci if (arg.cookie) 69062306a36Sopenharmony_ci memcpy(arg.verf, nr_arg->verf, sizeof(arg.verf)); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci dprintk("NFS call readdir%s %llu\n", nr_arg->plus ? "plus" : "", 69362306a36Sopenharmony_ci (unsigned long long)nr_arg->cookie); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci res.dir_attr = nfs_alloc_fattr(); 69662306a36Sopenharmony_ci if (res.dir_attr == NULL) 69762306a36Sopenharmony_ci goto out; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci nfs_invalidate_atime(dir); 70262306a36Sopenharmony_ci nfs_refresh_inode(dir, res.dir_attr); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci nfs_free_fattr(res.dir_attr); 70562306a36Sopenharmony_ciout: 70662306a36Sopenharmony_ci dprintk("NFS reply readdir%s: %d\n", nr_arg->plus ? "plus" : "", 70762306a36Sopenharmony_ci status); 70862306a36Sopenharmony_ci return status; 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic int 71262306a36Sopenharmony_cinfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, 71362306a36Sopenharmony_ci dev_t rdev) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci struct posix_acl *default_acl, *acl; 71662306a36Sopenharmony_ci struct nfs3_createdata *data; 71762306a36Sopenharmony_ci struct dentry *d_alias; 71862306a36Sopenharmony_ci int status = -ENOMEM; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci dprintk("NFS call mknod %pd %u:%u\n", dentry, 72162306a36Sopenharmony_ci MAJOR(rdev), MINOR(rdev)); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci data = nfs3_alloc_createdata(); 72462306a36Sopenharmony_ci if (data == NULL) 72562306a36Sopenharmony_ci goto out; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl); 72862306a36Sopenharmony_ci if (status) 72962306a36Sopenharmony_ci goto out; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD]; 73262306a36Sopenharmony_ci data->arg.mknod.fh = NFS_FH(dir); 73362306a36Sopenharmony_ci data->arg.mknod.name = dentry->d_name.name; 73462306a36Sopenharmony_ci data->arg.mknod.len = dentry->d_name.len; 73562306a36Sopenharmony_ci data->arg.mknod.sattr = sattr; 73662306a36Sopenharmony_ci data->arg.mknod.rdev = rdev; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci switch (sattr->ia_mode & S_IFMT) { 73962306a36Sopenharmony_ci case S_IFBLK: 74062306a36Sopenharmony_ci data->arg.mknod.type = NF3BLK; 74162306a36Sopenharmony_ci break; 74262306a36Sopenharmony_ci case S_IFCHR: 74362306a36Sopenharmony_ci data->arg.mknod.type = NF3CHR; 74462306a36Sopenharmony_ci break; 74562306a36Sopenharmony_ci case S_IFIFO: 74662306a36Sopenharmony_ci data->arg.mknod.type = NF3FIFO; 74762306a36Sopenharmony_ci break; 74862306a36Sopenharmony_ci case S_IFSOCK: 74962306a36Sopenharmony_ci data->arg.mknod.type = NF3SOCK; 75062306a36Sopenharmony_ci break; 75162306a36Sopenharmony_ci default: 75262306a36Sopenharmony_ci status = -EINVAL; 75362306a36Sopenharmony_ci goto out_release_acls; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci d_alias = nfs3_do_create(dir, dentry, data); 75762306a36Sopenharmony_ci status = PTR_ERR_OR_ZERO(d_alias); 75862306a36Sopenharmony_ci if (status != 0) 75962306a36Sopenharmony_ci goto out_release_acls; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (d_alias) 76262306a36Sopenharmony_ci dentry = d_alias; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci status = nfs3_proc_setacls(d_inode(dentry), acl, default_acl); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci dput(d_alias); 76762306a36Sopenharmony_ciout_release_acls: 76862306a36Sopenharmony_ci posix_acl_release(acl); 76962306a36Sopenharmony_ci posix_acl_release(default_acl); 77062306a36Sopenharmony_ciout: 77162306a36Sopenharmony_ci nfs3_free_createdata(data); 77262306a36Sopenharmony_ci dprintk("NFS reply mknod: %d\n", status); 77362306a36Sopenharmony_ci return status; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic int 77762306a36Sopenharmony_cinfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, 77862306a36Sopenharmony_ci struct nfs_fsstat *stat) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci struct rpc_message msg = { 78162306a36Sopenharmony_ci .rpc_proc = &nfs3_procedures[NFS3PROC_FSSTAT], 78262306a36Sopenharmony_ci .rpc_argp = fhandle, 78362306a36Sopenharmony_ci .rpc_resp = stat, 78462306a36Sopenharmony_ci }; 78562306a36Sopenharmony_ci int status; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci dprintk("NFS call fsstat\n"); 78862306a36Sopenharmony_ci nfs_fattr_init(stat->fattr); 78962306a36Sopenharmony_ci status = rpc_call_sync(server->client, &msg, 0); 79062306a36Sopenharmony_ci dprintk("NFS reply fsstat: %d\n", status); 79162306a36Sopenharmony_ci return status; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic int 79562306a36Sopenharmony_cido_proc_fsinfo(struct rpc_clnt *client, struct nfs_fh *fhandle, 79662306a36Sopenharmony_ci struct nfs_fsinfo *info) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci struct rpc_message msg = { 79962306a36Sopenharmony_ci .rpc_proc = &nfs3_procedures[NFS3PROC_FSINFO], 80062306a36Sopenharmony_ci .rpc_argp = fhandle, 80162306a36Sopenharmony_ci .rpc_resp = info, 80262306a36Sopenharmony_ci }; 80362306a36Sopenharmony_ci int status; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci dprintk("NFS call fsinfo\n"); 80662306a36Sopenharmony_ci nfs_fattr_init(info->fattr); 80762306a36Sopenharmony_ci status = rpc_call_sync(client, &msg, 0); 80862306a36Sopenharmony_ci dprintk("NFS reply fsinfo: %d\n", status); 80962306a36Sopenharmony_ci return status; 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci/* 81362306a36Sopenharmony_ci * Bare-bones access to fsinfo: this is for nfs_get_root/nfs_get_sb via 81462306a36Sopenharmony_ci * nfs_create_server 81562306a36Sopenharmony_ci */ 81662306a36Sopenharmony_cistatic int 81762306a36Sopenharmony_cinfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, 81862306a36Sopenharmony_ci struct nfs_fsinfo *info) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci int status; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci status = do_proc_fsinfo(server->client, fhandle, info); 82362306a36Sopenharmony_ci if (status && server->nfs_client->cl_rpcclient != server->client) 82462306a36Sopenharmony_ci status = do_proc_fsinfo(server->nfs_client->cl_rpcclient, fhandle, info); 82562306a36Sopenharmony_ci return status; 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cistatic int 82962306a36Sopenharmony_cinfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, 83062306a36Sopenharmony_ci struct nfs_pathconf *info) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci struct rpc_message msg = { 83362306a36Sopenharmony_ci .rpc_proc = &nfs3_procedures[NFS3PROC_PATHCONF], 83462306a36Sopenharmony_ci .rpc_argp = fhandle, 83562306a36Sopenharmony_ci .rpc_resp = info, 83662306a36Sopenharmony_ci }; 83762306a36Sopenharmony_ci int status; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci dprintk("NFS call pathconf\n"); 84062306a36Sopenharmony_ci nfs_fattr_init(info->fattr); 84162306a36Sopenharmony_ci status = rpc_call_sync(server->client, &msg, 0); 84262306a36Sopenharmony_ci dprintk("NFS reply pathconf: %d\n", status); 84362306a36Sopenharmony_ci return status; 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic int nfs3_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci struct inode *inode = hdr->inode; 84962306a36Sopenharmony_ci struct nfs_server *server = NFS_SERVER(inode); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci if (hdr->pgio_done_cb != NULL) 85262306a36Sopenharmony_ci return hdr->pgio_done_cb(task, hdr); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (nfs3_async_handle_jukebox(task, inode)) 85562306a36Sopenharmony_ci return -EAGAIN; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci if (task->tk_status >= 0 && !server->read_hdrsize) 85862306a36Sopenharmony_ci cmpxchg(&server->read_hdrsize, 0, hdr->res.replen); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci nfs_invalidate_atime(inode); 86162306a36Sopenharmony_ci nfs_refresh_inode(inode, &hdr->fattr); 86262306a36Sopenharmony_ci return 0; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic void nfs3_proc_read_setup(struct nfs_pgio_header *hdr, 86662306a36Sopenharmony_ci struct rpc_message *msg) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ]; 86962306a36Sopenharmony_ci hdr->args.replen = NFS_SERVER(hdr->inode)->read_hdrsize; 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_cistatic int nfs3_proc_pgio_rpc_prepare(struct rpc_task *task, 87362306a36Sopenharmony_ci struct nfs_pgio_header *hdr) 87462306a36Sopenharmony_ci{ 87562306a36Sopenharmony_ci rpc_call_start(task); 87662306a36Sopenharmony_ci return 0; 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_cistatic int nfs3_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci struct inode *inode = hdr->inode; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci if (hdr->pgio_done_cb != NULL) 88462306a36Sopenharmony_ci return hdr->pgio_done_cb(task, hdr); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (nfs3_async_handle_jukebox(task, inode)) 88762306a36Sopenharmony_ci return -EAGAIN; 88862306a36Sopenharmony_ci if (task->tk_status >= 0) 88962306a36Sopenharmony_ci nfs_writeback_update_inode(hdr); 89062306a36Sopenharmony_ci return 0; 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_cistatic void nfs3_proc_write_setup(struct nfs_pgio_header *hdr, 89462306a36Sopenharmony_ci struct rpc_message *msg, 89562306a36Sopenharmony_ci struct rpc_clnt **clnt) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE]; 89862306a36Sopenharmony_ci} 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_cistatic void nfs3_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci rpc_call_start(task); 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_cistatic int nfs3_commit_done(struct rpc_task *task, struct nfs_commit_data *data) 90662306a36Sopenharmony_ci{ 90762306a36Sopenharmony_ci if (data->commit_done_cb != NULL) 90862306a36Sopenharmony_ci return data->commit_done_cb(task, data); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci if (nfs3_async_handle_jukebox(task, data->inode)) 91162306a36Sopenharmony_ci return -EAGAIN; 91262306a36Sopenharmony_ci nfs_refresh_inode(data->inode, data->res.fattr); 91362306a36Sopenharmony_ci return 0; 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cistatic void nfs3_proc_commit_setup(struct nfs_commit_data *data, struct rpc_message *msg, 91762306a36Sopenharmony_ci struct rpc_clnt **clnt) 91862306a36Sopenharmony_ci{ 91962306a36Sopenharmony_ci msg->rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT]; 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_cistatic void nfs3_nlm_alloc_call(void *data) 92362306a36Sopenharmony_ci{ 92462306a36Sopenharmony_ci struct nfs_lock_context *l_ctx = data; 92562306a36Sopenharmony_ci if (l_ctx && test_bit(NFS_CONTEXT_UNLOCK, &l_ctx->open_context->flags)) { 92662306a36Sopenharmony_ci get_nfs_open_context(l_ctx->open_context); 92762306a36Sopenharmony_ci nfs_get_lock_context(l_ctx->open_context); 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_cistatic bool nfs3_nlm_unlock_prepare(struct rpc_task *task, void *data) 93262306a36Sopenharmony_ci{ 93362306a36Sopenharmony_ci struct nfs_lock_context *l_ctx = data; 93462306a36Sopenharmony_ci if (l_ctx && test_bit(NFS_CONTEXT_UNLOCK, &l_ctx->open_context->flags)) 93562306a36Sopenharmony_ci return nfs_async_iocounter_wait(task, l_ctx); 93662306a36Sopenharmony_ci return false; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic void nfs3_nlm_release_call(void *data) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci struct nfs_lock_context *l_ctx = data; 94362306a36Sopenharmony_ci struct nfs_open_context *ctx; 94462306a36Sopenharmony_ci if (l_ctx && test_bit(NFS_CONTEXT_UNLOCK, &l_ctx->open_context->flags)) { 94562306a36Sopenharmony_ci ctx = l_ctx->open_context; 94662306a36Sopenharmony_ci nfs_put_lock_context(l_ctx); 94762306a36Sopenharmony_ci put_nfs_open_context(ctx); 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci} 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_cistatic const struct nlmclnt_operations nlmclnt_fl_close_lock_ops = { 95262306a36Sopenharmony_ci .nlmclnt_alloc_call = nfs3_nlm_alloc_call, 95362306a36Sopenharmony_ci .nlmclnt_unlock_prepare = nfs3_nlm_unlock_prepare, 95462306a36Sopenharmony_ci .nlmclnt_release_call = nfs3_nlm_release_call, 95562306a36Sopenharmony_ci}; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_cistatic int 95862306a36Sopenharmony_cinfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) 95962306a36Sopenharmony_ci{ 96062306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 96162306a36Sopenharmony_ci struct nfs_lock_context *l_ctx = NULL; 96262306a36Sopenharmony_ci struct nfs_open_context *ctx = nfs_file_open_context(filp); 96362306a36Sopenharmony_ci int status; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci if (fl->fl_flags & FL_CLOSE) { 96662306a36Sopenharmony_ci l_ctx = nfs_get_lock_context(ctx); 96762306a36Sopenharmony_ci if (IS_ERR(l_ctx)) 96862306a36Sopenharmony_ci l_ctx = NULL; 96962306a36Sopenharmony_ci else 97062306a36Sopenharmony_ci set_bit(NFS_CONTEXT_UNLOCK, &ctx->flags); 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci status = nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl, l_ctx); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (l_ctx) 97662306a36Sopenharmony_ci nfs_put_lock_context(l_ctx); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci return status; 97962306a36Sopenharmony_ci} 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_cistatic int nfs3_have_delegation(struct inode *inode, fmode_t flags) 98262306a36Sopenharmony_ci{ 98362306a36Sopenharmony_ci return 0; 98462306a36Sopenharmony_ci} 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cistatic const struct inode_operations nfs3_dir_inode_operations = { 98762306a36Sopenharmony_ci .create = nfs_create, 98862306a36Sopenharmony_ci .lookup = nfs_lookup, 98962306a36Sopenharmony_ci .link = nfs_link, 99062306a36Sopenharmony_ci .unlink = nfs_unlink, 99162306a36Sopenharmony_ci .symlink = nfs_symlink, 99262306a36Sopenharmony_ci .mkdir = nfs_mkdir, 99362306a36Sopenharmony_ci .rmdir = nfs_rmdir, 99462306a36Sopenharmony_ci .mknod = nfs_mknod, 99562306a36Sopenharmony_ci .rename = nfs_rename, 99662306a36Sopenharmony_ci .permission = nfs_permission, 99762306a36Sopenharmony_ci .getattr = nfs_getattr, 99862306a36Sopenharmony_ci .setattr = nfs_setattr, 99962306a36Sopenharmony_ci#ifdef CONFIG_NFS_V3_ACL 100062306a36Sopenharmony_ci .listxattr = nfs3_listxattr, 100162306a36Sopenharmony_ci .get_inode_acl = nfs3_get_acl, 100262306a36Sopenharmony_ci .set_acl = nfs3_set_acl, 100362306a36Sopenharmony_ci#endif 100462306a36Sopenharmony_ci}; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_cistatic const struct inode_operations nfs3_file_inode_operations = { 100762306a36Sopenharmony_ci .permission = nfs_permission, 100862306a36Sopenharmony_ci .getattr = nfs_getattr, 100962306a36Sopenharmony_ci .setattr = nfs_setattr, 101062306a36Sopenharmony_ci#ifdef CONFIG_NFS_V3_ACL 101162306a36Sopenharmony_ci .listxattr = nfs3_listxattr, 101262306a36Sopenharmony_ci .get_inode_acl = nfs3_get_acl, 101362306a36Sopenharmony_ci .set_acl = nfs3_set_acl, 101462306a36Sopenharmony_ci#endif 101562306a36Sopenharmony_ci}; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ciconst struct nfs_rpc_ops nfs_v3_clientops = { 101862306a36Sopenharmony_ci .version = 3, /* protocol version */ 101962306a36Sopenharmony_ci .dentry_ops = &nfs_dentry_operations, 102062306a36Sopenharmony_ci .dir_inode_ops = &nfs3_dir_inode_operations, 102162306a36Sopenharmony_ci .file_inode_ops = &nfs3_file_inode_operations, 102262306a36Sopenharmony_ci .file_ops = &nfs_file_operations, 102362306a36Sopenharmony_ci .nlmclnt_ops = &nlmclnt_fl_close_lock_ops, 102462306a36Sopenharmony_ci .getroot = nfs3_proc_get_root, 102562306a36Sopenharmony_ci .submount = nfs_submount, 102662306a36Sopenharmony_ci .try_get_tree = nfs_try_get_tree, 102762306a36Sopenharmony_ci .getattr = nfs3_proc_getattr, 102862306a36Sopenharmony_ci .setattr = nfs3_proc_setattr, 102962306a36Sopenharmony_ci .lookup = nfs3_proc_lookup, 103062306a36Sopenharmony_ci .lookupp = nfs3_proc_lookupp, 103162306a36Sopenharmony_ci .access = nfs3_proc_access, 103262306a36Sopenharmony_ci .readlink = nfs3_proc_readlink, 103362306a36Sopenharmony_ci .create = nfs3_proc_create, 103462306a36Sopenharmony_ci .remove = nfs3_proc_remove, 103562306a36Sopenharmony_ci .unlink_setup = nfs3_proc_unlink_setup, 103662306a36Sopenharmony_ci .unlink_rpc_prepare = nfs3_proc_unlink_rpc_prepare, 103762306a36Sopenharmony_ci .unlink_done = nfs3_proc_unlink_done, 103862306a36Sopenharmony_ci .rename_setup = nfs3_proc_rename_setup, 103962306a36Sopenharmony_ci .rename_rpc_prepare = nfs3_proc_rename_rpc_prepare, 104062306a36Sopenharmony_ci .rename_done = nfs3_proc_rename_done, 104162306a36Sopenharmony_ci .link = nfs3_proc_link, 104262306a36Sopenharmony_ci .symlink = nfs3_proc_symlink, 104362306a36Sopenharmony_ci .mkdir = nfs3_proc_mkdir, 104462306a36Sopenharmony_ci .rmdir = nfs3_proc_rmdir, 104562306a36Sopenharmony_ci .readdir = nfs3_proc_readdir, 104662306a36Sopenharmony_ci .mknod = nfs3_proc_mknod, 104762306a36Sopenharmony_ci .statfs = nfs3_proc_statfs, 104862306a36Sopenharmony_ci .fsinfo = nfs3_proc_fsinfo, 104962306a36Sopenharmony_ci .pathconf = nfs3_proc_pathconf, 105062306a36Sopenharmony_ci .decode_dirent = nfs3_decode_dirent, 105162306a36Sopenharmony_ci .pgio_rpc_prepare = nfs3_proc_pgio_rpc_prepare, 105262306a36Sopenharmony_ci .read_setup = nfs3_proc_read_setup, 105362306a36Sopenharmony_ci .read_done = nfs3_read_done, 105462306a36Sopenharmony_ci .write_setup = nfs3_proc_write_setup, 105562306a36Sopenharmony_ci .write_done = nfs3_write_done, 105662306a36Sopenharmony_ci .commit_setup = nfs3_proc_commit_setup, 105762306a36Sopenharmony_ci .commit_rpc_prepare = nfs3_proc_commit_rpc_prepare, 105862306a36Sopenharmony_ci .commit_done = nfs3_commit_done, 105962306a36Sopenharmony_ci .lock = nfs3_proc_lock, 106062306a36Sopenharmony_ci .clear_acl_cache = forget_all_cached_acls, 106162306a36Sopenharmony_ci .close_context = nfs_close_context, 106262306a36Sopenharmony_ci .have_delegation = nfs3_have_delegation, 106362306a36Sopenharmony_ci .alloc_client = nfs_alloc_client, 106462306a36Sopenharmony_ci .init_client = nfs_init_client, 106562306a36Sopenharmony_ci .free_client = nfs_free_client, 106662306a36Sopenharmony_ci .create_server = nfs3_create_server, 106762306a36Sopenharmony_ci .clone_server = nfs3_clone_server, 106862306a36Sopenharmony_ci}; 1069