nfs42proc.c 14.5 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
A
Anna Schumaker 已提交
2 3 4 5 6 7 8 9 10 11 12 13
/*
 * 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"
P
Peng Tao 已提交
14 15
#include "iostat.h"
#include "pnfs.h"
16
#include "nfs4session.h"
P
Peng Tao 已提交
17 18
#include "internal.h"

19
#define NFSDBG_FACILITY NFSDBG_PROC
A
Anna Schumaker 已提交
20

A
Anna Schumaker 已提交
21
static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
22
		struct nfs_lock_context *lock, loff_t offset, loff_t len)
A
Anna Schumaker 已提交
23 24
{
	struct inode *inode = file_inode(filep);
25
	struct nfs_server *server = NFS_SERVER(inode);
A
Anna Schumaker 已提交
26 27 28 29
	struct nfs42_falloc_args args = {
		.falloc_fh	= NFS_FH(inode),
		.falloc_offset	= offset,
		.falloc_length	= len,
30 31 32 33
		.falloc_bitmask	= server->cache_consistency_bitmask,
	};
	struct nfs42_falloc_res res = {
		.falloc_server	= server,
A
Anna Schumaker 已提交
34 35 36 37 38 39
	};
	int status;

	msg->rpc_argp = &args;
	msg->rpc_resp = &res;

40 41
	status = nfs4_set_rw_stateid(&args.falloc_stateid, lock->open_context,
			lock, FMODE_WRITE);
A
Anna Schumaker 已提交
42 43 44
	if (status)
		return status;

45 46 47 48 49 50 51 52 53 54 55
	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;
A
Anna Schumaker 已提交
56 57 58 59 60 61 62
}

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 = { };
63
	struct nfs_lock_context *lock;
A
Anna Schumaker 已提交
64 65
	int err;

66 67 68 69 70 71 72
	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;

A
Anna Schumaker 已提交
73
	do {
74 75 76 77 78
		err = _nfs42_proc_fallocate(msg, filep, lock, offset, len);
		if (err == -ENOTSUPP) {
			err = -EOPNOTSUPP;
			break;
		}
A
Anna Schumaker 已提交
79 80 81
		err = nfs4_handle_exception(server, err, &exception);
	} while (exception.retry);

82
	nfs_put_lock_context(lock);
A
Anna Schumaker 已提交
83 84 85 86 87 88 89 90 91 92 93 94 95 96
	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;

A
Al Viro 已提交
97
	inode_lock(inode);
98

A
Anna Schumaker 已提交
99 100 101
	err = nfs42_proc_fallocate(&msg, filep, offset, len);
	if (err == -EOPNOTSUPP)
		NFS_SERVER(inode)->caps &= ~NFS_CAP_ALLOCATE;
102

A
Al Viro 已提交
103
	inode_unlock(inode);
A
Anna Schumaker 已提交
104 105 106
	return err;
}

A
Anna Schumaker 已提交
107 108 109 110 111 112 113 114 115 116 117
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;

A
Al Viro 已提交
118
	inode_lock(inode);
119 120 121
	err = nfs_sync_inode(inode);
	if (err)
		goto out_unlock;
122

A
Anna Schumaker 已提交
123
	err = nfs42_proc_fallocate(&msg, filep, offset, len);
124 125
	if (err == 0)
		truncate_pagecache_range(inode, offset, (offset + len) -1);
A
Anna Schumaker 已提交
126 127
	if (err == -EOPNOTSUPP)
		NFS_SERVER(inode)->caps &= ~NFS_CAP_DEALLOCATE;
128
out_unlock:
A
Al Viro 已提交
129
	inode_unlock(inode);
A
Anna Schumaker 已提交
130 131 132
	return err;
}

133
static ssize_t _nfs42_proc_copy(struct file *src,
A
Anna Schumaker 已提交
134
				struct nfs_lock_context *src_lock,
135
				struct file *dst,
A
Anna Schumaker 已提交
136
				struct nfs_lock_context *dst_lock,
137 138
				struct nfs42_copy_args *args,
				struct nfs42_copy_res *res)
A
Anna Schumaker 已提交
139 140 141
{
	struct rpc_message msg = {
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY],
142 143
		.rpc_argp = args,
		.rpc_resp = res,
A
Anna Schumaker 已提交
144 145 146
	};
	struct inode *dst_inode = file_inode(dst);
	struct nfs_server *server = NFS_SERVER(dst_inode);
147 148 149
	loff_t pos_src = args->src_pos;
	loff_t pos_dst = args->dst_pos;
	size_t count = args->count;
150
	ssize_t status;
A
Anna Schumaker 已提交
151

152
	status = nfs4_set_rw_stateid(&args->src_stateid, src_lock->open_context,
A
Anna Schumaker 已提交
153 154 155 156
				     src_lock, FMODE_READ);
	if (status)
		return status;

157 158 159 160 161
	status = nfs_filemap_write_and_wait_range(file_inode(src)->i_mapping,
			pos_src, pos_src + (loff_t)count - 1);
	if (status)
		return status;

162
	status = nfs4_set_rw_stateid(&args->dst_stateid, dst_lock->open_context,
A
Anna Schumaker 已提交
163 164 165
				     dst_lock, FMODE_WRITE);
	if (status)
		return status;
166 167 168 169

	status = nfs_sync_inode(dst_inode);
	if (status)
		return status;
A
Anna Schumaker 已提交
170

171 172 173
	res->commit_res.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS);
	if (!res->commit_res.verf)
		return -ENOMEM;
A
Anna Schumaker 已提交
174
	status = nfs4_call_sync(server->client, server, &msg,
175
				&args->seq_args, &res->seq_res, 0);
A
Anna Schumaker 已提交
176 177 178
	if (status == -ENOTSUPP)
		server->caps &= ~NFS_CAP_COPY;
	if (status)
179
		goto out;
A
Anna Schumaker 已提交
180

O
Olga Kornievskaia 已提交
181
	if (nfs_write_verifier_cmp(&res->write_res.verifier.verifier,
182 183 184
				    &res->commit_res.verf->verifier)) {
		status = -EAGAIN;
		goto out;
A
Anna Schumaker 已提交
185 186 187
	}

	truncate_pagecache_range(dst_inode, pos_dst,
188
				 pos_dst + res->write_res.count);
A
Anna Schumaker 已提交
189

190 191 192 193
	status = res->write_res.count;
out:
	kfree(res->commit_res.verf);
	return status;
A
Anna Schumaker 已提交
194 195 196 197 198 199 200 201 202
}

ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
			struct file *dst, loff_t pos_dst,
			size_t count)
{
	struct nfs_server *server = NFS_SERVER(file_inode(dst));
	struct nfs_lock_context *src_lock;
	struct nfs_lock_context *dst_lock;
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
	struct nfs42_copy_args args = {
		.src_fh		= NFS_FH(file_inode(src)),
		.src_pos	= pos_src,
		.dst_fh		= NFS_FH(file_inode(dst)),
		.dst_pos	= pos_dst,
		.count		= count,
	};
	struct nfs42_copy_res res;
	struct nfs4_exception src_exception = {
		.inode		= file_inode(src),
		.stateid	= &args.src_stateid,
	};
	struct nfs4_exception dst_exception = {
		.inode		= file_inode(dst),
		.stateid	= &args.dst_stateid,
	};
A
Anna Schumaker 已提交
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
	ssize_t err, err2;

	if (!nfs_server_capable(file_inode(dst), NFS_CAP_COPY))
		return -EOPNOTSUPP;

	src_lock = nfs_get_lock_context(nfs_file_open_context(src));
	if (IS_ERR(src_lock))
		return PTR_ERR(src_lock);

	src_exception.state = src_lock->open_context->state;

	dst_lock = nfs_get_lock_context(nfs_file_open_context(dst));
	if (IS_ERR(dst_lock)) {
		err = PTR_ERR(dst_lock);
		goto out_put_src_lock;
	}

	dst_exception.state = dst_lock->open_context->state;

	do {
239
		inode_lock(file_inode(dst));
240 241 242
		err = _nfs42_proc_copy(src, src_lock,
				dst, dst_lock,
				&args, &res);
243
		inode_unlock(file_inode(dst));
A
Anna Schumaker 已提交
244

245 246
		if (err >= 0)
			break;
A
Anna Schumaker 已提交
247 248 249
		if (err == -ENOTSUPP) {
			err = -EOPNOTSUPP;
			break;
250 251 252
		} if (err == -EAGAIN) {
			dst_exception.retry = 1;
			continue;
A
Anna Schumaker 已提交
253 254 255 256 257 258 259 260 261 262 263 264 265 266
		}

		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);

	nfs_put_lock_context(dst_lock);
out_put_src_lock:
	nfs_put_lock_context(src_lock);
	return err;
}

267 268
static loff_t _nfs42_proc_llseek(struct file *filep,
		struct nfs_lock_context *lock, loff_t offset, int whence)
A
Anna Schumaker 已提交
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
{
	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;

286
	if (!nfs_server_capable(inode, NFS_CAP_SEEK))
A
Anna Schumaker 已提交
287 288
		return -ENOTSUPP;

289 290
	status = nfs4_set_rw_stateid(&args.sa_stateid, lock->open_context,
			lock, FMODE_READ);
A
Anna Schumaker 已提交
291 292 293
	if (status)
		return status;

294 295 296 297 298
	status = nfs_filemap_write_and_wait_range(inode->i_mapping,
			offset, LLONG_MAX);
	if (status)
		return status;

A
Anna Schumaker 已提交
299 300 301 302 303 304 305 306 307
	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);
}
308

309 310 311 312
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 = { };
313
	struct nfs_lock_context *lock;
314
	loff_t err;
315

316 317 318 319 320 321 322
	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;

323
	do {
324
		err = _nfs42_proc_llseek(filep, lock, offset, whence);
325 326
		if (err >= 0)
			break;
327 328 329 330
		if (err == -ENOTSUPP) {
			err = -EOPNOTSUPP;
			break;
		}
331 332 333
		err = nfs4_handle_exception(server, err, &exception);
	} while (exception.retry);

334
	nfs_put_lock_context(lock);
335 336 337 338
	return err;
}


P
Peng Tao 已提交
339 340 341 342
static void
nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata)
{
	struct nfs42_layoutstat_data *data = calldata;
343 344 345
	struct inode *inode = data->inode;
	struct nfs_server *server = NFS_SERVER(inode);
	struct pnfs_layout_hdr *lo;
P
Peng Tao 已提交
346

347 348 349 350 351 352 353 354 355
	spin_lock(&inode->i_lock);
	lo = NFS_I(inode)->layout;
	if (!pnfs_layout_is_valid(lo)) {
		spin_unlock(&inode->i_lock);
		rpc_exit(task, 0);
		return;
	}
	nfs4_stateid_copy(&data->args.stateid, &lo->plh_stateid);
	spin_unlock(&inode->i_lock);
356 357
	nfs4_setup_sequence(server->nfs_client, &data->args.seq_args,
			    &data->res.seq_res, task);
P
Peng Tao 已提交
358 359 360 361 362 363
}

static void
nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
{
	struct nfs42_layoutstat_data *data = calldata;
P
Peng Tao 已提交
364 365
	struct inode *inode = data->inode;
	struct pnfs_layout_hdr *lo;
P
Peng Tao 已提交
366 367 368 369

	if (!nfs4_sequence_done(task, &data->res.seq_res))
		return;

370 371 372
	switch (task->tk_status) {
	case 0:
		break;
P
Peng Tao 已提交
373
	case -NFS4ERR_EXPIRED:
374 375
	case -NFS4ERR_ADMIN_REVOKED:
	case -NFS4ERR_DELEG_REVOKED:
P
Peng Tao 已提交
376 377 378 379
	case -NFS4ERR_STALE_STATEID:
	case -NFS4ERR_BAD_STATEID:
		spin_lock(&inode->i_lock);
		lo = NFS_I(inode)->layout;
380 381
		if (pnfs_layout_is_valid(lo) &&
		    nfs4_stateid_match(&data->args.stateid,
P
Peng Tao 已提交
382 383 384 385 386 387 388
					     &lo->plh_stateid)) {
			LIST_HEAD(head);

			/*
			 * Mark the bad layout state as invalid, then retry
			 * with the current stateid.
			 */
