nfs42proc.c 14.2 KB
Newer Older
A
Anna Schumaker 已提交
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"
P
Peng Tao 已提交
13 14
#include "iostat.h"
#include "pnfs.h"
15
#include "nfs4session.h"
P
Peng Tao 已提交
16 17
#include "internal.h"

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

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

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

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

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

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

65 66 67 68 69 70 71
	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 已提交
72
	do {
73 74 75 76 77
		err = _nfs42_proc_fallocate(msg, filep, lock, offset, len);
		if (err == -ENOTSUPP) {
			err = -EOPNOTSUPP;
			break;
		}
A
Anna Schumaker 已提交
78 79 80
		err = nfs4_handle_exception(server, err, &exception);
	} while (exception.retry);

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

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

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

A
Anna Schumaker 已提交
106 107 108 109 110 111 112 113 114 115 116
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 已提交
117
	inode_lock(inode);
118 119 120
	err = nfs_sync_inode(inode);
	if (err)
		goto out_unlock;
121

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

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

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

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

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

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

	status = nfs4_call_sync(server->client, server, &msg,
171
				&args->seq_args, &res->seq_res, 0);
A
Anna Schumaker 已提交
172 173 174 175 176
	if (status == -ENOTSUPP)
		server->caps &= ~NFS_CAP_COPY;
	if (status)
		return status;

177 178
	if (res->write_res.verifier.committed != NFS_FILE_SYNC) {
		status = nfs_commit_file(dst, &res->write_res.verifier.verifier);
A
Anna Schumaker 已提交
179 180 181 182 183
		if (status)
			return status;
	}

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

186
	return res->write_res.count;
A
Anna Schumaker 已提交
187 188 189 190 191 192 193 194 195
}

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;
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
	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 已提交
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
	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 {
232
		inode_lock(file_inode(dst));
233 234 235
		err = _nfs42_proc_copy(src, src_lock,
				dst, dst_lock,
				&args, &res);
236
		inode_unlock(file_inode(dst));
A
Anna Schumaker 已提交
237

238 239
		if (err >= 0)
			break;
A
Anna Schumaker 已提交
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
		if (err == -ENOTSUPP) {
			err = -EOPNOTSUPP;
			break;
		}

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

257 258
static loff_t _nfs42_proc_llseek(struct file *filep,
		struct nfs_lock_context *lock, loff_t offset, int whence)
A
Anna Schumaker 已提交
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
{
	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;

276
	if (!nfs_server_capable(inode, NFS_CAP_SEEK))
A
Anna Schumaker 已提交
277 278
		return -ENOTSUPP;

279 280
	status = nfs4_set_rw_stateid(&args.sa_stateid, lock->open_context,
			lock, FMODE_READ);
A
Anna Schumaker 已提交
281 282 283
	if (status)
		return status;

284 285 286 287 288
	status = nfs_filemap_write_and_wait_range(inode->i_mapping,
			offset, LLONG_MAX);
	if (status)
		return status;

A
Anna Schumaker 已提交
289 290 291 292 293 294 295 296 297
	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);
}
298

299 300 301 302
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 = { };
303
	struct nfs_lock_context *lock;
304
	loff_t err;
305

306 307 308 309 310 311 312
	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;

313
	do {
314
		err = _nfs42_proc_llseek(filep, lock, offset, whence);
315 316
		if (err >= 0)
			break;
317 318 319 320
		if (err == -ENOTSUPP) {
			err = -EOPNOTSUPP;
			break;
		}
321 322 323
		err = nfs4_handle_exception(server, err, &exception);
	} while (exception.retry);

324
	nfs_put_lock_context(lock);
325 326 327 328
	return err;
}


P
Peng Tao 已提交
329 330 331 332
static void
nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata)
{
	struct nfs42_layoutstat_data *data = calldata;
333 334 335
	struct inode *inode = data->inode;
	struct nfs_server *server = NFS_SERVER(inode);
	struct pnfs_layout_hdr *lo;
P
Peng Tao 已提交
336

337 338 339 340 341 342 343 344 345
	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);
346 347
	nfs4_setup_sequence(server->nfs_client, &data->args.seq_args,
			    &data->res.seq_res, task);
P
Peng Tao 已提交
348 349 350 351 352 353
}

