dir.c 31.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* dir.c: AFS filesystem directory handling
 *
 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
16
#include <linux/namei.h>
L
Linus Torvalds 已提交
17
#include <linux/pagemap.h>
D
David Howells 已提交
18
#include <linux/ctype.h>
A
Alexey Dobriyan 已提交
19
#include <linux/sched.h>
20
#include <linux/dns_resolver.h>
L
Linus Torvalds 已提交
21 22
#include "internal.h"

23
static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
A
Al Viro 已提交
24
				 unsigned int flags);
25 26
static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
					 unsigned int flags);
L
Linus Torvalds 已提交
27
static int afs_dir_open(struct inode *inode, struct file *file);
A
Al Viro 已提交
28
static int afs_readdir(struct file *file, struct dir_context *ctx);
29
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
N
Nick Piggin 已提交
30
static int afs_d_delete(const struct dentry *dentry);
31
static void afs_d_release(struct dentry *dentry);
32
static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen,
33
				  loff_t fpos, u64 ino, unsigned dtype);
A
Al Viro 已提交
34
static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
A
Al Viro 已提交
35
		      bool excl);
36
static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
37 38 39 40 41 42 43
static int afs_rmdir(struct inode *dir, struct dentry *dentry);
static int afs_unlink(struct inode *dir, struct dentry *dentry);
static int afs_link(struct dentry *from, struct inode *dir,
		    struct dentry *dentry);
static int afs_symlink(struct inode *dir, struct dentry *dentry,
		       const char *content);
static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
44 45
		      struct inode *new_dir, struct dentry *new_dentry,
		      unsigned int flags);
L
Linus Torvalds 已提交
46

47
const struct file_operations afs_dir_file_operations = {
L
Linus Torvalds 已提交
48
	.open		= afs_dir_open,
D
David Howells 已提交
49
	.release	= afs_release,
A
Al Viro 已提交
50
	.iterate_shared	= afs_readdir,
D
David Howells 已提交
51
	.lock		= afs_lock,
52
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
53 54
};

55
const struct inode_operations afs_dir_inode_operations = {
56 57 58 59 60 61 62
	.create		= afs_create,
	.lookup		= afs_lookup,
	.link		= afs_link,
	.unlink		= afs_unlink,
	.symlink	= afs_symlink,
	.mkdir		= afs_mkdir,
	.rmdir		= afs_rmdir,
63
	.rename		= afs_rename,
D
David Howells 已提交
64
	.permission	= afs_permission,
D
David Howells 已提交
65
	.getattr	= afs_getattr,
66
	.setattr	= afs_setattr,
D
David Howells 已提交
67
	.listxattr	= afs_listxattr,
L
Linus Torvalds 已提交
68 69
};

70 71 72 73 74 75 76 77 78 79 80
const struct file_operations afs_dynroot_file_operations = {
	.open		= dcache_dir_open,
	.release	= dcache_dir_close,
	.iterate_shared	= dcache_readdir,
	.llseek		= dcache_dir_lseek,
};

const struct inode_operations afs_dynroot_inode_operations = {
	.lookup		= afs_dynroot_lookup,
};

A
Al Viro 已提交
81
const struct dentry_operations afs_fs_dentry_operations = {
L
Linus Torvalds 已提交
82 83
	.d_revalidate	= afs_d_revalidate,
	.d_delete	= afs_d_delete,
84
	.d_release	= afs_d_release,
85
	.d_automount	= afs_d_automount,
L
Linus Torvalds 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
};

#define AFS_DIR_HASHTBL_SIZE	128
#define AFS_DIR_DIRENT_SIZE	32
#define AFS_DIRENT_PER_BLOCK	64

union afs_dirent {
	struct {
		uint8_t		valid;
		uint8_t		unused[1];
		__be16		hash_next;
		__be32		vnode;
		__be32		unique;
		uint8_t		name[16];
		uint8_t		overflow[4];	/* if any char of the name (inc
						 * NUL) reaches here, consume
						 * the next dirent too */
	} u;
	uint8_t	extended_name[32];
};

/* AFS directory page header (one at the beginning of every 2048-byte chunk) */
struct afs_dir_pagehdr {
	__be16		npages;
	__be16		magic;
#define AFS_DIR_MAGIC htons(1234)
	uint8_t		nentries;
	uint8_t		bitmap[8];
	uint8_t		pad[19];
};

/* directory block layout */
union afs_dir_block {

	struct afs_dir_pagehdr pagehdr;

	struct {
		struct afs_dir_pagehdr	pagehdr;
		uint8_t			alloc_ctrs[128];
		/* dir hash table */
		uint16_t		hashtable[AFS_DIR_HASHTBL_SIZE];
	} hdr;

	union afs_dirent dirents[AFS_DIRENT_PER_BLOCK];
};

/* layout on a linux VM page */
struct afs_dir_page {
	union afs_dir_block blocks[PAGE_SIZE / sizeof(union afs_dir_block)];
};

137
struct afs_lookup_cookie {
A
Al Viro 已提交
138
	struct dir_context ctx;
L
Linus Torvalds 已提交
139
	struct afs_fid	fid;
A
Al Viro 已提交
140
	struct qstr name;
L
Linus Torvalds 已提交
141 142 143 144 145 146
	int		found;
};

/*
 * check that a directory page is valid
 */
