Blame view

fs/nfs/nfs42proc.c 10.2 KB
1c6dcbe5c   Anna Schumaker   NFS: Implement SEEK
1
2
3
4
5
6
7
8
9
10
11
12
  /*
   * Copyright (c) 2014 Anna Schumaker <Anna.Schumaker@Netapp.com>
   */
  #include <linux/fs.h>
  #include <linux/sunrpc/sched.h>
  #include <linux/nfs.h>
  #include <linux/nfs3.h>
  #include <linux/nfs4.h>
  #include <linux/nfs_xdr.h>
  #include <linux/nfs_fs.h>
  #include "nfs4_fs.h"
  #include "nfs42.h"
1b4a4bd82   Peng Tao   pNFS: fill in nfs...
13
14
15
  #include "iostat.h"
  #include "pnfs.h"
  #include "internal.h"
291e1b945   Anna Schumaker   NFS: Properly set...
16
  #define NFSDBG_FACILITY NFSDBG_PROC
1c6dcbe5c   Anna Schumaker   NFS: Implement SEEK
17

f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
18
  static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
19
  		struct nfs_lock_context *lock, loff_t offset, loff_t len)
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
20
21
  {
  	struct inode *inode = file_inode(filep);
9a51940bf   Anna Schumaker   NFS: Don't zap ca...
22
  	struct nfs_server *server = NFS_SERVER(inode);
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
23
24
25
26
  	struct nfs42_falloc_args args = {
  		.falloc_fh	= NFS_FH(inode),
  		.falloc_offset	= offset,
  		.falloc_length	= len,
9a51940bf   Anna Schumaker   NFS: Don't zap ca...
27
28
29
30
  		.falloc_bitmask	= server->cache_consistency_bitmask,
  	};
  	struct nfs42_falloc_res res = {
  		.falloc_server	= server,
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
31
  	};
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
32
33
34
35
  	int status;
  
  	msg->rpc_argp = &args;
  	msg->rpc_resp = &res;
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
36
37
  	status = nfs4_set_rw_stateid(&args.falloc_stateid, lock->open_context,
  			lock, FMODE_WRITE);
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
38
39
  	if (status)
  		return status;
9a51940bf   Anna Schumaker   NFS: Don't zap ca...
40
41
42
43
44
45
46
47
48
49
50
  	res.falloc_fattr = nfs_alloc_fattr();
  	if (!res.falloc_fattr)
  		return -ENOMEM;
  
  	status = nfs4_call_sync(server->client, server, msg,
  				&args.seq_args, &res.seq_res, 0);
  	if (status == 0)
  		status = nfs_post_op_update_inode(inode, res.falloc_fattr);
  
  	kfree(res.falloc_fattr);
  	return status;
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
51
52
53
54
55
56
57
  }
  
  static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
  				loff_t offset, loff_t len)
  {
  	struct nfs_server *server = NFS_SERVER(file_inode(filep));
  	struct nfs4_exception exception = { };
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
58
  	struct nfs_lock_context *lock;
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
59
  	int err;
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
60
61
62
63
64
65
  	lock = nfs_get_lock_context(nfs_file_open_context(filep));
  	if (IS_ERR(lock))
  		return PTR_ERR(lock);
  
  	exception.inode = file_inode(filep);
  	exception.state = lock->open_context->state;
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
66
  	do {
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
67
68
69
70
71
  		err = _nfs42_proc_fallocate(msg, filep, lock, offset, len);
  		if (err == -ENOTSUPP) {
  			err = -EOPNOTSUPP;
  			break;
  		}
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
72
73
  		err = nfs4_handle_exception(server, err, &exception);
  	} while (exception.retry);
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
74
  	nfs_put_lock_context(lock);
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
75
76
77
78
79
80
81
82
83
84
85
86
87
  	return err;
  }
  
  int nfs42_proc_allocate(struct file *filep, loff_t offset, loff_t len)
  {
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE],
  	};
  	struct inode *inode = file_inode(filep);
  	int err;
  
  	if (!nfs_server_capable(inode, NFS_CAP_ALLOCATE))
  		return -EOPNOTSUPP;