static void
nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
{
	struct nfs42_layoutstat_data *data = calldata;
P
Peng Tao 已提交
354 355
	struct inode *inode = data->inode;
	struct pnfs_layout_hdr *lo;
P
Peng Tao 已提交
356 357 358 359

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

360 361 362
	switch (task->tk_status) {
	case 0:
		break;
P
Peng Tao 已提交
363
	case -NFS4ERR_EXPIRED:
364 365
	case -NFS4ERR_ADMIN_REVOKED:
	case -NFS4ERR_DELEG_REVOKED:
P
Peng Tao 已提交
366 367 368 369
	case -NFS4ERR_STALE_STATEID:
	case -NFS4ERR_BAD_STATEID:
		spin_lock(&inode->i_lock);
		lo = NFS_I(inode)->layout;
370 371
		if (pnfs_layout_is_valid(lo) &&
		    nfs4_stateid_match(&data->args.stateid,
P
Peng Tao 已提交
372 373 374 375 376 377 378
					     &lo->plh_stateid)) {
			LIST_HEAD(head);

			/*
			 * Mark the bad layout state as invalid, then retry
			 * with the current stateid.
			 */
379
			pnfs_mark_layout_stateid_invalid(lo, &head);
P
Peng Tao 已提交
380 381
			spin_unlock(&inode->i_lock);
			pnfs_free_lseg_list(&head);
382
			nfs_commit_inode(inode, 0);
P
Peng Tao 已提交
383 384 385
		} else
			spin_unlock(&inode->i_lock);
		break;
386 387 388 389 390 391 392 393 394 395 396 397 398 399
	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;
400 401
	case -ENOTSUPP:
	case -EOPNOTSUPP:
P
Peng Tao 已提交
402
		NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTSTATS;
403
	}
P
Peng Tao 已提交
404 405 406 407 408 409
}

static void
nfs42_layoutstat_release(void *calldata)
{
	struct nfs42_layoutstat_data *data = calldata;
410 411
	struct nfs42_layoutstat_devinfo *devinfo = data->args.devinfo;
	int i;
412

413 414 415 416
	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 已提交
417 418

	pnfs_put_layout_hdr(NFS_I(data->args.inode)->layout);
419 420 421
	smp_mb__before_atomic();
	clear_bit(NFS_INO_LAYOUTSTATS, &NFS_I(data->args.inode)->flags);
	smp_mb__after_atomic();
P
Peng Tao 已提交
422 423 424 425 426
	nfs_iput_and_deactive(data->inode);
	kfree(data->args.devinfo);
	kfree(data);
}

427
static const struct rpc_call_ops nfs42_layoutstat_ops = {
P
Peng Tao 已提交
428 429 430
	.rpc_call_prepare = nfs42_layoutstat_prepare,
	.rpc_call_done = nfs42_layoutstat_done,
	.rpc_release = nfs42_layoutstat_release,
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
};

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 已提交
450 451 452 453 454
	data->inode = nfs_igrab_and_active(data->args.inode);
	if (!data->inode) {
		nfs42_layoutstat_release(data);
		return -EAGAIN;
	}
455 456 457 458
	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);
459
	rpc_put_task(task);
460 461
	return 0;
}
P
Peng Tao 已提交
462 463

static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
464 465 466
		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 已提交
467 468 469 470 471 472 473 474 475
{
	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,
476
		.count = count,
P
Peng Tao 已提交
477 478 479 480 481 482 483 484 485 486
		.dst_bitmask = server->cache_consistency_bitmask,
	};
	struct nfs42_clone_res res = {
		.server	= server,
	};
	int status;

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

487 488
	status = nfs4_set_rw_stateid(&args.src_stateid, src_lock->open_context,
			src_lock, FMODE_READ);
P
Peng Tao 已提交
489 490 491
	if (status)
		return status;

492 493
	status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context,
			dst_lock, FMODE_WRITE);
P
Peng Tao 已提交
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
	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));
518 519 520 521 522
	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 已提交
523 524 525 526

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

527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
	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 已提交
543
	do {
544 545
		err = _nfs42_proc_clone(&msg, src_f, dst_f, src_lock, dst_lock,
					src_offset, dst_offset, count);
P
Peng Tao 已提交
546 547
		if (err == -ENOTSUPP || err == -EOPNOTSUPP) {
			NFS_SERVER(inode)->caps &= ~NFS_CAP_CLONE;
548 549
			err = -EOPNOTSUPP;
			break;
P
Peng Tao 已提交
550 551
		}

552 553 554 555 556
		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 已提交
557

558 559 560 561
	nfs_put_lock_context(dst_lock);
out_put_src_lock:
	nfs_put_lock_context(src_lock);
	return err;
P
Peng Tao 已提交
562
}