147
bool afs_dir_check_page(struct inode *dir, struct page *page)
L
Linus Torvalds 已提交
148 149
{
	struct afs_dir_page *dbuf;
150 151
	struct afs_vnode *vnode = AFS_FS_I(dir);
	loff_t latter, i_size, off;
L
Linus Torvalds 已提交
152 153 154 155 156 157 158 159
	int tmp, qty;

#if 0
	/* check the page count */
	qty = desc.size / sizeof(dbuf->blocks[0]);
	if (qty == 0)
		goto error;

160
	if (page->index == 0 && qty != ntohs(dbuf->blocks[0].pagehdr.npages)) {
L
Linus Torvalds 已提交
161
		printk("kAFS: %s(%lu): wrong number of dir blocks %d!=%hu\n",
162
		       __func__, dir->i_ino, qty,
163
		       ntohs(dbuf->blocks[0].pagehdr.npages));
L
Linus Torvalds 已提交
164 165 166 167
		goto error;
	}
#endif

168 169 170 171 172 173 174 175 176
	/* Determine how many magic numbers there should be in this page, but
	 * we must take care because the directory may change size under us.
	 */
	off = page_offset(page);
	i_size = i_size_read(dir);
	if (i_size <= off)
		goto checked;

	latter = i_size - off;
L
Linus Torvalds 已提交
177 178 179 180 181 182 183 184 185 186
	if (latter >= PAGE_SIZE)
		qty = PAGE_SIZE;
	else
		qty = latter;
	qty /= sizeof(union afs_dir_block);

	/* check them */
	dbuf = page_address(page);
	for (tmp = 0; tmp < qty; tmp++) {
		if (dbuf->blocks[tmp].pagehdr.magic != AFS_DIR_MAGIC) {
187
			printk("kAFS: %s(%lx): bad magic %d/%d is %04hx\n",
188
			       __func__, dir->i_ino, tmp, qty,
L
Linus Torvalds 已提交
189
			       ntohs(dbuf->blocks[tmp].pagehdr.magic));
190
			trace_afs_dir_check_failed(vnode, off, i_size);
L
Linus Torvalds 已提交
191 192 193 194
			goto error;
		}
	}

195
checked:
L
Linus Torvalds 已提交
196
	SetPageChecked(page);
197
	return true;
L
Linus Torvalds 已提交
198

D
David Howells 已提交
199
error:
L
Linus Torvalds 已提交
200
	SetPageError(page);
201
	return false;
D
David Howells 已提交
202
}
L
Linus Torvalds 已提交
203 204 205 206 207 208 209

/*
 * discard a page cached in the pagecache
 */
static inline void afs_dir_put_page(struct page *page)
{
	kunmap(page);
210
	unlock_page(page);
211
	put_page(page);
D
David Howells 已提交
212
}
L
Linus Torvalds 已提交
213 214 215 216

/*
 * get a page into the pagecache
 */
D
David Howells 已提交
217 218
static struct page *afs_dir_get_page(struct inode *dir, unsigned long index,
				     struct key *key)
L
Linus Torvalds 已提交
219 220 221 222
{
	struct page *page;
	_enter("{%lu},%lu", dir->i_ino, index);

223
	page = read_cache_page(dir->i_mapping, index, afs_page_filler, key);
L
Linus Torvalds 已提交
224
	if (!IS_ERR(page)) {
225
		lock_page(page);
L
Linus Torvalds 已提交
226
		kmap(page);
227
		if (unlikely(!PageChecked(page))) {
228
			if (PageError(page))
229 230
				goto fail;
		}
L
Linus Torvalds 已提交
231 232 233
	}
	return page;

D
David Howells 已提交
234
fail:
L
Linus Torvalds 已提交
235
	afs_dir_put_page(page);
236
	_leave(" = -EIO");
L
Linus Torvalds 已提交
237
	return ERR_PTR(-EIO);
D
David Howells 已提交
238
}
L
Linus Torvalds 已提交
239 240 241 242 243 244 245 246

/*
 * open an AFS directory file
 */
static int afs_dir_open(struct inode *inode, struct file *file)
{
	_enter("{%lu}", inode->i_ino);

A
Alexey Dobriyan 已提交
247 248
	BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
	BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
L
Linus Torvalds 已提交
249

250
	if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags))
L
Linus Torvalds 已提交
251 252
		return -ENOENT;

D
David Howells 已提交
253
	return afs_open(inode, file);
D
David Howells 已提交
254
}
L
Linus Torvalds 已提交
255 256 257 258

/*
 * deal with one block in an AFS directory
 */
A
Al Viro 已提交
259
static int afs_dir_iterate_block(struct dir_context *ctx,
L
Linus Torvalds 已提交
260
				 union afs_dir_block *block,
A
Al Viro 已提交
261
				 unsigned blkoff)
L
Linus Torvalds 已提交
262 263 264 265
{
	union afs_dirent *dire;
	unsigned offset, next, curr;
	size_t nlen;
A
Al Viro 已提交
266
	int tmp;
L
Linus Torvalds 已提交
267

A
Al Viro 已提交
268
	_enter("%u,%x,%p,,",(unsigned)ctx->pos,blkoff,block);
L
Linus Torvalds 已提交
269

A
Al Viro 已提交
270
	curr = (ctx->pos - blkoff) / sizeof(union afs_dirent);
L
Linus Torvalds 已提交
271 272 273 274 275 276 277 278 279 280 281

	/* walk through the block, an entry at a time */
	for (offset = AFS_DIRENT_PER_BLOCK - block->pagehdr.nentries;
	     offset < AFS_DIRENT_PER_BLOCK;
	     offset = next
	     ) {
		next = offset + 1;

		/* skip entries marked unused in the bitmap */
		if (!(block->pagehdr.bitmap[offset / 8] &
		      (1 << (offset % 8)))) {
282
			_debug("ENT[%zu.%u]: unused",
L
Linus Torvalds 已提交
283 284
			       blkoff / sizeof(union afs_dir_block), offset);
			if (offset >= curr)
A
Al Viro 已提交
285
				ctx->pos = blkoff +
L
Linus Torvalds 已提交
286 287 288 289 290 291 292 293 294 295
					next * sizeof(union afs_dirent);
			continue;
		}

		/* got a valid entry */
		dire = &block->dirents[offset];
		nlen = strnlen(dire->u.name,
			       sizeof(*block) -
			       offset * sizeof(union afs_dirent));

296
		_debug("ENT[%zu.%u]: %s %zu \"%s\"",
L
Linus Torvalds 已提交
297 298 299 300 301 302 303
		       blkoff / sizeof(union afs_dir_block), offset,
		       (offset < curr ? "skip" : "fill"),
		       nlen, dire->u.name);

		/* work out where the next possible entry is */
		for (tmp = nlen; tmp > 15; tmp -= sizeof(union afs_dirent)) {
			if (next >= AFS_DIRENT_PER_BLOCK) {
304
				_debug("ENT[%zu.%u]:"
L
Linus Torvalds 已提交
305
				       " %u travelled beyond end dir block"
306
				       " (len %u/%zu)",
L
Linus Torvalds 已提交
307 308 309 310 311 312
				       blkoff / sizeof(union afs_dir_block),
				       offset, next, tmp, nlen);
				return -EIO;
			}
			if (!(block->pagehdr.bitmap[next / 8] &
			      (1 << (next % 8)))) {
313 314
				_debug("ENT[%zu.%u]:"
				       " %u unmarked extension (len %u/%zu)",
L
Linus Torvalds 已提交
315 316 317 318 319
				       blkoff / sizeof(union afs_dir_block),
				       offset, next, tmp, nlen);
				return -EIO;
			}

320
			_debug("ENT[%zu.%u]: ext %u/%zu",
L
Linus Torvalds 已提交
321 322 323 324 325 326 327 328 329 330
			       blkoff / sizeof(union afs_dir_block),
			       next, tmp, nlen);
			next++;
		}

		/* skip if starts before the current position */
		if (offset < curr)
			continue;

		/* found the next entry */
A
Al Viro 已提交
331
		if (!dir_emit(ctx, dire->u.name, nlen,
L
Linus Torvalds 已提交
332
			      ntohl(dire->u.vnode),
A
Al Viro 已提交
333 334
			      ctx->actor == afs_lookup_filldir ?
			      ntohl(dire->u.unique) : DT_UNKNOWN)) {
L
Linus Torvalds 已提交
335 336 337 338
			_leave(" = 0 [full]");
			return 0;
		}

A
Al Viro 已提交
339
		ctx->pos = blkoff + next * sizeof(union afs_dirent);
L
Linus Torvalds 已提交
340 341 342 343
	}

	_leave(" = 1 [more]");
	return 1;
D
David Howells 已提交
344
}
L
Linus Torvalds 已提交
345 346