5955102c9   Al Viro   wrappers for ->i_...
88
  	inode_lock(inode);
f830f7ddd   Anna Schumaker   NFS: Reduce time ...
89

f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
90
91
92
  	err = nfs42_proc_fallocate(&msg, filep, offset, len);
  	if (err == -EOPNOTSUPP)
  		NFS_SERVER(inode)->caps &= ~NFS_CAP_ALLOCATE;
f830f7ddd   Anna Schumaker   NFS: Reduce time ...
93

5955102c9   Al Viro   wrappers for ->i_...
94
  	inode_unlock(inode);
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
95
96
  	return err;
  }
624bd5b7b   Anna Schumaker   nfs: Add DEALLOCA...
97
98
99
100
101
102
103
104
105
106
  int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
  {
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DEALLOCATE],
  	};
  	struct inode *inode = file_inode(filep);
  	int err;
  
  	if (!nfs_server_capable(inode, NFS_CAP_DEALLOCATE))
  		return -EOPNOTSUPP;
9a51940bf   Anna Schumaker   NFS: Don't zap ca...
107
  	nfs_wb_all(inode);
5955102c9   Al Viro   wrappers for ->i_...
108
  	inode_lock(inode);
f830f7ddd   Anna Schumaker   NFS: Reduce time ...
109

624bd5b7b   Anna Schumaker   nfs: Add DEALLOCA...
110
  	err = nfs42_proc_fallocate(&msg, filep, offset, len);
9a51940bf   Anna Schumaker   NFS: Don't zap ca...
111
112
  	if (err == 0)
  		truncate_pagecache_range(inode, offset, (offset + len) -1);
624bd5b7b   Anna Schumaker   nfs: Add DEALLOCA...
113
114
  	if (err == -EOPNOTSUPP)
  		NFS_SERVER(inode)->caps &= ~NFS_CAP_DEALLOCATE;
f830f7ddd   Anna Schumaker   NFS: Reduce time ...
115

5955102c9   Al Viro   wrappers for ->i_...
116
  	inode_unlock(inode);
624bd5b7b   Anna Schumaker   nfs: Add DEALLOCA...
117
118
  	return err;
  }
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
119
120
  static loff_t _nfs42_proc_llseek(struct file *filep,
  		struct nfs_lock_context *lock, loff_t offset, int whence)
1c6dcbe5c   Anna Schumaker   NFS: Implement SEEK
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
  {
  	struct inode *inode = file_inode(filep);
  	struct nfs42_seek_args args = {
  		.sa_fh		= NFS_FH(inode),
  		.sa_offset	= offset,
  		.sa_what	= (whence == SEEK_HOLE) ?
  					NFS4_CONTENT_HOLE : NFS4_CONTENT_DATA,
  	};
  	struct nfs42_seek_res res;
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEEK],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
  	};
  	struct nfs_server *server = NFS_SERVER(inode);
  	int status;
878ffa9f8   Anna Schumaker   NFS: Use nfs_serv...
137
  	if (!nfs_server_capable(inode, NFS_CAP_SEEK))
1c6dcbe5c   Anna Schumaker   NFS: Implement SEEK
138
  		return -ENOTSUPP;
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
139
140
  	status = nfs4_set_rw_stateid(&args.sa_stateid, lock->open_context,
  			lock, FMODE_READ);
1c6dcbe5c   Anna Schumaker   NFS: Implement SEEK
141
142
143
144
145
146
147
148
149
150
151
152
153
  	if (status)
  		return status;
  
  	nfs_wb_all(inode);
  	status = nfs4_call_sync(server->client, server, &msg,
  				&args.seq_args, &res.seq_res, 0);
  	if (status == -ENOTSUPP)
  		server->caps &= ~NFS_CAP_SEEK;
  	if (status)
  		return status;
  
  	return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes);
  }
be3a5d233   Trond Myklebust   NFSv.2/pnfs Add a...
154