389
			pnfs_mark_layout_stateid_invalid(lo, &head);
P
Peng Tao 已提交
390 391
			spin_unlock(&inode->i_lock);
			pnfs_free_lseg_list(&head);
392
			nfs_commit_inode(inode, 0);
P
Peng Tao 已提交
393 394 395
		} else
			spin_unlock(&inode->i_lock);
		break;
396 397 398 399 400 401 402 403 404 405 406 407 408 409
	case -NFS4ERR_OLD_STATEID:
		spin_lock(&inode->i_lock);
		lo = NFS_I(inode)->layout;
		if (pnfs_layout_is_valid(lo) &&
		    nfs4_stateid_match_other(&data->args.stateid,
					&lo->plh_stateid)) {
			/* Do we need to delay before resending? */
			if (!nfs4_stateid_is_newer(&lo->plh_stateid,
						&data->args.stateid))
				rpc_delay(task, HZ);
			rpc_restart_call_prepare(task);
		}
		spin_unlock(&inode->i_lock);
		break;
410 411
	case -ENOTSUPP:
	case -EOPNOTSUPP:
P
Peng Tao 已提交
412
		NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTSTATS;
413
	}
P
Peng Tao 已提交
414 415 416 417 418 419
}

static void
nfs42_layoutstat_release(void *calldata)
{
	struct nfs42_layoutstat_data *data = calldata;
420 421
	struct nfs42_layoutstat_devinfo *devinfo = data->args.devinfo;
	int i;
422

423 424 425 426
	for (i = 0; i < data->args.num_dev; i++) {
		if (devinfo[i].ld_private.ops && devinfo[i].ld_private.ops->free)
			devinfo[i].ld_private.ops->free(&devinfo[i].ld_private);
	}
P
Peng Tao 已提交
427 428

	pnfs_put_layout_hdr(NFS_I(data->args.inode)->layout);
429 430 431
	smp_mb__before_atomic();
	clear_bit(NFS_INO_LAYOUTSTATS, &NFS_I(data->args.inode)->flags);
	smp_mb__after_atomic();
P
Peng Tao 已提交
432 433 434 435 436
	nfs_iput_and_deactive(data->inode);
	kfree(data->args.devinfo);
	kfree(data);
}