/*
347
 * iterate through the data blob that lists the contents of an AFS directory
L
Linus Torvalds 已提交
348
 */
A
Al Viro 已提交
349 350
static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
			   struct key *key)
L
Linus Torvalds 已提交
351
{
352
	union afs_dir_block *dblock;
L
Linus Torvalds 已提交
353 354 355 356 357
	struct afs_dir_page *dbuf;
	struct page *page;
	unsigned blkoff, limit;
	int ret;

A
Al Viro 已提交
358
	_enter("{%lu},%u,,", dir->i_ino, (unsigned)ctx->pos);
L
Linus Torvalds 已提交
359

360
	if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) {
L
Linus Torvalds 已提交
361 362 363 364 365
		_leave(" = -ESTALE");
		return -ESTALE;
	}

	/* round the file position up to the next entry boundary */
A
Al Viro 已提交
366 367
	ctx->pos += sizeof(union afs_dirent) - 1;
	ctx->pos &= ~(sizeof(union afs_dirent) - 1);
L
Linus Torvalds 已提交
368 369 370

	/* walk through the blocks in sequence */
	ret = 0;
A
Al Viro 已提交
371 372
	while (ctx->pos < dir->i_size) {
		blkoff = ctx->pos & ~(sizeof(union afs_dir_block) - 1);
L
Linus Torvalds 已提交
373 374

		/* fetch the appropriate page from the directory */
D
David Howells 已提交
375
		page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key);
L
Linus Torvalds 已提交
376 377 378 379 380 381 382 383 384 385 386 387 388
		if (IS_ERR(page)) {
			ret = PTR_ERR(page);
			break;
		}

		limit = blkoff & ~(PAGE_SIZE - 1);

		dbuf = page_address(page);

		/* deal with the individual blocks stashed on this page */
		do {
			dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) /
					       sizeof(union afs_dir_block)];
A
Al Viro 已提交
389
			ret = afs_dir_iterate_block(ctx, dblock, blkoff);
L
Linus Torvalds 已提交
390 391 392 393 394 395 396
			if (ret != 1) {
				afs_dir_put_page(page);
				goto out;
			}

			blkoff += sizeof(union afs_dir_block);

A
Al Viro 已提交
397
		} while (ctx->pos < dir->i_size && blkoff < limit);
L
Linus Torvalds 已提交
398 399 400 401 402

		afs_dir_put_page(page);
		ret = 0;
	}

D
David Howells 已提交
403
out:
L
Linus Torvalds 已提交
404 405
	_leave(" = %d", ret);
	return ret;
D
David Howells 已提交
406
}
L
Linus Torvalds 已提交
407 408 409 410

/*
 * read an AFS directory
 */
A
Al Viro 已提交
411
static int afs_readdir(struct file *file, struct dir_context *ctx)
L
Linus Torvalds 已提交
412
{
413
	return afs_dir_iterate(file_inode(file), ctx, afs_file_key(file));
D
David Howells 已提交
414
}
L
Linus Torvalds 已提交
415 416 417 418 419 420

/*
 * search the directory for a name
 * - if afs_dir_iterate_block() spots this function, it'll pass the FID
 *   uniquifier through dtype
 */
421 422
static int afs_lookup_filldir(struct dir_context *ctx, const char *name,
			      int nlen, loff_t fpos, u64 ino, unsigned dtype)
L
Linus Torvalds 已提交
423
{
424 425
	struct afs_lookup_cookie *cookie =
		container_of(ctx, struct afs_lookup_cookie, ctx);
L
Linus Torvalds 已提交
426

A
Al Viro 已提交
427 428
	_enter("{%s,%u},%s,%u,,%llu,%u",
	       cookie->name.name, cookie->name.len, name, nlen,
429
	       (unsigned long long) ino, dtype);
L
Linus Torvalds 已提交
430

431 432 433 434
	/* insanity checks first */
	BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
	BUILD_BUG_ON(sizeof(union afs_dirent) != 32);

A
Al Viro 已提交
435 436
	if (cookie->name.len != nlen ||
	    memcmp(cookie->name.name, name, nlen) != 0) {
L
Linus Torvalds 已提交
437 438 439 440 441 442 443 444 445 446
		_leave(" = 0 [no]");
		return 0;
	}

	cookie->fid.vnode = ino;
	cookie->fid.unique = dtype;
	cookie->found = 1;

	_leave(" = -1 [found]");
	return -1;
D
David Howells 已提交
447
}
L
Linus Torvalds 已提交
448 449

/*
450
 * do a lookup in a directory
451
 * - just returns the FID the dentry name maps to if found
L
Linus Torvalds 已提交
452
 */
453
static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
D
David Howells 已提交
454
			 struct afs_fid *fid, struct key *key)
L
Linus Torvalds 已提交
455
{
A
Al Viro 已提交
456 457 458 459 460 461
	struct afs_super_info *as = dir->i_sb->s_fs_info;
	struct afs_lookup_cookie cookie = {
		.ctx.actor = afs_lookup_filldir,
		.name = dentry->d_name,
		.fid.vid = as->volume->vid
	};
L
Linus Torvalds 已提交
462 463
	int ret;

A
Al Viro 已提交
464
	_enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry);