bdcc2cd14   J. Bruce Fields   NFSv4.2: handle N...
155
156
157
158
  loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
  {
  	struct nfs_server *server = NFS_SERVER(file_inode(filep));
  	struct nfs4_exception exception = { };
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
159
  	struct nfs_lock_context *lock;
306a55493   J. Bruce Fields   nfs: fix v4.2 SEE...
160
  	loff_t err;
bdcc2cd14   J. Bruce Fields   NFSv4.2: handle N...
161

4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
162
163
164
165
166
167
  	lock = nfs_get_lock_context(nfs_file_open_context(filep));
  	if (IS_ERR(lock))
  		return PTR_ERR(lock);
  
  	exception.inode = file_inode(filep);
  	exception.state = lock->open_context->state;
bdcc2cd14   J. Bruce Fields   NFSv4.2: handle N...
168
  	do {
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
169
  		err = _nfs42_proc_llseek(filep, lock, offset, whence);
306a55493   J. Bruce Fields   nfs: fix v4.2 SEE...
170
171
  		if (err >= 0)
  			break;
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
172
173
174
175
  		if (err == -ENOTSUPP) {
  			err = -EOPNOTSUPP;
  			break;
  		}
bdcc2cd14   J. Bruce Fields   NFSv4.2: handle N...
176
177
  		err = nfs4_handle_exception(server, err, &exception);
  	} while (exception.retry);
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
178
  	nfs_put_lock_context(lock);
bdcc2cd14   J. Bruce Fields   NFSv4.2: handle N...
179
180
  	return err;
  }
