1/* 2 * Copyright (c) 2014 Anna Schumaker <Anna.Schumaker@Netapp.com> 3 */ 4#include <linux/fs.h> 5#include <linux/sunrpc/sched.h> 6#include <linux/nfs.h> 7#include <linux/nfs3.h> 8#include <linux/nfs4.h> 9#include <linux/nfs_xdr.h> 10#include <linux/nfs_fs.h> 11#include "nfs4_fs.h" 12#include "nfs42.h" 13#include "iostat.h" 14#include "pnfs.h" 15#include "internal.h" 16 17#define NFSDBG_FACILITY NFSDBG_PROC 18 19static int nfs42_set_rw_stateid(nfs4_stateid *dst, struct file *file, 20 fmode_t fmode) 21{ 22 struct nfs_open_context *open; 23 struct nfs_lock_context *lock; 24 int ret; 25 26 open = get_nfs_open_context(nfs_file_open_context(file)); 27 lock = nfs_get_lock_context(open); 28 if (IS_ERR(lock)) { 29 put_nfs_open_context(open); 30 return PTR_ERR(lock); 31 } 32 33 ret = nfs4_set_rw_stateid(dst, open, lock, fmode); 34 35 nfs_put_lock_context(lock); 36 put_nfs_open_context(open); 37 return ret; 38} 39 40static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep, 41 loff_t offset, loff_t len) 42{ 43 struct inode *inode = file_inode(filep); 44 struct nfs_server *server = NFS_SERVER(inode); 45 struct nfs42_falloc_args args = { 46 .falloc_fh = NFS_FH(inode), 47 .falloc_offset = offset, 48 .falloc_length = len, 49 .falloc_bitmask = server->cache_consistency_bitmask, 50 }; 51 struct nfs42_falloc_res res = { 52 .falloc_server = server, 53 }; 54 int status; 55 56 msg->rpc_argp = &args; 57 msg->rpc_resp = &res; 58 59 status = nfs42_set_rw_stateid(&args.falloc_stateid, filep, FMODE_WRITE); 60 if (status) 61 return status; 62 63 res.falloc_fattr = nfs_alloc_fattr(); 64 if (!res.falloc_fattr) 65 return -ENOMEM; 66 67 status = nfs4_call_sync(server->client, server, msg, 68 &args.seq_args, &res.seq_res, 0); 69 if (status == 0) 70 status = nfs_post_op_update_inode(inode, res.falloc_fattr); 71 72 kfree(res.falloc_fattr); 73 return status; 74} 75 76static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep, 77 loff_t offset, loff_t len) 78{ 79 struct nfs_server *server = NFS_SERVER(file_inode(filep)); 80 struct nfs4_exception exception = { }; 81 int err; 82 83 do { 84 err = _nfs42_proc_fallocate(msg, filep, offset, len); 85 if (err == -ENOTSUPP) 86 return -EOPNOTSUPP; 87 err = nfs4_handle_exception(server, err, &exception); 88 } while (exception.retry); 89 90 return err; 91} 92 93int nfs42_proc_allocate(struct file *filep, loff_t offset, loff_t len) 94{ 95 struct rpc_message msg = { 96 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE], 97 }; 98 struct inode *inode = file_inode(filep); 99 int err; 100 101 if (!nfs_server_capable(inode, NFS_CAP_ALLOCATE)) 102 return -EOPNOTSUPP; 103 104 mutex_lock(&inode->i_mutex); 105 106 err = nfs42_proc_fallocate(&msg, filep, offset, len); 107 if (err == -EOPNOTSUPP) 108 NFS_SERVER(inode)->caps &= ~NFS_CAP_ALLOCATE; 109 110 mutex_unlock(&inode->i_mutex); 111 return err; 112} 113 114int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len) 115{ 116 struct rpc_message msg = { 117 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DEALLOCATE], 118 }; 119 struct inode *inode = file_inode(filep); 120 int err; 121 122 if (!nfs_server_capable(inode, NFS_CAP_DEALLOCATE)) 123 return -EOPNOTSUPP; 124 125 nfs_wb_all(inode); 126 mutex_lock(&inode->i_mutex); 127 128 err = nfs42_proc_fallocate(&msg, filep, offset, len); 129 if (err == 0) 130 truncate_pagecache_range(inode, offset, (offset + len) -1); 131 if (err == -EOPNOTSUPP) 132 NFS_SERVER(inode)->caps &= ~NFS_CAP_DEALLOCATE; 133 134 mutex_unlock(&inode->i_mutex); 135 return err; 136} 137 138static loff_t _nfs42_proc_llseek(struct file *filep, loff_t offset, int whence) 139{ 140 struct inode *inode = file_inode(filep); 141 struct nfs42_seek_args args = { 142 .sa_fh = NFS_FH(inode), 143 .sa_offset = offset, 144 .sa_what = (whence == SEEK_HOLE) ? 145 NFS4_CONTENT_HOLE : NFS4_CONTENT_DATA, 146 }; 147 struct nfs42_seek_res res; 148 struct rpc_message msg = { 149 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEEK], 150 .rpc_argp = &args, 151 .rpc_resp = &res, 152 }; 153 struct nfs_server *server = NFS_SERVER(inode); 154 int status; 155 156 if (!nfs_server_capable(inode, NFS_CAP_SEEK)) 157 return -ENOTSUPP; 158 159 status = nfs42_set_rw_stateid(&args.sa_stateid, filep, FMODE_READ); 160 if (status) 161 return status; 162 163 nfs_wb_all(inode); 164 status = nfs4_call_sync(server->client, server, &msg, 165 &args.seq_args, &res.seq_res, 0); 166 if (status == -ENOTSUPP) 167 server->caps &= ~NFS_CAP_SEEK; 168 if (status) 169 return status; 170 171 return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes); 172} 173 174loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence) 175{ 176 struct nfs_server *server = NFS_SERVER(file_inode(filep)); 177 struct nfs4_exception exception = { }; 178 loff_t err; 179 180 do { 181 err = _nfs42_proc_llseek(filep, offset, whence); 182 if (err >= 0) 183 break; 184 if (err == -ENOTSUPP) 185 return -EOPNOTSUPP; 186 err = nfs4_handle_exception(server, err, &exception); 187 } while (exception.retry); 188 189 return err; 190} 191 192 193static void 194nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata) 195{ 196 struct nfs42_layoutstat_data *data = calldata; 197 struct nfs_server *server = NFS_SERVER(data->args.inode); 198 199 nfs41_setup_sequence(nfs4_get_session(server), &data->args.seq_args, 200 &data->res.seq_res, task); 201} 202 203static void 204nfs42_layoutstat_done(struct rpc_task *task, void *calldata) 205{ 206 struct nfs42_layoutstat_data *data = calldata; 207 208 if (!nfs4_sequence_done(task, &data->res.seq_res)) 209 return; 210 211 switch (task->tk_status) { 212 case 0: 213 break; 214 case -ENOTSUPP: 215 case -EOPNOTSUPP: 216 NFS_SERVER(data->inode)->caps &= ~NFS_CAP_LAYOUTSTATS; 217 default: 218 dprintk("%s server returns %d\n", __func__, task->tk_status); 219 } 220} 221 222static void 223nfs42_layoutstat_release(void *calldata) 224{ 225 struct nfs42_layoutstat_data *data = calldata; 226 struct nfs_server *nfss = NFS_SERVER(data->args.inode); 227 228 if (nfss->pnfs_curr_ld->cleanup_layoutstats) 229 nfss->pnfs_curr_ld->cleanup_layoutstats(data); 230 231 pnfs_put_layout_hdr(NFS_I(data->args.inode)->layout); 232 smp_mb__before_atomic(); 233 clear_bit(NFS_INO_LAYOUTSTATS, &NFS_I(data->args.inode)->flags); 234 smp_mb__after_atomic(); 235 nfs_iput_and_deactive(data->inode); 236 kfree(data->args.devinfo); 237 kfree(data); 238} 239 240static const struct rpc_call_ops nfs42_layoutstat_ops = { 241 .rpc_call_prepare = nfs42_layoutstat_prepare, 242 .rpc_call_done = nfs42_layoutstat_done, 243 .rpc_release = nfs42_layoutstat_release, 244}; 245 246int nfs42_proc_layoutstats_generic(struct nfs_server *server, 247 struct nfs42_layoutstat_data *data) 248{ 249 struct rpc_message msg = { 250 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTSTATS], 251 .rpc_argp = &data->args, 252 .rpc_resp = &data->res, 253 }; 254 struct rpc_task_setup task_setup = { 255 .rpc_client = server->client, 256 .rpc_message = &msg, 257 .callback_ops = &nfs42_layoutstat_ops, 258 .callback_data = data, 259 .flags = RPC_TASK_ASYNC, 260 }; 261 struct rpc_task *task; 262 263 data->inode = nfs_igrab_and_active(data->args.inode); 264 if (!data->inode) { 265 nfs42_layoutstat_release(data); 266 return -EAGAIN; 267 } 268 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0); 269 task = rpc_run_task(&task_setup); 270 if (IS_ERR(task)) 271 return PTR_ERR(task); 272 return 0; 273} 274 275static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f, 276 struct file *dst_f, loff_t src_offset, 277 loff_t dst_offset, loff_t count) 278{ 279 struct inode *src_inode = file_inode(src_f); 280 struct inode *dst_inode = file_inode(dst_f); 281 struct nfs_server *server = NFS_SERVER(dst_inode); 282 struct nfs42_clone_args args = { 283 .src_fh = NFS_FH(src_inode), 284 .dst_fh = NFS_FH(dst_inode), 285 .src_offset = src_offset, 286 .dst_offset = dst_offset, 287 .count = count, 288 .dst_bitmask = server->cache_consistency_bitmask, 289 }; 290 struct nfs42_clone_res res = { 291 .server = server, 292 }; 293 int status; 294 295 msg->rpc_argp = &args; 296 msg->rpc_resp = &res; 297 298 status = nfs42_set_rw_stateid(&args.src_stateid, src_f, FMODE_READ); 299 if (status) 300 return status; 301 302 status = nfs42_set_rw_stateid(&args.dst_stateid, dst_f, FMODE_WRITE); 303 if (status) 304 return status; 305 306 res.dst_fattr = nfs_alloc_fattr(); 307 if (!res.dst_fattr) 308 return -ENOMEM; 309 310 status = nfs4_call_sync(server->client, server, msg, 311 &args.seq_args, &res.seq_res, 0); 312 if (status == 0) 313 status = nfs_post_op_update_inode(dst_inode, res.dst_fattr); 314 315 kfree(res.dst_fattr); 316 return status; 317} 318 319int nfs42_proc_clone(struct file *src_f, struct file *dst_f, 320 loff_t src_offset, loff_t dst_offset, loff_t count) 321{ 322 struct rpc_message msg = { 323 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLONE], 324 }; 325 struct inode *inode = file_inode(src_f); 326 struct nfs_server *server = NFS_SERVER(file_inode(src_f)); 327 struct nfs4_exception exception = { }; 328 int err; 329 330 if (!nfs_server_capable(inode, NFS_CAP_CLONE)) 331 return -EOPNOTSUPP; 332 333 do { 334 err = _nfs42_proc_clone(&msg, src_f, dst_f, src_offset, 335 dst_offset, count); 336 if (err == -ENOTSUPP || err == -EOPNOTSUPP) { 337 NFS_SERVER(inode)->caps &= ~NFS_CAP_CLONE; 338 return -EOPNOTSUPP; 339 } 340 err = nfs4_handle_exception(server, err, &exception); 341 } while (exception.retry); 342 343 return err; 344 345} 346