L
Linus Torvalds 已提交
465 466

	/* search the directory */
A
Al Viro 已提交
467
	ret = afs_dir_iterate(dir, &cookie.ctx, key);
L
Linus Torvalds 已提交
468
	if (ret < 0) {
469 470
		_leave(" = %d [iter]", ret);
		return ret;
L
Linus Torvalds 已提交
471 472 473 474
	}

	ret = -ENOENT;
	if (!cookie.found) {
475 476
		_leave(" = -ENOENT [not found]");
		return -ENOENT;
L
Linus Torvalds 已提交
477 478
	}

479 480 481 482 483
	*fid = cookie.fid;
	_leave(" = 0 { vn=%u u=%u }", fid->vnode, fid->unique);
	return 0;
}

484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
/*
 * Probe to see if a cell may exist.  This prevents positive dentries from
 * being created unnecessarily.
 */
static int afs_probe_cell_name(struct dentry *dentry)
{
	struct afs_cell *cell;
	const char *name = dentry->d_name.name;
	size_t len = dentry->d_name.len;
	int ret;

	/* Names prefixed with a dot are R/W mounts. */
	if (name[0] == '.') {
		if (len == 1)
			return -EINVAL;
		name++;
		len--;
	}

	cell = afs_lookup_cell_rcu(afs_d2net(dentry), name, len);
	if (!IS_ERR(cell)) {
		afs_put_cell(afs_d2net(dentry), cell);
		return 0;
	}

	ret = dns_query("afsdb", name, len, "ipv4", NULL, NULL);
	if (ret == -ENODATA)
		ret = -EDESTADDRREQ;
	return ret;
}

515 516 517 518
/*
 * Try to auto mount the mountpoint with pseudo directory, if the autocell
 * operation is setted.
 */
519 520
static struct inode *afs_try_auto_mntpt(struct dentry *dentry,
					struct inode *dir, struct afs_fid *fid)
521 522 523
{
	struct afs_vnode *vnode = AFS_FS_I(dir);
	struct inode *inode;
524
	int ret = -ENOENT;
525

526 527 528 529 530
	_enter("%p{%pd}, {%x:%u}",
	       dentry, dentry, vnode->fid.vid, vnode->fid.vnode);

	if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
		goto out;
531

532 533
	ret = afs_probe_cell_name(dentry);
	if (ret < 0)
534 535
		goto out;

536
	inode = afs_iget_pseudo_dir(dir->i_sb, false);
537 538 539 540 541 542 543 544 545 546 547 548 549 550
	if (IS_ERR(inode)) {
		ret = PTR_ERR(inode);
		goto out;
	}

	*fid = AFS_FS_I(inode)->fid;
	_leave("= %p", inode);
	return inode;

out:
	_leave("= %d", ret);
	return ERR_PTR(ret);
}

551 552 553
/*
 * look up an entry in a directory
 */
554
static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
A
Al Viro 已提交
555
				 unsigned int flags)
556 557 558 559
{
	struct afs_vnode *vnode;
	struct afs_fid fid;
	struct inode *inode;
D
David Howells 已提交
560
	struct key *key;
561 562
	int ret;

563 564
	vnode = AFS_FS_I(dir);

A
Al Viro 已提交
565 566
	_enter("{%x:%u},%p{%pd},",
	       vnode->fid.vid, vnode->fid.vnode, dentry, dentry);
567

568
	ASSERTCMP(d_inode(dentry), ==, NULL);
569

D
David Howells 已提交
570
	if (dentry->d_name.len >= AFSNAMEMAX) {
571 572 573 574 575 576 577 578 579
		_leave(" = -ENAMETOOLONG");
		return ERR_PTR(-ENAMETOOLONG);
	}

	if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
		_leave(" = -ESTALE");
		return ERR_PTR(-ESTALE);
	}

D
David Howells 已提交
580 581 582
	key = afs_request_key(vnode->volume->cell);
	if (IS_ERR(key)) {
		_leave(" = %ld [key]", PTR_ERR(key));
583
		return ERR_CAST(key);
D
David Howells 已提交
584 585
	}

586 587 588 589 590 591 592
	ret = afs_validate(vnode, key);
	if (ret < 0) {
		key_put(key);
		_leave(" = %d [val]", ret);
		return ERR_PTR(ret);
	}

D
David Howells 已提交
593
	ret = afs_do_lookup(dir, dentry, &fid, key);
L
Linus Torvalds 已提交
594
	if (ret < 0) {
595 596 597 598 599 600 601 602
		if (ret == -ENOENT) {
			inode = afs_try_auto_mntpt(dentry, dir, &fid);
			if (!IS_ERR(inode)) {
				key_put(key);
				goto success;
			}

			ret = PTR_ERR(inode);
603 604
		}

D
David Howells 已提交
605
		key_put(key);
606 607 608 609 610
		if (ret == -ENOENT) {
			d_add(dentry, NULL);
			_leave(" = NULL [negative]");
			return NULL;
		}
611
		_leave(" = %d [do]", ret);
L
Linus Torvalds 已提交
612 613
		return ERR_PTR(ret);
	}
614
	dentry->d_fsdata = (void *)(unsigned long) vnode->status.data_version;
L
Linus Torvalds 已提交
615

616
	/* instantiate the dentry */
617
	inode = afs_iget(dir->i_sb, key, &fid, NULL, NULL, NULL);
D
David Howells 已提交
618
	key_put(key);
619 620
	if (IS_ERR(inode)) {
		_leave(" = %ld", PTR_ERR(inode));
621
		return ERR_CAST(inode);
622 623
	}

624
success:
L
Linus Torvalds 已提交
625
	d_add(dentry, inode);
626
	_leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%u }",
627 628
	       fid.vnode,
	       fid.unique,
629 630
	       d_inode(dentry)->i_ino,
	       d_inode(dentry)->i_generation);
L
Linus Torvalds 已提交
631 632

	return NULL;
D
David Howells 已提交
633
}
L
Linus Torvalds 已提交
634

635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
/*
 * Look up an entry in a dynroot directory.
 */