1b4a4bd82   Peng Tao   pNFS: fill in nfs...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  static void
  nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata)
  {
  	struct nfs42_layoutstat_data *data = calldata;
  	struct nfs_server *server = NFS_SERVER(data->args.inode);
  
  	nfs41_setup_sequence(nfs4_get_session(server), &data->args.seq_args,
  			     &data->res.seq_res, task);
  }
  
  static void
  nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
  {
  	struct nfs42_layoutstat_data *data = calldata;
68d264cf0   Peng Tao   NFS42: handle lay...
195
196
  	struct inode *inode = data->inode;
  	struct pnfs_layout_hdr *lo;
1b4a4bd82   Peng Tao   pNFS: fill in nfs...
197
198
199
  
  	if (!nfs4_sequence_done(task, &data->res.seq_res))
  		return;
6c5a0d891   Trond Myklebust   NFSv4.2: LAYOUTST...
200
201
202
  	switch (task->tk_status) {
  	case 0:
  		break;
68d264cf0   Peng Tao   NFS42: handle lay...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  	case -NFS4ERR_EXPIRED:
  	case -NFS4ERR_STALE_STATEID:
  	case -NFS4ERR_OLD_STATEID:
  	case -NFS4ERR_BAD_STATEID:
  		spin_lock(&inode->i_lock);
  		lo = NFS_I(inode)->layout;
  		if (lo && nfs4_stateid_match(&data->args.stateid,
  					     &lo->plh_stateid)) {
  			LIST_HEAD(head);
  
  			/*
  			 * Mark the bad layout state as invalid, then retry
  			 * with the current stateid.
  			 */
  			set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
  			pnfs_mark_matching_lsegs_invalid(lo, &head, NULL);
  			spin_unlock(&inode->i_lock);
  			pnfs_free_lseg_list(&head);
  		} else
  			spin_unlock(&inode->i_lock);
  		break;
6c5a0d891   Trond Myklebust   NFSv4.2: LAYOUTST...
224
225
  	case -ENOTSUPP:
  	case -EOPNOTSUPP:
68d264cf0   Peng Tao   NFS42: handle lay...
226
  		NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTSTATS;
6c5a0d891   Trond Myklebust   NFSv4.2: LAYOUTST...
227
  	default:
68d264cf0   Peng Tao   NFS42: handle lay...
228
  		break;
6c5a0d891   Trond Myklebust   NFSv4.2: LAYOUTST...
229
  	}
68d264cf0   Peng Tao   NFS42: handle lay...
230
231
232
  
  	dprintk("%s server returns %d
  ", __func__, task->tk_status);
1b4a4bd82   Peng Tao   pNFS: fill in nfs...
233
234
235
236
237
238
  }
  
  static void
  nfs42_layoutstat_release(void *calldata)
  {
  	struct nfs42_layoutstat_data *data = calldata;
8733408d6   Peng Tao   pnfs: add pnfs_re...
239
240
241
242
  	struct nfs_server *nfss = NFS_SERVER(data->args.inode);
  
  	if (nfss->pnfs_curr_ld->cleanup_layoutstats)
  		nfss->pnfs_curr_ld->cleanup_layoutstats(data);
1b4a4bd82   Peng Tao   pNFS: fill in nfs...
243
244
  
  	pnfs_put_layout_hdr(NFS_I(data->args.inode)->layout);
1bfe3b259   Peng Tao   nfs42: serialize ...
245
246
247
  	smp_mb__before_atomic();
  	clear_bit(NFS_INO_LAYOUTSTATS, &NFS_I(data->args.inode)->flags);
  	smp_mb__after_atomic();
1b4a4bd82   Peng Tao   pNFS: fill in nfs...
248
249
250
251
  	nfs_iput_and_deactive(data->inode);
  	kfree(data->args.devinfo);
  	kfree(data);
  }
be3a5d233   Trond Myklebust   NFSv.2/pnfs Add a...
252
  static const struct rpc_call_ops nfs42_layoutstat_ops = {
1b4a4bd82   Peng Tao   pNFS: fill in nfs...
253
254
255
  	.rpc_call_prepare = nfs42_layoutstat_prepare,
  	.rpc_call_done = nfs42_layoutstat_done,
  	.rpc_release = nfs42_layoutstat_release,
be3a5d233   Trond Myklebust   NFSv.2/pnfs Add a...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  };
  
  int nfs42_proc_layoutstats_generic(struct nfs_server *server,
  				   struct nfs42_layoutstat_data *data)
  {
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTSTATS],
  		.rpc_argp = &data->args,
  		.rpc_resp = &data->res,
  	};
  	struct rpc_task_setup task_setup = {
  		.rpc_client = server->client,
  		.rpc_message = &msg,
  		.callback_ops = &nfs42_layoutstat_ops,
  		.callback_data = data,
  		.flags = RPC_TASK_ASYNC,
  	};
  	struct rpc_task *task;
1b4a4bd82   Peng Tao   pNFS: fill in nfs...
274
275
276
277
278
  	data->inode = nfs_igrab_and_active(data->args.inode);
  	if (!data->inode) {
  		nfs42_layoutstat_release(data);
  		return -EAGAIN;
  	}
be3a5d233   Trond Myklebust   NFSv.2/pnfs Add a...
279
280
281
282
283
284
  	nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
  	task = rpc_run_task(&task_setup);
  	if (IS_ERR(task))
  		return PTR_ERR(task);
  	return 0;
  }
e5341f3a5   Peng Tao   nfs42: add CLONE ...
285
286
  
  static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
287
288
289
  		struct file *dst_f, struct nfs_lock_context *src_lock,
  		struct nfs_lock_context *dst_lock, loff_t src_offset,
  		loff_t dst_offset, loff_t count)
e5341f3a5   Peng Tao   nfs42: add CLONE ...
290
291
292
293
294
295
296
297
298
  {
  	struct inode *src_inode = file_inode(src_f);
  	struct inode *dst_inode = file_inode(dst_f);
  	struct nfs_server *server = NFS_SERVER(dst_inode);
  	struct nfs42_clone_args args = {
  		.src_fh = NFS_FH(src_inode),
  		.dst_fh = NFS_FH(dst_inode),
  		.src_offset = src_offset,
  		.dst_offset = dst_offset,
9494b2ce4   Christoph Hellwig   nfs: pass on coun...
299
  		.count = count,
e5341f3a5   Peng Tao   nfs42: add CLONE ...
300
301
302
303
304
305
306
307
308
  		.dst_bitmask = server->cache_consistency_bitmask,
  	};
  	struct nfs42_clone_res res = {
  		.server	= server,
  	};
  	int status;
  
  	msg->rpc_argp = &args;
  	msg->rpc_resp = &res;
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
309
310
  	status = nfs4_set_rw_stateid(&args.src_stateid, src_lock->open_context,
  			src_lock, FMODE_READ);
e5341f3a5   Peng Tao   nfs42: add CLONE ...
311
312
  	if (status)
  		return status;
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
313
314
  	status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context,
  			dst_lock, FMODE_WRITE);