437
static const struct rpc_call_ops nfs42_layoutstat_ops = {
P
Peng Tao 已提交
438 439 440
	.rpc_call_prepare = nfs42_layoutstat_prepare,
	.rpc_call_done = nfs42_layoutstat_done,
	.rpc_release = nfs42_layoutstat_release,
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
};

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;

P
Peng Tao 已提交
460 461 462 463 464
	data->inode = nfs_igrab_and_active(data->args.inode);
	if (!data->inode) {
		nfs42_layoutstat_release(data);
		return -EAGAIN;
	}
465
	nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0, 0);
466 467 468
	task = rpc_run_task(&task_setup);
	if (IS_ERR(task))
		return PTR_ERR(task);
469
	rpc_put_task(task);
470 471
	return 0;
}
P
Peng Tao 已提交
472 473

static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
474 475 476
		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)
P
Peng Tao 已提交
477 478 479 480 481 482 483 484 485
{
	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,
486
		.count = count,
P
Peng Tao 已提交
487 488 489 490 491 492 493 494 495 496
		.dst_bitmask = server->cache_consistency_bitmask,
	};
	struct nfs42_clone_res res = {
		.server	= server,
	};
	int status;

	msg->rpc_argp = &args;
	msg->rpc_resp = &res;

497 498
	status = nfs4_set_rw_stateid(&args.src_stateid, src_lock->open_context,
			src_lock, FMODE_READ);
P
Peng Tao 已提交
499 500 501
	if (status)
		return status;

502 503
	status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context,
			dst_lock, FMODE_WRITE);
P
Peng Tao 已提交
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
	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));
528 529 530 531 532
	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;
P
Peng Tao 已提交
533 534 535 536

	if (!nfs_server_capable(inode, NFS_CAP_CLONE))
		return -EOPNOTSUPP;

537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
	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;

P
Peng Tao 已提交
553
	do {
554 555
		err = _nfs42_proc_clone(&msg, src_f, dst_f, src_lock, dst_lock,
					src_offset, dst_offset, count);
P
Peng Tao 已提交
556 557
		if (err == -ENOTSUPP || err == -EOPNOTSUPP) {
			NFS_SERVER(inode)->caps &= ~NFS_CAP_CLONE;
558 559
			err = -EOPNOTSUPP;
			break;
P
Peng Tao 已提交
560 561
		}

562 563 564 565 566
		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);
P
Peng Tao 已提交
567

568 569 570 571
	nfs_put_lock_context(dst_lock);
out_put_src_lock:
	nfs_put_lock_context(src_lock);
	return err;
P
Peng Tao 已提交
572
}