static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
					 unsigned int flags)
{
	struct afs_vnode *vnode;
	struct afs_fid fid;
	struct inode *inode;
	int ret;

	vnode = AFS_FS_I(dir);

	_enter("%pd", dentry);

	ASSERTCMP(d_inode(dentry), ==, NULL);

	if (dentry->d_name.len >= AFSNAMEMAX) {
		_leave(" = -ENAMETOOLONG");
		return ERR_PTR(-ENAMETOOLONG);
	}

	inode = afs_try_auto_mntpt(dentry, dir, &fid);
	if (IS_ERR(inode)) {
		ret = PTR_ERR(inode);
		if (ret == -ENOENT) {
			d_add(dentry, NULL);
			_leave(" = NULL [negative]");
			return NULL;
		}
		_leave(" = %d [do]", ret);
		return ERR_PTR(ret);
	}

	d_add(dentry, inode);
	_leave(" = 0 { ino=%lu v=%u }",
	       d_inode(dentry)->i_ino, d_inode(dentry)->i_generation);
	return NULL;
}

L
Linus Torvalds 已提交
675 676 677 678 679
/*
 * check that a dentry lookup hit has found a valid entry
 * - NOTE! the hit can be a negative hit too, so we can't assume we have an
 *   inode
 */
680
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
L
Linus Torvalds 已提交
681
{
682
	struct afs_super_info *as = dentry->d_sb->s_fs_info;
683
	struct afs_vnode *vnode, *dir;
A
Artem Bityutskiy 已提交
684
	struct afs_fid uninitialized_var(fid);
L
Linus Torvalds 已提交
685
	struct dentry *parent;
686
	struct inode *inode;
D
David Howells 已提交
687
	struct key *key;
688
	void *dir_version;
L
Linus Torvalds 已提交
689 690
	int ret;

691
	if (flags & LOOKUP_RCU)
692 693
		return -ECHILD;

694 695 696
	if (as->dyn_root)
		return 1;

697 698
	if (d_really_is_positive(dentry)) {
		vnode = AFS_FS_I(d_inode(dentry));
A
Al Viro 已提交
699 700
		_enter("{v={%x:%u} n=%pd fl=%lx},",
		       vnode->fid.vid, vnode->fid.vnode, dentry,
701
		       vnode->flags);
702
	} else {
A
Al Viro 已提交
703
		_enter("{neg n=%pd}", dentry);
704
	}
L
Linus Torvalds 已提交
705

706
	key = afs_request_key(AFS_FS_S(dentry->d_sb)->volume->cell);
D
David Howells 已提交
707 708 709
	if (IS_ERR(key))
		key = NULL;

710 711 712 713 714 715 716 717 718 719
	if (d_really_is_positive(dentry)) {
		inode = d_inode(dentry);
		if (inode) {
			vnode = AFS_FS_I(inode);
			afs_validate(vnode, key);
			if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
				goto out_bad;
		}
	}

L
Linus Torvalds 已提交
720
	/* lock down the parent dentry so we can peer at it */
721
	parent = dget_parent(dentry);
722
	dir = AFS_FS_I(d_inode(parent));
L
Linus Torvalds 已提交
723

724
	/* validate the parent directory */
725
	afs_validate(dir, key);
726 727

	if (test_bit(AFS_VNODE_DELETED, &dir->flags)) {
A
Al Viro 已提交
728
		_debug("%pd: parent dir deleted", dentry);
729
		goto out_bad_parent;
L
Linus Torvalds 已提交
730 731
	}

732 733 734
	dir_version = (void *) (unsigned long) dir->status.data_version;
	if (dentry->d_fsdata == dir_version)
		goto out_valid; /* the dir contents are unchanged */
L
Linus Torvalds 已提交
735

736 737 738 739 740 741 742
	_debug("dir modified");

	/* search the directory for this vnode */
	ret = afs_do_lookup(&dir->vfs_inode, dentry, &fid, key);
	switch (ret) {
	case 0:
		/* the filename maps to something */
743
		if (d_really_is_negative(dentry))
744 745 746
			goto out_bad_parent;
		inode = d_inode(dentry);
		if (is_bad_inode(inode)) {
A
Al Viro 已提交
747 748
			printk("kAFS: afs_d_revalidate: %pd2 has bad inode\n",
			       dentry);
749
			goto out_bad_parent;
L
Linus Torvalds 已提交
750 751
		}

752 753
		vnode = AFS_FS_I(inode);

L
Linus Torvalds 已提交
754 755
		/* if the vnode ID has changed, then the dirent points to a
		 * different file */
756
		if (fid.vnode != vnode->fid.vnode) {
A
Al Viro 已提交
757 758
			_debug("%pd: dirent changed [%u != %u]",
			       dentry, fid.vnode,
759
			       vnode->fid.vnode);
L
Linus Torvalds 已提交
760 761 762 763
			goto not_found;
		}

		/* if the vnode ID uniqifier has changed, then the file has
764 765
		 * been deleted and replaced, and the original vnode ID has
		 * been reused */
766
		if (fid.unique != vnode->fid.unique) {
A
Al Viro 已提交
767 768
			_debug("%pd: file deleted (uq %u -> %u I:%u)",
			       dentry, fid.unique,
769
			       vnode->fid.unique,
770 771
			       vnode->vfs_inode.i_generation);
			write_seqlock(&vnode->cb_lock);
772
			set_bit(AFS_VNODE_DELETED, &vnode->flags);
773
			write_sequnlock(&vnode->cb_lock);
774
			goto not_found;
L
Linus Torvalds 已提交
775
		}
776
		goto out_valid;
777

778 779
	case -ENOENT:
		/* the filename is unknown */
A
Al Viro 已提交
780
		_debug("%pd: dirent not found", dentry);
781
		if (d_really_is_positive(dentry))
782 783
			goto not_found;
		goto out_valid;
L
Linus Torvalds 已提交
784

785
	default:
A
Al Viro 已提交
786 787
		_debug("failed to iterate dir %pd: %d",
		       parent, ret);
788
		goto out_bad_parent;
789 790
	}

D
David Howells 已提交
791
out_valid:
792
	dentry->d_fsdata = dir_version;
L
Linus Torvalds 已提交
793
	dput(parent);
D
David Howells 已提交
794
	key_put(key);
L
Linus Torvalds 已提交
795 796 797 798
	_leave(" = 1 [valid]");
	return 1;

	/* the dirent, if it exists, now points to a different vnode */
D
David Howells 已提交
799
not_found:
L
Linus Torvalds 已提交
800 801 802 803
	spin_lock(&dentry->d_lock);
	dentry->d_flags |= DCACHE_NFSFS_RENAMED;
	spin_unlock(&dentry->d_lock);

804
out_bad_parent:
A
Al Viro 已提交
805
	_debug("dropping dentry %pd2", dentry);
L
Linus Torvalds 已提交
806
	dput(parent);
807
out_bad:
D
David Howells 已提交
808
	key_put(key);
L
Linus Torvalds 已提交
809 810 811

	_leave(" = 0 [bad]");
	return 0;
D
David Howells 已提交
812
}
L
Linus Torvalds 已提交
813 814 815 816 817 818 819