e5341f3a5   Peng Tao   nfs42: add CLONE ...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
  	if (status)
  		return status;
  
  	res.dst_fattr = nfs_alloc_fattr();
  	if (!res.dst_fattr)
  		return -ENOMEM;
  
  	status = nfs4_call_sync(server->client, server, msg,
  				&args.seq_args, &res.seq_res, 0);
  	if (status == 0)
  		status = nfs_post_op_update_inode(dst_inode, res.dst_fattr);
  
  	kfree(res.dst_fattr);
  	return status;
  }
  
  int nfs42_proc_clone(struct file *src_f, struct file *dst_f,
  		     loff_t src_offset, loff_t dst_offset, loff_t count)
  {
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLONE],
  	};
  	struct inode *inode = file_inode(src_f);
  	struct nfs_server *server = NFS_SERVER(file_inode(src_f));
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
339
340
341
342
343
  	struct nfs_lock_context *src_lock;
  	struct nfs_lock_context *dst_lock;
  	struct nfs4_exception src_exception = { };
  	struct nfs4_exception dst_exception = { };
  	int err, err2;
e5341f3a5   Peng Tao   nfs42: add CLONE ...
344
345
346
  
  	if (!nfs_server_capable(inode, NFS_CAP_CLONE))
  		return -EOPNOTSUPP;
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
  	src_lock = nfs_get_lock_context(nfs_file_open_context(src_f));
  	if (IS_ERR(src_lock))
  		return PTR_ERR(src_lock);
  
  	src_exception.inode = file_inode(src_f);
  	src_exception.state = src_lock->open_context->state;
  
  	dst_lock = nfs_get_lock_context(nfs_file_open_context(dst_f));
  	if (IS_ERR(dst_lock)) {
  		err = PTR_ERR(dst_lock);
  		goto out_put_src_lock;
  	}
  
  	dst_exception.inode = file_inode(dst_f);
  	dst_exception.state = dst_lock->open_context->state;
e5341f3a5   Peng Tao   nfs42: add CLONE ...
362
  	do {
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
363
364
  		err = _nfs42_proc_clone(&msg, src_f, dst_f, src_lock, dst_lock,
  					src_offset, dst_offset, count);
e5341f3a5   Peng Tao   nfs42: add CLONE ...
365
366
  		if (err == -ENOTSUPP || err == -EOPNOTSUPP) {
  			NFS_SERVER(inode)->caps &= ~NFS_CAP_CLONE;
4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
367
368
  			err = -EOPNOTSUPP;
  			break;
e5341f3a5   Peng Tao   nfs42: add CLONE ...
369
  		}
e5341f3a5   Peng Tao   nfs42: add CLONE ...
370

4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
371
372
373
374
375
  		err2 = nfs4_handle_exception(server, err, &src_exception);
  		err = nfs4_handle_exception(server, err, &dst_exception);
  		if (!err)
  			err = err2;
  	} while (src_exception.retry || dst_exception.retry);
e5341f3a5   Peng Tao   nfs42: add CLONE ...
376

4bdf87ebd   Christoph Hellwig   nfs4: fix stateid...
377
378
379
380
  	nfs_put_lock_context(dst_lock);
  out_put_src_lock:
  	nfs_put_lock_context(src_lock);
  	return err;
e5341f3a5   Peng Tao   nfs42: add CLONE ...
381
  }