/*
 * allow the VFS to enquire as to whether a dentry should be unhashed (mustn't
 * sleep)
 * - called from dput() when d_count is going to 0.
 * - return 1 to request dentry be unhashed, 0 otherwise
 */
N
Nick Piggin 已提交
820
static int afs_d_delete(const struct dentry *dentry)
L
Linus Torvalds 已提交
821
{
A
Al Viro 已提交
822
	_enter("%pd", dentry);
L
Linus Torvalds 已提交
823 824 825 826

	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
		goto zap;

827 828 829
	if (d_really_is_positive(dentry) &&
	    (test_bit(AFS_VNODE_DELETED,   &AFS_FS_I(d_inode(dentry))->flags) ||
	     test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(d_inode(dentry))->flags)))
830
		goto zap;
L
Linus Torvalds 已提交
831 832 833 834

	_leave(" = 0 [keep]");
	return 0;

D
David Howells 已提交
835
zap:
L
Linus Torvalds 已提交
836 837
	_leave(" = 1 [zap]");
	return 1;
D
David Howells 已提交
838
}
839 840 841 842 843 844

/*
 * handle dentry release
 */
static void afs_d_release(struct dentry *dentry)
{
A
Al Viro 已提交
845
	_enter("%pd", dentry);
846 847
}

848 849 850 851 852 853 854 855 856 857 858 859 860 861
/*
 * Create a new inode for create/mkdir/symlink
 */
static void afs_vnode_new_inode(struct afs_fs_cursor *fc,
				struct dentry *new_dentry,
				struct afs_fid *newfid,
				struct afs_file_status *newstatus,
				struct afs_callback *newcb)
{
	struct inode *inode;

	if (fc->ac.error < 0)
		return;

862 863
	d_drop(new_dentry);

864 865 866 867 868 869 870 871 872 873
	inode = afs_iget(fc->vnode->vfs_inode.i_sb, fc->key,
			 newfid, newstatus, newcb, fc->cbi);
	if (IS_ERR(inode)) {
		/* ENOMEM or EINTR at a really inconvenient time - just abandon
		 * the new directory on the server.
		 */
		fc->ac.error = PTR_ERR(inode);
		return;
	}

874
	d_add(new_dentry, inode);
875 876
}

877 878 879
/*
 * create a directory on an AFS filesystem
 */
880
static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
881
{
882 883 884 885 886
	struct afs_file_status newstatus;
	struct afs_fs_cursor fc;
	struct afs_callback newcb;
	struct afs_vnode *dvnode = AFS_FS_I(dir);
	struct afs_fid newfid;
887 888 889
	struct key *key;
	int ret;

890
	mode |= S_IFDIR;
891

A
Al Viro 已提交
892 893
	_enter("{%x:%u},{%pd},%ho",
	       dvnode->fid.vid, dvnode->fid.vnode, dentry, mode);
894 895 896 897 898 899 900

	key = afs_request_key(dvnode->volume->cell);
	if (IS_ERR(key)) {
		ret = PTR_ERR(key);
		goto error;
	}

901 902 903 904 905 906 907
	ret = -ERESTARTSYS;
	if (afs_begin_vnode_operation(&fc, dvnode, key)) {
		while (afs_select_fileserver(&fc)) {
			fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
			afs_fs_create(&fc, dentry->d_name.name, mode,
				      &newfid, &newstatus, &newcb);
		}
908

909 910 911 912 913 914
		afs_check_for_remote_deletion(&fc, fc.vnode);
		afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
		afs_vnode_new_inode(&fc, dentry, &newfid, &newstatus, &newcb);
		ret = afs_end_vnode_operation(&fc);
		if (ret < 0)
			goto error_key;
915 916
	} else {
		goto error_key;
917 918 919 920 921 922
	}

	key_put(key);
	_leave(" = 0");
	return 0;

923
error_key:
924 925 926 927 928 929 930
	key_put(key);
error:
	d_drop(dentry);
	_leave(" = %d", ret);
	return ret;
}

931 932 933 934 935 936 937 938 939 940 941 942 943 944
/*
 * Remove a subdir from a directory.
 */
static void afs_dir_remove_subdir(struct dentry *dentry)
{
	if (d_really_is_positive(dentry)) {
		struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));

		clear_nlink(&vnode->vfs_inode);
		set_bit(AFS_VNODE_DELETED, &vnode->flags);
		clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
	}
}

945 946 947 948 949
/*
 * remove a directory from an AFS filesystem
 */
static int afs_rmdir(struct inode *dir, struct dentry *dentry)
{
950 951
	struct afs_fs_cursor fc;
	struct afs_vnode *dvnode = AFS_FS_I(dir);
952 953 954
	struct key *key;
	int ret;

A
Al Viro 已提交
955 956
	_enter("{%x:%u},{%pd}",
	       dvnode->fid.vid, dvnode->fid.vnode, dentry);
957 958 959 960 961 962 963

	key = afs_request_key(dvnode->volume->cell);
	if (IS_ERR(key)) {
		ret = PTR_ERR(key);
		goto error;
	}

964 965 966 967 968 969
	ret = -ERESTARTSYS;
	if (afs_begin_vnode_operation(&fc, dvnode, key)) {
		while (afs_select_fileserver(&fc)) {
			fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
			afs_fs_remove(&fc, dentry->d_name.name, true);
		}
970

971 972 973 974
		afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
		ret = afs_end_vnode_operation(&fc);
		if (ret == 0)
			afs_dir_remove_subdir(dentry);
975 976 977 978 979 980 981 982
	}

	key_put(key);
error:
	return ret;
}

/*
983 984 985 986 987 988 989 990 991
 * Remove a link to a file or symlink from a directory.
 *
 * If the file was not deleted due to excess hard links, the fileserver will
 * break the callback promise on the file - if it had one - before it returns
 * to us, and if it was deleted, it won't
 *
 * However, if we didn't have a callback promise outstanding, or it was
 * outstanding on a different server, then it won't break it either...
 */
D
David Howells 已提交
992 993 994
static int afs_dir_remove_link(struct dentry *dentry, struct key *key,
			       unsigned long d_version_before,
			       unsigned long d_version_after)
995
{
D
David Howells 已提交
996
	bool dir_valid;
997 998
	int ret = 0;

D
David Howells 已提交
999 1000 1001 1002 1003
	/* There were no intervening changes on the server if the version
	 * number we got back was incremented by exactly 1.
	 */
	dir_valid = (d_version_after == d_version_before + 1);

1004 1005 1006
	if (d_really_is_positive(dentry)) {
		struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));

D
David Howells 已提交
1007 1008 1009 1010 1011 1012
		if (dir_valid) {
			drop_nlink(&vnode->vfs_inode);
			if (vnode->vfs_inode.i_nlink == 0) {
				set_bit(AFS_VNODE_DELETED, &vnode->flags);
				clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
			}
1013
			ret = 0;
D
David Howells 已提交
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
		} else {
			clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);

			if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
				kdebug("AFS_VNODE_DELETED");

			ret = afs_validate(vnode, key);
			if (ret == -ESTALE)
				ret = 0;
		}
1024 1025 1026 1027 1028 1029 1030 1031
		_debug("nlink %d [val %d]", vnode->vfs_inode.i_nlink, ret);
	}

	return ret;
}

/*
 * Remove a file or symlink from an AFS filesystem.
1032 1033 1034
 */
static int afs_unlink(struct inode *dir, struct dentry *dentry)
{
1035 1036
	struct afs_fs_cursor fc;
	struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode;
1037
	struct key *key;
D
David Howells 已提交
1038
	unsigned long d_version = (unsigned long)dentry->d_fsdata;
1039 1040
	int ret;

A
Al Viro 已提交
1041 1042
	_enter("{%x:%u},{%pd}",
	       dvnode->fid.vid, dvnode->fid.vnode, dentry);
1043

D
David Howells 已提交
1044
	if (dentry->d_name.len >= AFSNAMEMAX)
1045
		return -ENAMETOOLONG;
1046 1047 1048 1049 1050 1051 1052

	key = afs_request_key(dvnode->volume->cell);
	if (IS_ERR(key)) {
		ret = PTR_ERR(key);
		goto error;
	}

1053
	/* Try to make sure we have a callback promise on the victim. */
1054 1055
	if (d_really_is_positive(dentry)) {
		vnode = AFS_FS_I(d_inode(dentry));
1056 1057
		ret = afs_validate(vnode, key);
		if (ret < 0)
1058
			goto error_key;
1059 1060
	}

1061 1062 1063 1064 1065 1066
	ret = -ERESTARTSYS;
	if (afs_begin_vnode_operation(&fc, dvnode, key)) {
		while (afs_select_fileserver(&fc)) {
			fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
			afs_fs_remove(&fc, dentry->d_name.name, false);
		}
1067

1068 1069 1070
		afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
		ret = afs_end_vnode_operation(&fc);
		if (ret == 0)
D
David Howells 已提交
1071 1072 1073
			ret = afs_dir_remove_link(
				dentry, key, d_version,
				(unsigned long)dvnode->status.data_version);
1074 1075
	}

1076
error_key:
1077 1078 1079 1080 1081 1082 1083 1084 1085
	key_put(key);
error:
	_leave(" = %d", ret);
	return ret;
}

/*
 * create a regular file on an AFS filesystem
 */
A
Al Viro 已提交
1086
static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
A
Al Viro 已提交
1087
		      bool excl)
1088
{
1089 1090 1091
	struct afs_fs_cursor fc;
	struct afs_file_status newstatus;
	struct afs_callback newcb;
1092
	struct afs_vnode *dvnode = AFS_FS_I(dir);
1093
	struct afs_fid newfid;
1094 1095 1096
	struct key *key;
	int ret;

1097
	mode |= S_IFREG;
1098

A
Al Viro 已提交
1099 1100
	_enter("{%x:%u},{%pd},%ho,",
	       dvnode->fid.vid, dvnode->fid.vnode, dentry, mode);
1101

1102 1103 1104 1105
	ret = -ENAMETOOLONG;
	if (dentry->d_name.len >= AFSNAMEMAX)
		goto error;

1106 1107 1108 1109 1110 1111
	key = afs_request_key(dvnode->volume->cell);
	if (IS_ERR(key)) {
		ret = PTR_ERR(key);
		goto error;
	}

1112 1113 1114 1115 1116 1117 1118
	ret = -ERESTARTSYS;
	if (afs_begin_vnode_operation(&fc, dvnode, key)) {
		while (afs_select_fileserver(&fc)) {
			fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
			afs_fs_create(&fc, dentry->d_name.name, mode,
				      &newfid, &newstatus, &newcb);
		}
1119

1120 1121 1122 1123 1124 1125
		afs_check_for_remote_deletion(&fc, fc.vnode);
		afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
		afs_vnode_new_inode(&fc, dentry, &newfid, &newstatus, &newcb);
		ret = afs_end_vnode_operation(&fc);
		if (ret < 0)
			goto error_key;
1126 1127
	} else {
		goto error_key;
1128 1129 1130 1131 1132 1133
	}

	key_put(key);
	_leave(" = 0");
	return 0;

1134
error_key:
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
	key_put(key);
error:
	d_drop(dentry);
	_leave(" = %d", ret);
	return ret;
}

/*
 * create a hard link between files in an AFS filesystem
 */
static int afs_link(struct dentry *from, struct inode *dir,
		    struct dentry *dentry)
{
1148
	struct afs_fs_cursor fc;
1149 1150 1151 1152
	struct afs_vnode *dvnode, *vnode;
	struct key *key;
	int ret;

1153
	vnode = AFS_FS_I(d_inode(from));
1154 1155
	dvnode = AFS_FS_I(dir);

A
Al Viro 已提交
1156
	_enter("{%x:%u},{%x:%u},{%pd}",
1157 1158
	       vnode->fid.vid, vnode->fid.vnode,
	       dvnode->fid.vid, dvnode->fid.vnode,
A
Al Viro 已提交
1159
	       dentry);
1160

1161 1162 1163 1164
	ret = -ENAMETOOLONG;
	if (dentry->d_name.len >= AFSNAMEMAX)
		goto error;

1165 1166 1167 1168 1169 1170
	key = afs_request_key(dvnode->volume->cell);
	if (IS_ERR(key)) {
		ret = PTR_ERR(key);
		goto error;
	}

1171 1172 1173 1174
	ret = -ERESTARTSYS;
	if (afs_begin_vnode_operation(&fc, dvnode, key)) {
		if (mutex_lock_interruptible_nested(&vnode->io_lock, 1) < 0) {
			afs_end_vnode_operation(&fc);
1175
			goto error_key;
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
		}

		while (afs_select_fileserver(&fc)) {
			fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
			fc.cb_break_2 = vnode->cb_break + vnode->cb_s_break;
			afs_fs_link(&fc, vnode, dentry->d_name.name);
		}

		afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
		afs_vnode_commit_status(&fc, vnode, fc.cb_break_2);
		ihold(&vnode->vfs_inode);
		d_instantiate(dentry, &vnode->vfs_inode);

		mutex_unlock(&vnode->io_lock);
		ret = afs_end_vnode_operation(&fc);
		if (ret < 0)
			goto error_key;
1193 1194
	} else {
		goto error_key;
1195
	}
1196 1197 1198 1199 1200

	key_put(key);
	_leave(" = 0");
	return 0;

1201
error_key:
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214
	key_put(key);
error:
	d_drop(dentry);
	_leave(" = %d", ret);
	return ret;
}

/*
 * create a symlink in an AFS filesystem
 */
static int afs_symlink(struct inode *dir, struct dentry *dentry,
		       const char *content)
{
1215 1216 1217 1218
	struct afs_fs_cursor fc;
	struct afs_file_status newstatus;
	struct afs_vnode *dvnode = AFS_FS_I(dir);
	struct afs_fid newfid;
1219 1220 1221
	struct key *key;
	int ret;

A
Al Viro 已提交
1222 1223
	_enter("{%x:%u},{%pd},%s",
	       dvnode->fid.vid, dvnode->fid.vnode, dentry,
1224 1225
	       content);

1226 1227 1228 1229
	ret = -ENAMETOOLONG;
	if (dentry->d_name.len >= AFSNAMEMAX)
		goto error;

1230
	ret = -EINVAL;
D
David Howells 已提交
1231
	if (strlen(content) >= AFSPATHMAX)
1232 1233 1234 1235 1236 1237 1238 1239
		goto error;

	key = afs_request_key(dvnode->volume->cell);
	if (IS_ERR(key)) {
		ret = PTR_ERR(key);
		goto error;
	}

1240 1241 1242 1243 1244 1245 1246
	ret = -ERESTARTSYS;
	if (afs_begin_vnode_operation(&fc, dvnode, key)) {
		while (afs_select_fileserver(&fc)) {
			fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
			afs_fs_symlink(&fc, dentry->d_name.name, content,
				       &newfid, &newstatus);
		}
1247

1248 1249 1250 1251 1252 1253
		afs_check_for_remote_deletion(&fc, fc.vnode);
		afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
		afs_vnode_new_inode(&fc, dentry, &newfid, &newstatus, NULL);
		ret = afs_end_vnode_operation(&fc);
		if (ret < 0)
			goto error_key;
1254 1255
	} else {
		goto error_key;
1256 1257 1258 1259 1260 1261
	}

	key_put(key);
	_leave(" = 0");
	return 0;

1262
error_key:
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
	key_put(key);
error:
	d_drop(dentry);
	_leave(" = %d", ret);
	return ret;
}

/*
 * rename a file in an AFS filesystem and/or move it between directories
 */
static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
1274 1275
		      struct inode *new_dir, struct dentry *new_dentry,
		      unsigned int flags)
1276
{
1277
	struct afs_fs_cursor fc;
1278 1279 1280 1281
	struct afs_vnode *orig_dvnode, *new_dvnode, *vnode;
	struct key *key;
	int ret;

1282 1283 1284
	if (flags)
		return -EINVAL;

1285
	vnode = AFS_FS_I(d_inode(old_dentry));
1286 1287 1288
	orig_dvnode = AFS_FS_I(old_dir);
	new_dvnode = AFS_FS_I(new_dir);

A
Al Viro 已提交
1289
	_enter("{%x:%u},{%x:%u},{%x:%u},{%pd}",
1290 1291 1292
	       orig_dvnode->fid.vid, orig_dvnode->fid.vnode,
	       vnode->fid.vid, vnode->fid.vnode,
	       new_dvnode->fid.vid, new_dvnode->fid.vnode,
A
Al Viro 已提交
1293
	       new_dentry);
1294 1295 1296 1297 1298 1299 1300

	key = afs_request_key(orig_dvnode->volume->cell);
	if (IS_ERR(key)) {
		ret = PTR_ERR(key);
		goto error;
	}

1301 1302 1303 1304 1305
	ret = -ERESTARTSYS;
	if (afs_begin_vnode_operation(&fc, orig_dvnode, key)) {
		if (orig_dvnode != new_dvnode) {
			if (mutex_lock_interruptible_nested(&new_dvnode->io_lock, 1) < 0) {
				afs_end_vnode_operation(&fc);
1306
				goto error_key;
1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325
			}
		}
		while (afs_select_fileserver(&fc)) {
			fc.cb_break = orig_dvnode->cb_break + orig_dvnode->cb_s_break;
			fc.cb_break_2 = new_dvnode->cb_break + new_dvnode->cb_s_break;
			afs_fs_rename(&fc, old_dentry->d_name.name,
				      new_dvnode, new_dentry->d_name.name);
		}

		afs_vnode_commit_status(&fc, orig_dvnode, fc.cb_break);
		afs_vnode_commit_status(&fc, new_dvnode, fc.cb_break_2);
		if (orig_dvnode != new_dvnode)
			mutex_unlock(&new_dvnode->io_lock);
		ret = afs_end_vnode_operation(&fc);
		if (ret < 0)
			goto error_key;
	}

error_key:
1326 1327 1328 1329 1330
	key_put(key);
error:
	_leave(" = %d", ret);
	return ret;
}