xref: /openbmc/linux/fs/afs/dir.c (revision 66c7e1d3)
11da177e4SLinus Torvalds /* dir.c: AFS filesystem directory handling
21da177e4SLinus Torvalds  *
31da177e4SLinus Torvalds  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
41da177e4SLinus Torvalds  * Written by David Howells (dhowells@redhat.com)
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or
71da177e4SLinus Torvalds  * modify it under the terms of the GNU General Public License
81da177e4SLinus Torvalds  * as published by the Free Software Foundation; either version
91da177e4SLinus Torvalds  * 2 of the License, or (at your option) any later version.
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds #include <linux/kernel.h>
131da177e4SLinus Torvalds #include <linux/fs.h>
1434286d66SNick Piggin #include <linux/namei.h>
151da177e4SLinus Torvalds #include <linux/pagemap.h>
1600d3b7a4SDavid Howells #include <linux/ctype.h>
17e8edc6e0SAlexey Dobriyan #include <linux/sched.h>
181da177e4SLinus Torvalds #include "internal.h"
191da177e4SLinus Torvalds 
20260a9803SDavid Howells static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
2100cd8dd3SAl Viro 				 unsigned int flags);
221da177e4SLinus Torvalds static int afs_dir_open(struct inode *inode, struct file *file);
231bbae9f8SAl Viro static int afs_readdir(struct file *file, struct dir_context *ctx);
240b728e19SAl Viro static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
25fe15ce44SNick Piggin static int afs_d_delete(const struct dentry *dentry);
265cf9dd55SDavid Howells static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen,
275cf9dd55SDavid Howells 				  loff_t fpos, u64 ino, unsigned dtype);
28ac7576f4SMiklos Szeredi static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen,
29afefdbb2SDavid Howells 			      loff_t fpos, u64 ino, unsigned dtype);
304acdaf27SAl Viro static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
31ebfc3b49SAl Viro 		      bool excl);
3218bb1db3SAl Viro static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
33260a9803SDavid Howells static int afs_rmdir(struct inode *dir, struct dentry *dentry);
34260a9803SDavid Howells static int afs_unlink(struct inode *dir, struct dentry *dentry);
35260a9803SDavid Howells static int afs_link(struct dentry *from, struct inode *dir,
36260a9803SDavid Howells 		    struct dentry *dentry);
37260a9803SDavid Howells static int afs_symlink(struct inode *dir, struct dentry *dentry,
38260a9803SDavid Howells 		       const char *content);
39260a9803SDavid Howells static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
401cd66c93SMiklos Szeredi 		      struct inode *new_dir, struct dentry *new_dentry,
411cd66c93SMiklos Szeredi 		      unsigned int flags);
421da177e4SLinus Torvalds 
434b6f5d20SArjan van de Ven const struct file_operations afs_dir_file_operations = {
441da177e4SLinus Torvalds 	.open		= afs_dir_open,
4500d3b7a4SDavid Howells 	.release	= afs_release,
4629884effSAl Viro 	.iterate_shared	= afs_readdir,
47e8d6c554SDavid Howells 	.lock		= afs_lock,
483222a3e5SChristoph Hellwig 	.llseek		= generic_file_llseek,
491da177e4SLinus Torvalds };
501da177e4SLinus Torvalds 
51754661f1SArjan van de Ven const struct inode_operations afs_dir_inode_operations = {
52260a9803SDavid Howells 	.create		= afs_create,
53260a9803SDavid Howells 	.lookup		= afs_lookup,
54260a9803SDavid Howells 	.link		= afs_link,
55260a9803SDavid Howells 	.unlink		= afs_unlink,
56260a9803SDavid Howells 	.symlink	= afs_symlink,
57260a9803SDavid Howells 	.mkdir		= afs_mkdir,
58260a9803SDavid Howells 	.rmdir		= afs_rmdir,
592773bf00SMiklos Szeredi 	.rename		= afs_rename,
6000d3b7a4SDavid Howells 	.permission	= afs_permission,
61416351f2SDavid Howells 	.getattr	= afs_getattr,
6231143d5dSDavid Howells 	.setattr	= afs_setattr,
63d3e3b7eaSDavid Howells 	.listxattr	= afs_listxattr,
641da177e4SLinus Torvalds };
651da177e4SLinus Torvalds 
66d61dcce2SAl Viro const struct dentry_operations afs_fs_dentry_operations = {
671da177e4SLinus Torvalds 	.d_revalidate	= afs_d_revalidate,
681da177e4SLinus Torvalds 	.d_delete	= afs_d_delete,
69260a9803SDavid Howells 	.d_release	= afs_d_release,
70d18610b0SDavid Howells 	.d_automount	= afs_d_automount,
711da177e4SLinus Torvalds };
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds #define AFS_DIR_HASHTBL_SIZE	128
741da177e4SLinus Torvalds #define AFS_DIR_DIRENT_SIZE	32
751da177e4SLinus Torvalds #define AFS_DIRENT_PER_BLOCK	64
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds union afs_dirent {
781da177e4SLinus Torvalds 	struct {
791da177e4SLinus Torvalds 		uint8_t		valid;
801da177e4SLinus Torvalds 		uint8_t		unused[1];
811da177e4SLinus Torvalds 		__be16		hash_next;
821da177e4SLinus Torvalds 		__be32		vnode;
831da177e4SLinus Torvalds 		__be32		unique;
841da177e4SLinus Torvalds 		uint8_t		name[16];
851da177e4SLinus Torvalds 		uint8_t		overflow[4];	/* if any char of the name (inc
861da177e4SLinus Torvalds 						 * NUL) reaches here, consume
871da177e4SLinus Torvalds 						 * the next dirent too */
881da177e4SLinus Torvalds 	} u;
891da177e4SLinus Torvalds 	uint8_t	extended_name[32];
901da177e4SLinus Torvalds };
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds /* AFS directory page header (one at the beginning of every 2048-byte chunk) */
931da177e4SLinus Torvalds struct afs_dir_pagehdr {
941da177e4SLinus Torvalds 	__be16		npages;
951da177e4SLinus Torvalds 	__be16		magic;
961da177e4SLinus Torvalds #define AFS_DIR_MAGIC htons(1234)
971da177e4SLinus Torvalds 	uint8_t		nentries;
981da177e4SLinus Torvalds 	uint8_t		bitmap[8];
991da177e4SLinus Torvalds 	uint8_t		pad[19];
1001da177e4SLinus Torvalds };
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds /* directory block layout */
1031da177e4SLinus Torvalds union afs_dir_block {
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 	struct afs_dir_pagehdr pagehdr;
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds 	struct {
1081da177e4SLinus Torvalds 		struct afs_dir_pagehdr	pagehdr;
1091da177e4SLinus Torvalds 		uint8_t			alloc_ctrs[128];
1101da177e4SLinus Torvalds 		/* dir hash table */
1111da177e4SLinus Torvalds 		uint16_t		hashtable[AFS_DIR_HASHTBL_SIZE];
1121da177e4SLinus Torvalds 	} hdr;
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 	union afs_dirent dirents[AFS_DIRENT_PER_BLOCK];
1151da177e4SLinus Torvalds };
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds /* layout on a linux VM page */
1181da177e4SLinus Torvalds struct afs_dir_page {
1191da177e4SLinus Torvalds 	union afs_dir_block blocks[PAGE_SIZE / sizeof(union afs_dir_block)];
1201da177e4SLinus Torvalds };
1211da177e4SLinus Torvalds 
1225cf9dd55SDavid Howells struct afs_lookup_one_cookie {
1235cf9dd55SDavid Howells 	struct dir_context	ctx;
1245cf9dd55SDavid Howells 	struct qstr		name;
1255cf9dd55SDavid Howells 	bool			found;
1265cf9dd55SDavid Howells 	struct afs_fid		fid;
1275cf9dd55SDavid Howells };
1285cf9dd55SDavid Howells 
129260a9803SDavid Howells struct afs_lookup_cookie {
1301bbae9f8SAl Viro 	struct dir_context	ctx;
1311bbae9f8SAl Viro 	struct qstr		name;
1325cf9dd55SDavid Howells 	bool			found;
1335cf9dd55SDavid Howells 	bool			one_only;
1345cf9dd55SDavid Howells 	unsigned short		nr_fids;
1355cf9dd55SDavid Howells 	struct afs_file_status	*statuses;
1365cf9dd55SDavid Howells 	struct afs_callback	*callbacks;
1375cf9dd55SDavid Howells 	struct afs_fid		fids[50];
1381da177e4SLinus Torvalds };
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds /*
1411da177e4SLinus Torvalds  * check that a directory page is valid
1421da177e4SLinus Torvalds  */
143dab17c1aSDavid Howells bool afs_dir_check_page(struct inode *dir, struct page *page)
1441da177e4SLinus Torvalds {
1451da177e4SLinus Torvalds 	struct afs_dir_page *dbuf;
146dab17c1aSDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(dir);
147dab17c1aSDavid Howells 	loff_t latter, i_size, off;
1481da177e4SLinus Torvalds 	int tmp, qty;
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds #if 0
1511da177e4SLinus Torvalds 	/* check the page count */
1521da177e4SLinus Torvalds 	qty = desc.size / sizeof(dbuf->blocks[0]);
1531da177e4SLinus Torvalds 	if (qty == 0)
1541da177e4SLinus Torvalds 		goto error;
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	if (page->index == 0 && qty != ntohs(dbuf->blocks[0].pagehdr.npages)) {
1571da177e4SLinus Torvalds 		printk("kAFS: %s(%lu): wrong number of dir blocks %d!=%hu\n",
158530b6412SHarvey Harrison 		       __func__, dir->i_ino, qty,
15908e0e7c8SDavid Howells 		       ntohs(dbuf->blocks[0].pagehdr.npages));
1601da177e4SLinus Torvalds 		goto error;
1611da177e4SLinus Torvalds 	}
1621da177e4SLinus Torvalds #endif
1631da177e4SLinus Torvalds 
164dab17c1aSDavid Howells 	/* Determine how many magic numbers there should be in this page, but
165dab17c1aSDavid Howells 	 * we must take care because the directory may change size under us.
166dab17c1aSDavid Howells 	 */
167dab17c1aSDavid Howells 	off = page_offset(page);
168dab17c1aSDavid Howells 	i_size = i_size_read(dir);
169dab17c1aSDavid Howells 	if (i_size <= off)
170dab17c1aSDavid Howells 		goto checked;
171dab17c1aSDavid Howells 
172dab17c1aSDavid Howells 	latter = i_size - off;
1731da177e4SLinus Torvalds 	if (latter >= PAGE_SIZE)
1741da177e4SLinus Torvalds 		qty = PAGE_SIZE;
1751da177e4SLinus Torvalds 	else
1761da177e4SLinus Torvalds 		qty = latter;
1771da177e4SLinus Torvalds 	qty /= sizeof(union afs_dir_block);
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds 	/* check them */
1801da177e4SLinus Torvalds 	dbuf = page_address(page);
1811da177e4SLinus Torvalds 	for (tmp = 0; tmp < qty; tmp++) {
1821da177e4SLinus Torvalds 		if (dbuf->blocks[tmp].pagehdr.magic != AFS_DIR_MAGIC) {
183dab17c1aSDavid Howells 			printk("kAFS: %s(%lx): bad magic %d/%d is %04hx\n",
184530b6412SHarvey Harrison 			       __func__, dir->i_ino, tmp, qty,
1851da177e4SLinus Torvalds 			       ntohs(dbuf->blocks[tmp].pagehdr.magic));
186dab17c1aSDavid Howells 			trace_afs_dir_check_failed(vnode, off, i_size);
1871da177e4SLinus Torvalds 			goto error;
1881da177e4SLinus Torvalds 		}
1891da177e4SLinus Torvalds 	}
1901da177e4SLinus Torvalds 
191dab17c1aSDavid Howells checked:
192d55b4da4SDavid Howells 	afs_stat_v(vnode, n_read_dir);
1931da177e4SLinus Torvalds 	SetPageChecked(page);
194be5b82dbSAl Viro 	return true;
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds error:
1971da177e4SLinus Torvalds 	SetPageError(page);
198be5b82dbSAl Viro 	return false;
199ec26815aSDavid Howells }
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds /*
2021da177e4SLinus Torvalds  * discard a page cached in the pagecache
2031da177e4SLinus Torvalds  */
2041da177e4SLinus Torvalds static inline void afs_dir_put_page(struct page *page)
2051da177e4SLinus Torvalds {
2061da177e4SLinus Torvalds 	kunmap(page);
207dab17c1aSDavid Howells 	unlock_page(page);
20809cbfeafSKirill A. Shutemov 	put_page(page);
209ec26815aSDavid Howells }
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds /*
2121da177e4SLinus Torvalds  * get a page into the pagecache
2131da177e4SLinus Torvalds  */
21400d3b7a4SDavid Howells static struct page *afs_dir_get_page(struct inode *dir, unsigned long index,
21500d3b7a4SDavid Howells 				     struct key *key)
2161da177e4SLinus Torvalds {
2171da177e4SLinus Torvalds 	struct page *page;
2181da177e4SLinus Torvalds 	_enter("{%lu},%lu", dir->i_ino, index);
2191da177e4SLinus Torvalds 
220f6d335c0SAl Viro 	page = read_cache_page(dir->i_mapping, index, afs_page_filler, key);
2211da177e4SLinus Torvalds 	if (!IS_ERR(page)) {
222dab17c1aSDavid Howells 		lock_page(page);
2231da177e4SLinus Torvalds 		kmap(page);
224be5b82dbSAl Viro 		if (unlikely(!PageChecked(page))) {
225dab17c1aSDavid Howells 			if (PageError(page))
2261da177e4SLinus Torvalds 				goto fail;
2271da177e4SLinus Torvalds 		}
228be5b82dbSAl Viro 	}
2291da177e4SLinus Torvalds 	return page;
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds fail:
2321da177e4SLinus Torvalds 	afs_dir_put_page(page);
23308e0e7c8SDavid Howells 	_leave(" = -EIO");
2341da177e4SLinus Torvalds 	return ERR_PTR(-EIO);
235ec26815aSDavid Howells }
2361da177e4SLinus Torvalds 
2371da177e4SLinus Torvalds /*
2381da177e4SLinus Torvalds  * open an AFS directory file
2391da177e4SLinus Torvalds  */
2401da177e4SLinus Torvalds static int afs_dir_open(struct inode *inode, struct file *file)
2411da177e4SLinus Torvalds {
2421da177e4SLinus Torvalds 	_enter("{%lu}", inode->i_ino);
2431da177e4SLinus Torvalds 
2442ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
2452ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
2461da177e4SLinus Torvalds 
24708e0e7c8SDavid Howells 	if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags))
2481da177e4SLinus Torvalds 		return -ENOENT;
2491da177e4SLinus Torvalds 
25000d3b7a4SDavid Howells 	return afs_open(inode, file);
251ec26815aSDavid Howells }
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds /*
2541da177e4SLinus Torvalds  * deal with one block in an AFS directory
2551da177e4SLinus Torvalds  */
2561bbae9f8SAl Viro static int afs_dir_iterate_block(struct dir_context *ctx,
2571da177e4SLinus Torvalds 				 union afs_dir_block *block,
2581bbae9f8SAl Viro 				 unsigned blkoff)
2591da177e4SLinus Torvalds {
2601da177e4SLinus Torvalds 	union afs_dirent *dire;
2611da177e4SLinus Torvalds 	unsigned offset, next, curr;
2621da177e4SLinus Torvalds 	size_t nlen;
2631bbae9f8SAl Viro 	int tmp;
2641da177e4SLinus Torvalds 
2651bbae9f8SAl Viro 	_enter("%u,%x,%p,,",(unsigned)ctx->pos,blkoff,block);
2661da177e4SLinus Torvalds 
2671bbae9f8SAl Viro 	curr = (ctx->pos - blkoff) / sizeof(union afs_dirent);
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds 	/* walk through the block, an entry at a time */
2701da177e4SLinus Torvalds 	for (offset = AFS_DIRENT_PER_BLOCK - block->pagehdr.nentries;
2711da177e4SLinus Torvalds 	     offset < AFS_DIRENT_PER_BLOCK;
2721da177e4SLinus Torvalds 	     offset = next
2731da177e4SLinus Torvalds 	     ) {
2741da177e4SLinus Torvalds 		next = offset + 1;
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 		/* skip entries marked unused in the bitmap */
2771da177e4SLinus Torvalds 		if (!(block->pagehdr.bitmap[offset / 8] &
2781da177e4SLinus Torvalds 		      (1 << (offset % 8)))) {
2795b5e0928SAlexey Dobriyan 			_debug("ENT[%zu.%u]: unused",
2801da177e4SLinus Torvalds 			       blkoff / sizeof(union afs_dir_block), offset);
2811da177e4SLinus Torvalds 			if (offset >= curr)
2821bbae9f8SAl Viro 				ctx->pos = blkoff +
2831da177e4SLinus Torvalds 					next * sizeof(union afs_dirent);
2841da177e4SLinus Torvalds 			continue;
2851da177e4SLinus Torvalds 		}
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 		/* got a valid entry */
2881da177e4SLinus Torvalds 		dire = &block->dirents[offset];
2891da177e4SLinus Torvalds 		nlen = strnlen(dire->u.name,
2901da177e4SLinus Torvalds 			       sizeof(*block) -
2911da177e4SLinus Torvalds 			       offset * sizeof(union afs_dirent));
2921da177e4SLinus Torvalds 
2935b5e0928SAlexey Dobriyan 		_debug("ENT[%zu.%u]: %s %zu \"%s\"",
2941da177e4SLinus Torvalds 		       blkoff / sizeof(union afs_dir_block), offset,
2951da177e4SLinus Torvalds 		       (offset < curr ? "skip" : "fill"),
2961da177e4SLinus Torvalds 		       nlen, dire->u.name);
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds 		/* work out where the next possible entry is */
2991da177e4SLinus Torvalds 		for (tmp = nlen; tmp > 15; tmp -= sizeof(union afs_dirent)) {
3001da177e4SLinus Torvalds 			if (next >= AFS_DIRENT_PER_BLOCK) {
3015b5e0928SAlexey Dobriyan 				_debug("ENT[%zu.%u]:"
3021da177e4SLinus Torvalds 				       " %u travelled beyond end dir block"
3035b5e0928SAlexey Dobriyan 				       " (len %u/%zu)",
3041da177e4SLinus Torvalds 				       blkoff / sizeof(union afs_dir_block),
3051da177e4SLinus Torvalds 				       offset, next, tmp, nlen);
3061da177e4SLinus Torvalds 				return -EIO;
3071da177e4SLinus Torvalds 			}
3081da177e4SLinus Torvalds 			if (!(block->pagehdr.bitmap[next / 8] &
3091da177e4SLinus Torvalds 			      (1 << (next % 8)))) {
3105b5e0928SAlexey Dobriyan 				_debug("ENT[%zu.%u]:"
3115b5e0928SAlexey Dobriyan 				       " %u unmarked extension (len %u/%zu)",
3121da177e4SLinus Torvalds 				       blkoff / sizeof(union afs_dir_block),
3131da177e4SLinus Torvalds 				       offset, next, tmp, nlen);
3141da177e4SLinus Torvalds 				return -EIO;
3151da177e4SLinus Torvalds 			}
3161da177e4SLinus Torvalds 
3175b5e0928SAlexey Dobriyan 			_debug("ENT[%zu.%u]: ext %u/%zu",
3181da177e4SLinus Torvalds 			       blkoff / sizeof(union afs_dir_block),
3191da177e4SLinus Torvalds 			       next, tmp, nlen);
3201da177e4SLinus Torvalds 			next++;
3211da177e4SLinus Torvalds 		}
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds 		/* skip if starts before the current position */
3241da177e4SLinus Torvalds 		if (offset < curr)
3251da177e4SLinus Torvalds 			continue;
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds 		/* found the next entry */
3281bbae9f8SAl Viro 		if (!dir_emit(ctx, dire->u.name, nlen,
3291da177e4SLinus Torvalds 			      ntohl(dire->u.vnode),
3305cf9dd55SDavid Howells 			      (ctx->actor == afs_lookup_filldir ||
3315cf9dd55SDavid Howells 			       ctx->actor == afs_lookup_one_filldir)?
3321bbae9f8SAl Viro 			      ntohl(dire->u.unique) : DT_UNKNOWN)) {
3331da177e4SLinus Torvalds 			_leave(" = 0 [full]");
3341da177e4SLinus Torvalds 			return 0;
3351da177e4SLinus Torvalds 		}
3361da177e4SLinus Torvalds 
3371bbae9f8SAl Viro 		ctx->pos = blkoff + next * sizeof(union afs_dirent);
3381da177e4SLinus Torvalds 	}
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds 	_leave(" = 1 [more]");
3411da177e4SLinus Torvalds 	return 1;
342ec26815aSDavid Howells }
3431da177e4SLinus Torvalds 
3441da177e4SLinus Torvalds /*
34508e0e7c8SDavid Howells  * iterate through the data blob that lists the contents of an AFS directory
3461da177e4SLinus Torvalds  */
3471bbae9f8SAl Viro static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
3481bbae9f8SAl Viro 			   struct key *key)
3491da177e4SLinus Torvalds {
3501da177e4SLinus Torvalds 	union afs_dir_block *dblock;
3511da177e4SLinus Torvalds 	struct afs_dir_page *dbuf;
3521da177e4SLinus Torvalds 	struct page *page;
3531da177e4SLinus Torvalds 	unsigned blkoff, limit;
3541da177e4SLinus Torvalds 	int ret;
3551da177e4SLinus Torvalds 
3561bbae9f8SAl Viro 	_enter("{%lu},%u,,", dir->i_ino, (unsigned)ctx->pos);
3571da177e4SLinus Torvalds 
35808e0e7c8SDavid Howells 	if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) {
3591da177e4SLinus Torvalds 		_leave(" = -ESTALE");
3601da177e4SLinus Torvalds 		return -ESTALE;
3611da177e4SLinus Torvalds 	}
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds 	/* round the file position up to the next entry boundary */
3641bbae9f8SAl Viro 	ctx->pos += sizeof(union afs_dirent) - 1;
3651bbae9f8SAl Viro 	ctx->pos &= ~(sizeof(union afs_dirent) - 1);
3661da177e4SLinus Torvalds 
3671da177e4SLinus Torvalds 	/* walk through the blocks in sequence */
3681da177e4SLinus Torvalds 	ret = 0;
3691bbae9f8SAl Viro 	while (ctx->pos < dir->i_size) {
3701bbae9f8SAl Viro 		blkoff = ctx->pos & ~(sizeof(union afs_dir_block) - 1);
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds 		/* fetch the appropriate page from the directory */
37300d3b7a4SDavid Howells 		page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key);
3741da177e4SLinus Torvalds 		if (IS_ERR(page)) {
3751da177e4SLinus Torvalds 			ret = PTR_ERR(page);
3761da177e4SLinus Torvalds 			break;
3771da177e4SLinus Torvalds 		}
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 		limit = blkoff & ~(PAGE_SIZE - 1);
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds 		dbuf = page_address(page);
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds 		/* deal with the individual blocks stashed on this page */
3841da177e4SLinus Torvalds 		do {
3851da177e4SLinus Torvalds 			dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) /
3861da177e4SLinus Torvalds 					       sizeof(union afs_dir_block)];
3871bbae9f8SAl Viro 			ret = afs_dir_iterate_block(ctx, dblock, blkoff);
3881da177e4SLinus Torvalds 			if (ret != 1) {
3891da177e4SLinus Torvalds 				afs_dir_put_page(page);
3901da177e4SLinus Torvalds 				goto out;
3911da177e4SLinus Torvalds 			}
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds 			blkoff += sizeof(union afs_dir_block);
3941da177e4SLinus Torvalds 
3951bbae9f8SAl Viro 		} while (ctx->pos < dir->i_size && blkoff < limit);
3961da177e4SLinus Torvalds 
3971da177e4SLinus Torvalds 		afs_dir_put_page(page);
3981da177e4SLinus Torvalds 		ret = 0;
3991da177e4SLinus Torvalds 	}
4001da177e4SLinus Torvalds 
4011da177e4SLinus Torvalds out:
4021da177e4SLinus Torvalds 	_leave(" = %d", ret);
4031da177e4SLinus Torvalds 	return ret;
404ec26815aSDavid Howells }
4051da177e4SLinus Torvalds 
4061da177e4SLinus Torvalds /*
4071da177e4SLinus Torvalds  * read an AFS directory
4081da177e4SLinus Torvalds  */
4091bbae9f8SAl Viro static int afs_readdir(struct file *file, struct dir_context *ctx)
4101da177e4SLinus Torvalds {
411215804a9SDavid Howells 	return afs_dir_iterate(file_inode(file), ctx, afs_file_key(file));
412ec26815aSDavid Howells }
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds /*
4155cf9dd55SDavid Howells  * Search the directory for a single name
4161da177e4SLinus Torvalds  * - if afs_dir_iterate_block() spots this function, it'll pass the FID
4171da177e4SLinus Torvalds  *   uniquifier through dtype
4181da177e4SLinus Torvalds  */
4195cf9dd55SDavid Howells static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name,
420ac7576f4SMiklos Szeredi 				  int nlen, loff_t fpos, u64 ino, unsigned dtype)
4211da177e4SLinus Torvalds {
4225cf9dd55SDavid Howells 	struct afs_lookup_one_cookie *cookie =
4235cf9dd55SDavid Howells 		container_of(ctx, struct afs_lookup_one_cookie, ctx);
4241da177e4SLinus Torvalds 
4251bbae9f8SAl Viro 	_enter("{%s,%u},%s,%u,,%llu,%u",
4261bbae9f8SAl Viro 	       cookie->name.name, cookie->name.len, name, nlen,
427ba3e0e1aSDavid S. Miller 	       (unsigned long long) ino, dtype);
4281da177e4SLinus Torvalds 
42908e0e7c8SDavid Howells 	/* insanity checks first */
43008e0e7c8SDavid Howells 	BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
43108e0e7c8SDavid Howells 	BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
43208e0e7c8SDavid Howells 
4331bbae9f8SAl Viro 	if (cookie->name.len != nlen ||
4341bbae9f8SAl Viro 	    memcmp(cookie->name.name, name, nlen) != 0) {
4351da177e4SLinus Torvalds 		_leave(" = 0 [no]");
4361da177e4SLinus Torvalds 		return 0;
4371da177e4SLinus Torvalds 	}
4381da177e4SLinus Torvalds 
4391da177e4SLinus Torvalds 	cookie->fid.vnode = ino;
4401da177e4SLinus Torvalds 	cookie->fid.unique = dtype;
4411da177e4SLinus Torvalds 	cookie->found = 1;
4421da177e4SLinus Torvalds 
4431da177e4SLinus Torvalds 	_leave(" = -1 [found]");
4441da177e4SLinus Torvalds 	return -1;
445ec26815aSDavid Howells }
4461da177e4SLinus Torvalds 
4471da177e4SLinus Torvalds /*
4485cf9dd55SDavid Howells  * Do a lookup of a single name in a directory
449260a9803SDavid Howells  * - just returns the FID the dentry name maps to if found
4501da177e4SLinus Torvalds  */
4515cf9dd55SDavid Howells static int afs_do_lookup_one(struct inode *dir, struct dentry *dentry,
45200d3b7a4SDavid Howells 			     struct afs_fid *fid, struct key *key)
4531da177e4SLinus Torvalds {
4541bbae9f8SAl Viro 	struct afs_super_info *as = dir->i_sb->s_fs_info;
4555cf9dd55SDavid Howells 	struct afs_lookup_one_cookie cookie = {
4565cf9dd55SDavid Howells 		.ctx.actor = afs_lookup_one_filldir,
4571bbae9f8SAl Viro 		.name = dentry->d_name,
4581bbae9f8SAl Viro 		.fid.vid = as->volume->vid
4591bbae9f8SAl Viro 	};
4601da177e4SLinus Torvalds 	int ret;
4611da177e4SLinus Torvalds 
462a455589fSAl Viro 	_enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry);
4631da177e4SLinus Torvalds 
4641da177e4SLinus Torvalds 	/* search the directory */
4651bbae9f8SAl Viro 	ret = afs_dir_iterate(dir, &cookie.ctx, key);
4661da177e4SLinus Torvalds 	if (ret < 0) {
46708e0e7c8SDavid Howells 		_leave(" = %d [iter]", ret);
46808e0e7c8SDavid Howells 		return ret;
4691da177e4SLinus Torvalds 	}
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds 	ret = -ENOENT;
4721da177e4SLinus Torvalds 	if (!cookie.found) {
47308e0e7c8SDavid Howells 		_leave(" = -ENOENT [not found]");
47408e0e7c8SDavid Howells 		return -ENOENT;
47508e0e7c8SDavid Howells 	}
47608e0e7c8SDavid Howells 
47708e0e7c8SDavid Howells 	*fid = cookie.fid;
47808e0e7c8SDavid Howells 	_leave(" = 0 { vn=%u u=%u }", fid->vnode, fid->unique);
47908e0e7c8SDavid Howells 	return 0;
48008e0e7c8SDavid Howells }
48108e0e7c8SDavid Howells 
48208e0e7c8SDavid Howells /*
4835cf9dd55SDavid Howells  * search the directory for a name
4845cf9dd55SDavid Howells  * - if afs_dir_iterate_block() spots this function, it'll pass the FID
4855cf9dd55SDavid Howells  *   uniquifier through dtype
4865cf9dd55SDavid Howells  */
4875cf9dd55SDavid Howells static int afs_lookup_filldir(struct dir_context *ctx, const char *name,
4885cf9dd55SDavid Howells 			      int nlen, loff_t fpos, u64 ino, unsigned dtype)
4895cf9dd55SDavid Howells {
4905cf9dd55SDavid Howells 	struct afs_lookup_cookie *cookie =
4915cf9dd55SDavid Howells 		container_of(ctx, struct afs_lookup_cookie, ctx);
4925cf9dd55SDavid Howells 	int ret;
4935cf9dd55SDavid Howells 
4945cf9dd55SDavid Howells 	_enter("{%s,%u},%s,%u,,%llu,%u",
4955cf9dd55SDavid Howells 	       cookie->name.name, cookie->name.len, name, nlen,
4965cf9dd55SDavid Howells 	       (unsigned long long) ino, dtype);
4975cf9dd55SDavid Howells 
4985cf9dd55SDavid Howells 	/* insanity checks first */
4995cf9dd55SDavid Howells 	BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
5005cf9dd55SDavid Howells 	BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
5015cf9dd55SDavid Howells 
5025cf9dd55SDavid Howells 	if (cookie->found) {
5035cf9dd55SDavid Howells 		if (cookie->nr_fids < 50) {
5045cf9dd55SDavid Howells 			cookie->fids[cookie->nr_fids].vnode	= ino;
5055cf9dd55SDavid Howells 			cookie->fids[cookie->nr_fids].unique	= dtype;
5065cf9dd55SDavid Howells 			cookie->nr_fids++;
5075cf9dd55SDavid Howells 		}
5085cf9dd55SDavid Howells 	} else if (cookie->name.len == nlen &&
5095cf9dd55SDavid Howells 		   memcmp(cookie->name.name, name, nlen) == 0) {
5105cf9dd55SDavid Howells 		cookie->fids[0].vnode	= ino;
5115cf9dd55SDavid Howells 		cookie->fids[0].unique	= dtype;
5125cf9dd55SDavid Howells 		cookie->found = 1;
5135cf9dd55SDavid Howells 		if (cookie->one_only)
5145cf9dd55SDavid Howells 			return -1;
5155cf9dd55SDavid Howells 	}
5165cf9dd55SDavid Howells 
5175cf9dd55SDavid Howells 	ret = cookie->nr_fids >= 50 ? -1 : 0;
5185cf9dd55SDavid Howells 	_leave(" = %d", ret);
5195cf9dd55SDavid Howells 	return ret;
5205cf9dd55SDavid Howells }
5215cf9dd55SDavid Howells 
5225cf9dd55SDavid Howells /*
5235cf9dd55SDavid Howells  * Do a lookup in a directory.  We make use of bulk lookup to query a slew of
5245cf9dd55SDavid Howells  * files in one go and create inodes for them.  The inode of the file we were
5255cf9dd55SDavid Howells  * asked for is returned.
5265cf9dd55SDavid Howells  */
5275cf9dd55SDavid Howells static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
5285cf9dd55SDavid Howells 				   struct key *key)
5295cf9dd55SDavid Howells {
5305cf9dd55SDavid Howells 	struct afs_lookup_cookie *cookie;
5315cf9dd55SDavid Howells 	struct afs_cb_interest *cbi = NULL;
5325cf9dd55SDavid Howells 	struct afs_super_info *as = dir->i_sb->s_fs_info;
5335cf9dd55SDavid Howells 	struct afs_iget_data data;
5345cf9dd55SDavid Howells 	struct afs_fs_cursor fc;
5355cf9dd55SDavid Howells 	struct afs_vnode *dvnode = AFS_FS_I(dir);
5365cf9dd55SDavid Howells 	struct inode *inode = NULL;
5375cf9dd55SDavid Howells 	int ret, i;
5385cf9dd55SDavid Howells 
5395cf9dd55SDavid Howells 	_enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry);
5405cf9dd55SDavid Howells 
5415cf9dd55SDavid Howells 	cookie = kzalloc(sizeof(struct afs_lookup_cookie), GFP_KERNEL);
5425cf9dd55SDavid Howells 	if (!cookie)
5435cf9dd55SDavid Howells 		return ERR_PTR(-ENOMEM);
5445cf9dd55SDavid Howells 
5455cf9dd55SDavid Howells 	cookie->ctx.actor = afs_lookup_filldir;
5465cf9dd55SDavid Howells 	cookie->name = dentry->d_name;
5475cf9dd55SDavid Howells 	cookie->nr_fids = 1; /* slot 0 is saved for the fid we actually want */
5485cf9dd55SDavid Howells 
5495cf9dd55SDavid Howells 	read_seqlock_excl(&dvnode->cb_lock);
5505cf9dd55SDavid Howells 	if (dvnode->cb_interest &&
5515cf9dd55SDavid Howells 	    dvnode->cb_interest->server &&
5525cf9dd55SDavid Howells 	    test_bit(AFS_SERVER_FL_NO_IBULK, &dvnode->cb_interest->server->flags))
5535cf9dd55SDavid Howells 		cookie->one_only = true;
5545cf9dd55SDavid Howells 	read_sequnlock_excl(&dvnode->cb_lock);
5555cf9dd55SDavid Howells 
5565cf9dd55SDavid Howells 	for (i = 0; i < 50; i++)
5575cf9dd55SDavid Howells 		cookie->fids[i].vid = as->volume->vid;
5585cf9dd55SDavid Howells 
5595cf9dd55SDavid Howells 	/* search the directory */
5605cf9dd55SDavid Howells 	ret = afs_dir_iterate(dir, &cookie->ctx, key);
5615cf9dd55SDavid Howells 	if (ret < 0) {
5625cf9dd55SDavid Howells 		inode = ERR_PTR(ret);
5635cf9dd55SDavid Howells 		goto out;
5645cf9dd55SDavid Howells 	}
5655cf9dd55SDavid Howells 
5665cf9dd55SDavid Howells 	inode = ERR_PTR(-ENOENT);
5675cf9dd55SDavid Howells 	if (!cookie->found)
5685cf9dd55SDavid Howells 		goto out;
5695cf9dd55SDavid Howells 
5705cf9dd55SDavid Howells 	/* Check to see if we already have an inode for the primary fid. */
5715cf9dd55SDavid Howells 	data.volume = dvnode->volume;
5725cf9dd55SDavid Howells 	data.fid = cookie->fids[0];
5735cf9dd55SDavid Howells 	inode = ilookup5(dir->i_sb, cookie->fids[0].vnode, afs_iget5_test, &data);
5745cf9dd55SDavid Howells 	if (inode)
5755cf9dd55SDavid Howells 		goto out;
5765cf9dd55SDavid Howells 
5775cf9dd55SDavid Howells 	/* Need space for examining all the selected files */
5785cf9dd55SDavid Howells 	inode = ERR_PTR(-ENOMEM);
5795cf9dd55SDavid Howells 	cookie->statuses = kcalloc(cookie->nr_fids, sizeof(struct afs_file_status),
5805cf9dd55SDavid Howells 				   GFP_KERNEL);
5815cf9dd55SDavid Howells 	if (!cookie->statuses)
5825cf9dd55SDavid Howells 		goto out;
5835cf9dd55SDavid Howells 
5845cf9dd55SDavid Howells 	cookie->callbacks = kcalloc(cookie->nr_fids, sizeof(struct afs_callback),
5855cf9dd55SDavid Howells 				    GFP_KERNEL);
5865cf9dd55SDavid Howells 	if (!cookie->callbacks)
5875cf9dd55SDavid Howells 		goto out_s;
5885cf9dd55SDavid Howells 
5895cf9dd55SDavid Howells 	/* Try FS.InlineBulkStatus first.  Abort codes for the individual
5905cf9dd55SDavid Howells 	 * lookups contained therein are stored in the reply without aborting
5915cf9dd55SDavid Howells 	 * the whole operation.
5925cf9dd55SDavid Howells 	 */
5935cf9dd55SDavid Howells 	if (cookie->one_only)
5945cf9dd55SDavid Howells 		goto no_inline_bulk_status;
5955cf9dd55SDavid Howells 
5965cf9dd55SDavid Howells 	inode = ERR_PTR(-ERESTARTSYS);
5975cf9dd55SDavid Howells 	if (afs_begin_vnode_operation(&fc, dvnode, key)) {
5985cf9dd55SDavid Howells 		while (afs_select_fileserver(&fc)) {
5995cf9dd55SDavid Howells 			if (test_bit(AFS_SERVER_FL_NO_IBULK,
6005cf9dd55SDavid Howells 				      &fc.cbi->server->flags)) {
6015cf9dd55SDavid Howells 				fc.ac.abort_code = RX_INVALID_OPERATION;
6025cf9dd55SDavid Howells 				fc.ac.error = -ECONNABORTED;
6035cf9dd55SDavid Howells 				break;
6045cf9dd55SDavid Howells 			}
6055cf9dd55SDavid Howells 			afs_fs_inline_bulk_status(&fc,
6065cf9dd55SDavid Howells 						  afs_v2net(dvnode),
6075cf9dd55SDavid Howells 						  cookie->fids,
6085cf9dd55SDavid Howells 						  cookie->statuses,
6095cf9dd55SDavid Howells 						  cookie->callbacks,
6105cf9dd55SDavid Howells 						  cookie->nr_fids, NULL);
6115cf9dd55SDavid Howells 		}
6125cf9dd55SDavid Howells 
6135cf9dd55SDavid Howells 		if (fc.ac.error == 0)
6145cf9dd55SDavid Howells 			cbi = afs_get_cb_interest(fc.cbi);
6155cf9dd55SDavid Howells 		if (fc.ac.abort_code == RX_INVALID_OPERATION)
6165cf9dd55SDavid Howells 			set_bit(AFS_SERVER_FL_NO_IBULK, &fc.cbi->server->flags);
6175cf9dd55SDavid Howells 		inode = ERR_PTR(afs_end_vnode_operation(&fc));
6185cf9dd55SDavid Howells 	}
6195cf9dd55SDavid Howells 
6205cf9dd55SDavid Howells 	if (!IS_ERR(inode))
6215cf9dd55SDavid Howells 		goto success;
6225cf9dd55SDavid Howells 	if (fc.ac.abort_code != RX_INVALID_OPERATION)
6235cf9dd55SDavid Howells 		goto out_c;
6245cf9dd55SDavid Howells 
6255cf9dd55SDavid Howells no_inline_bulk_status:
6265cf9dd55SDavid Howells 	/* We could try FS.BulkStatus next, but this aborts the entire op if
6275cf9dd55SDavid Howells 	 * any of the lookups fails - so, for the moment, revert to
6285cf9dd55SDavid Howells 	 * FS.FetchStatus for just the primary fid.
6295cf9dd55SDavid Howells 	 */
6305cf9dd55SDavid Howells 	cookie->nr_fids = 1;
6315cf9dd55SDavid Howells 	inode = ERR_PTR(-ERESTARTSYS);
6325cf9dd55SDavid Howells 	if (afs_begin_vnode_operation(&fc, dvnode, key)) {
6335cf9dd55SDavid Howells 		while (afs_select_fileserver(&fc)) {
6345cf9dd55SDavid Howells 			afs_fs_fetch_status(&fc,
6355cf9dd55SDavid Howells 					    afs_v2net(dvnode),
6365cf9dd55SDavid Howells 					    cookie->fids,
6375cf9dd55SDavid Howells 					    cookie->statuses,
6385cf9dd55SDavid Howells 					    cookie->callbacks,
6395cf9dd55SDavid Howells 					    NULL);
6405cf9dd55SDavid Howells 		}
6415cf9dd55SDavid Howells 
6425cf9dd55SDavid Howells 		if (fc.ac.error == 0)
6435cf9dd55SDavid Howells 			cbi = afs_get_cb_interest(fc.cbi);
6445cf9dd55SDavid Howells 		inode = ERR_PTR(afs_end_vnode_operation(&fc));
6455cf9dd55SDavid Howells 	}
6465cf9dd55SDavid Howells 
6475cf9dd55SDavid Howells 	if (IS_ERR(inode))
6485cf9dd55SDavid Howells 		goto out_c;
6495cf9dd55SDavid Howells 
6505cf9dd55SDavid Howells 	for (i = 0; i < cookie->nr_fids; i++)
6515cf9dd55SDavid Howells 		cookie->statuses[i].abort_code = 0;
6525cf9dd55SDavid Howells 
6535cf9dd55SDavid Howells success:
6545cf9dd55SDavid Howells 	/* Turn all the files into inodes and save the first one - which is the
6555cf9dd55SDavid Howells 	 * one we actually want.
6565cf9dd55SDavid Howells 	 */
6575cf9dd55SDavid Howells 	if (cookie->statuses[0].abort_code != 0)
6585cf9dd55SDavid Howells 		inode = ERR_PTR(afs_abort_to_error(cookie->statuses[0].abort_code));
6595cf9dd55SDavid Howells 
6605cf9dd55SDavid Howells 	for (i = 0; i < cookie->nr_fids; i++) {
6615cf9dd55SDavid Howells 		struct inode *ti;
6625cf9dd55SDavid Howells 
6635cf9dd55SDavid Howells 		if (cookie->statuses[i].abort_code != 0)
6645cf9dd55SDavid Howells 			continue;
6655cf9dd55SDavid Howells 
6665cf9dd55SDavid Howells 		ti = afs_iget(dir->i_sb, key, &cookie->fids[i],
6675cf9dd55SDavid Howells 			      &cookie->statuses[i],
6685cf9dd55SDavid Howells 			      &cookie->callbacks[i],
6695cf9dd55SDavid Howells 			      cbi);
6705cf9dd55SDavid Howells 		if (i == 0) {
6715cf9dd55SDavid Howells 			inode = ti;
6725cf9dd55SDavid Howells 		} else {
6735cf9dd55SDavid Howells 			if (!IS_ERR(ti))
6745cf9dd55SDavid Howells 				iput(ti);
6755cf9dd55SDavid Howells 		}
6765cf9dd55SDavid Howells 	}
6775cf9dd55SDavid Howells 
6785cf9dd55SDavid Howells out_c:
6795cf9dd55SDavid Howells 	afs_put_cb_interest(afs_v2net(dvnode), cbi);
6805cf9dd55SDavid Howells 	kfree(cookie->callbacks);
6815cf9dd55SDavid Howells out_s:
6825cf9dd55SDavid Howells 	kfree(cookie->statuses);
6835cf9dd55SDavid Howells out:
6845cf9dd55SDavid Howells 	kfree(cookie);
6855cf9dd55SDavid Howells 	return inode;
6865cf9dd55SDavid Howells }
6875cf9dd55SDavid Howells 
6885cf9dd55SDavid Howells /*
6896f8880d8SDavid Howells  * Look up an entry in a directory with @sys substitution.
6906f8880d8SDavid Howells  */
6916f8880d8SDavid Howells static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry,
6926f8880d8SDavid Howells 				       struct key *key)
6936f8880d8SDavid Howells {
6946f8880d8SDavid Howells 	struct afs_sysnames *subs;
6956f8880d8SDavid Howells 	struct afs_net *net = afs_i2net(dir);
6966f8880d8SDavid Howells 	struct dentry *ret;
6976f8880d8SDavid Howells 	char *buf, *p, *name;
6986f8880d8SDavid Howells 	int len, i;
6996f8880d8SDavid Howells 
7006f8880d8SDavid Howells 	_enter("");
7016f8880d8SDavid Howells 
7026f8880d8SDavid Howells 	ret = ERR_PTR(-ENOMEM);
7036f8880d8SDavid Howells 	p = buf = kmalloc(AFSNAMEMAX, GFP_KERNEL);
7046f8880d8SDavid Howells 	if (!buf)
7056f8880d8SDavid Howells 		goto out_p;
7066f8880d8SDavid Howells 	if (dentry->d_name.len > 4) {
7076f8880d8SDavid Howells 		memcpy(p, dentry->d_name.name, dentry->d_name.len - 4);
7086f8880d8SDavid Howells 		p += dentry->d_name.len - 4;
7096f8880d8SDavid Howells 	}
7106f8880d8SDavid Howells 
7116f8880d8SDavid Howells 	/* There is an ordered list of substitutes that we have to try. */
7126f8880d8SDavid Howells 	read_lock(&net->sysnames_lock);
7136f8880d8SDavid Howells 	subs = net->sysnames;
7146f8880d8SDavid Howells 	refcount_inc(&subs->usage);
7156f8880d8SDavid Howells 	read_unlock(&net->sysnames_lock);
7166f8880d8SDavid Howells 
7176f8880d8SDavid Howells 	for (i = 0; i < subs->nr; i++) {
7186f8880d8SDavid Howells 		name = subs->subs[i];
7196f8880d8SDavid Howells 		len = dentry->d_name.len - 4 + strlen(name);
7206f8880d8SDavid Howells 		if (len >= AFSNAMEMAX) {
7216f8880d8SDavid Howells 			ret = ERR_PTR(-ENAMETOOLONG);
7226f8880d8SDavid Howells 			goto out_s;
7236f8880d8SDavid Howells 		}
7246f8880d8SDavid Howells 
7256f8880d8SDavid Howells 		strcpy(p, name);
7266f8880d8SDavid Howells 		ret = lookup_one_len(buf, dentry->d_parent, len);
7276f8880d8SDavid Howells 		if (IS_ERR(ret) || d_is_positive(ret))
7286f8880d8SDavid Howells 			goto out_s;
7296f8880d8SDavid Howells 		dput(ret);
7306f8880d8SDavid Howells 	}
7316f8880d8SDavid Howells 
7326f8880d8SDavid Howells 	/* We don't want to d_add() the @sys dentry here as we don't want to
7336f8880d8SDavid Howells 	 * the cached dentry to hide changes to the sysnames list.
7346f8880d8SDavid Howells 	 */
7356f8880d8SDavid Howells 	ret = NULL;
7366f8880d8SDavid Howells out_s:
7376f8880d8SDavid Howells 	afs_put_sysnames(subs);
7386f8880d8SDavid Howells 	kfree(buf);
7396f8880d8SDavid Howells out_p:
7406f8880d8SDavid Howells 	key_put(key);
7416f8880d8SDavid Howells 	return ret;
7426f8880d8SDavid Howells }
7436f8880d8SDavid Howells 
7446f8880d8SDavid Howells /*
74508e0e7c8SDavid Howells  * look up an entry in a directory
74608e0e7c8SDavid Howells  */
747260a9803SDavid Howells static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
74800cd8dd3SAl Viro 				 unsigned int flags)
74908e0e7c8SDavid Howells {
7505cf9dd55SDavid Howells 	struct afs_vnode *dvnode = AFS_FS_I(dir);
75108e0e7c8SDavid Howells 	struct inode *inode;
75200d3b7a4SDavid Howells 	struct key *key;
75308e0e7c8SDavid Howells 	int ret;
75408e0e7c8SDavid Howells 
755a455589fSAl Viro 	_enter("{%x:%u},%p{%pd},",
7565cf9dd55SDavid Howells 	       dvnode->fid.vid, dvnode->fid.vnode, dentry, dentry);
757260a9803SDavid Howells 
7582b0143b5SDavid Howells 	ASSERTCMP(d_inode(dentry), ==, NULL);
75908e0e7c8SDavid Howells 
76045222b9eSDavid Howells 	if (dentry->d_name.len >= AFSNAMEMAX) {
76108e0e7c8SDavid Howells 		_leave(" = -ENAMETOOLONG");
76208e0e7c8SDavid Howells 		return ERR_PTR(-ENAMETOOLONG);
76308e0e7c8SDavid Howells 	}
76408e0e7c8SDavid Howells 
7655cf9dd55SDavid Howells 	if (test_bit(AFS_VNODE_DELETED, &dvnode->flags)) {
76608e0e7c8SDavid Howells 		_leave(" = -ESTALE");
76708e0e7c8SDavid Howells 		return ERR_PTR(-ESTALE);
76808e0e7c8SDavid Howells 	}
76908e0e7c8SDavid Howells 
7705cf9dd55SDavid Howells 	key = afs_request_key(dvnode->volume->cell);
77100d3b7a4SDavid Howells 	if (IS_ERR(key)) {
77200d3b7a4SDavid Howells 		_leave(" = %ld [key]", PTR_ERR(key));
773e231c2eeSDavid Howells 		return ERR_CAST(key);
77400d3b7a4SDavid Howells 	}
77500d3b7a4SDavid Howells 
7765cf9dd55SDavid Howells 	ret = afs_validate(dvnode, key);
77708e0e7c8SDavid Howells 	if (ret < 0) {
77800d3b7a4SDavid Howells 		key_put(key);
779260a9803SDavid Howells 		_leave(" = %d [val]", ret);
7801da177e4SLinus Torvalds 		return ERR_PTR(ret);
7811da177e4SLinus Torvalds 	}
7821da177e4SLinus Torvalds 
7836f8880d8SDavid Howells 	if (dentry->d_name.len >= 4 &&
7846f8880d8SDavid Howells 	    dentry->d_name.name[dentry->d_name.len - 4] == '@' &&
7856f8880d8SDavid Howells 	    dentry->d_name.name[dentry->d_name.len - 3] == 's' &&
7866f8880d8SDavid Howells 	    dentry->d_name.name[dentry->d_name.len - 2] == 'y' &&
7876f8880d8SDavid Howells 	    dentry->d_name.name[dentry->d_name.len - 1] == 's')
7886f8880d8SDavid Howells 		return afs_lookup_atsys(dir, dentry, key);
7896f8880d8SDavid Howells 
790d55b4da4SDavid Howells 	afs_stat_v(dvnode, n_lookup);
7915cf9dd55SDavid Howells 	inode = afs_do_lookup(dir, dentry, key);
7925cf9dd55SDavid Howells 	if (IS_ERR(inode)) {
7935cf9dd55SDavid Howells 		ret = PTR_ERR(inode);
7944d673da1SDavid Howells 		if (ret == -ENOENT) {
7955cf9dd55SDavid Howells 			inode = afs_try_auto_mntpt(dentry, dir);
796bec5eb61Swanglei 			if (!IS_ERR(inode)) {
797bec5eb61Swanglei 				key_put(key);
798bec5eb61Swanglei 				goto success;
799bec5eb61Swanglei 			}
800bec5eb61Swanglei 
801bec5eb61Swanglei 			ret = PTR_ERR(inode);
8024d673da1SDavid Howells 		}
8034d673da1SDavid Howells 
804260a9803SDavid Howells 		key_put(key);
805260a9803SDavid Howells 		if (ret == -ENOENT) {
806260a9803SDavid Howells 			d_add(dentry, NULL);
807260a9803SDavid Howells 			_leave(" = NULL [negative]");
808260a9803SDavid Howells 			return NULL;
809260a9803SDavid Howells 		}
810260a9803SDavid Howells 		_leave(" = %d [do]", ret);
811260a9803SDavid Howells 		return ERR_PTR(ret);
812260a9803SDavid Howells 	}
8135cf9dd55SDavid Howells 	dentry->d_fsdata = (void *)(unsigned long)dvnode->status.data_version;
814260a9803SDavid Howells 
8151da177e4SLinus Torvalds 	/* instantiate the dentry */
81600d3b7a4SDavid Howells 	key_put(key);
81708e0e7c8SDavid Howells 	if (IS_ERR(inode)) {
81808e0e7c8SDavid Howells 		_leave(" = %ld", PTR_ERR(inode));
819e231c2eeSDavid Howells 		return ERR_CAST(inode);
8201da177e4SLinus Torvalds 	}
8211da177e4SLinus Torvalds 
822bec5eb61Swanglei success:
8231da177e4SLinus Torvalds 	d_add(dentry, inode);
8245cf9dd55SDavid Howells 	_leave(" = 0 { ino=%lu v=%u }",
8252b0143b5SDavid Howells 	       d_inode(dentry)->i_ino,
8262b0143b5SDavid Howells 	       d_inode(dentry)->i_generation);
8271da177e4SLinus Torvalds 
8281da177e4SLinus Torvalds 	return NULL;
829ec26815aSDavid Howells }
8301da177e4SLinus Torvalds 
8311da177e4SLinus Torvalds /*
8321da177e4SLinus Torvalds  * check that a dentry lookup hit has found a valid entry
8331da177e4SLinus Torvalds  * - NOTE! the hit can be a negative hit too, so we can't assume we have an
8341da177e4SLinus Torvalds  *   inode
8351da177e4SLinus Torvalds  */
8360b728e19SAl Viro static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
8371da177e4SLinus Torvalds {
838260a9803SDavid Howells 	struct afs_vnode *vnode, *dir;
839dd0d9a46SArtem Bityutskiy 	struct afs_fid uninitialized_var(fid);
8401da177e4SLinus Torvalds 	struct dentry *parent;
841c435ee34SDavid Howells 	struct inode *inode;
84200d3b7a4SDavid Howells 	struct key *key;
843a4ff7401SDavid Howells 	long dir_version, de_version;
8441da177e4SLinus Torvalds 	int ret;
8451da177e4SLinus Torvalds 
8460b728e19SAl Viro 	if (flags & LOOKUP_RCU)
84734286d66SNick Piggin 		return -ECHILD;
84834286d66SNick Piggin 
849c435ee34SDavid Howells 	if (d_really_is_positive(dentry)) {
8502b0143b5SDavid Howells 		vnode = AFS_FS_I(d_inode(dentry));
851a455589fSAl Viro 		_enter("{v={%x:%u} n=%pd fl=%lx},",
852a455589fSAl Viro 		       vnode->fid.vid, vnode->fid.vnode, dentry,
853260a9803SDavid Howells 		       vnode->flags);
854c435ee34SDavid Howells 	} else {
855a455589fSAl Viro 		_enter("{neg n=%pd}", dentry);
856c435ee34SDavid Howells 	}
8571da177e4SLinus Torvalds 
858260a9803SDavid Howells 	key = afs_request_key(AFS_FS_S(dentry->d_sb)->volume->cell);
85900d3b7a4SDavid Howells 	if (IS_ERR(key))
86000d3b7a4SDavid Howells 		key = NULL;
86100d3b7a4SDavid Howells 
862c435ee34SDavid Howells 	if (d_really_is_positive(dentry)) {
863c435ee34SDavid Howells 		inode = d_inode(dentry);
864c435ee34SDavid Howells 		if (inode) {
865c435ee34SDavid Howells 			vnode = AFS_FS_I(inode);
866c435ee34SDavid Howells 			afs_validate(vnode, key);
867c435ee34SDavid Howells 			if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
868c435ee34SDavid Howells 				goto out_bad;
869c435ee34SDavid Howells 		}
870c435ee34SDavid Howells 	}
871c435ee34SDavid Howells 
8721da177e4SLinus Torvalds 	/* lock down the parent dentry so we can peer at it */
87308e0e7c8SDavid Howells 	parent = dget_parent(dentry);
8742b0143b5SDavid Howells 	dir = AFS_FS_I(d_inode(parent));
8751da177e4SLinus Torvalds 
876260a9803SDavid Howells 	/* validate the parent directory */
877260a9803SDavid Howells 	afs_validate(dir, key);
878260a9803SDavid Howells 
879260a9803SDavid Howells 	if (test_bit(AFS_VNODE_DELETED, &dir->flags)) {
880a455589fSAl Viro 		_debug("%pd: parent dir deleted", dentry);
881c435ee34SDavid Howells 		goto out_bad_parent;
8821da177e4SLinus Torvalds 	}
8831da177e4SLinus Torvalds 
884a4ff7401SDavid Howells 	/* We only need to invalidate a dentry if the server's copy changed
885a4ff7401SDavid Howells 	 * behind our back.  If we made the change, it's no problem.  Note that
886a4ff7401SDavid Howells 	 * on a 32-bit system, we only have 32 bits in the dentry to store the
887a4ff7401SDavid Howells 	 * version.
888a4ff7401SDavid Howells 	 */
889a4ff7401SDavid Howells 	dir_version = (long)dir->status.data_version;
890a4ff7401SDavid Howells 	de_version = (long)dentry->d_fsdata;
891a4ff7401SDavid Howells 	if (de_version == dir_version)
892a4ff7401SDavid Howells 		goto out_valid;
893a4ff7401SDavid Howells 
894a4ff7401SDavid Howells 	dir_version = (long)dir->invalid_before;
895a4ff7401SDavid Howells 	if (de_version - dir_version >= 0)
896a4ff7401SDavid Howells 		goto out_valid;
897260a9803SDavid Howells 
89808e0e7c8SDavid Howells 	_debug("dir modified");
899d55b4da4SDavid Howells 	afs_stat_v(dir, n_reval);
9001da177e4SLinus Torvalds 
9011da177e4SLinus Torvalds 	/* search the directory for this vnode */
9025cf9dd55SDavid Howells 	ret = afs_do_lookup_one(&dir->vfs_inode, dentry, &fid, key);
903260a9803SDavid Howells 	switch (ret) {
904260a9803SDavid Howells 	case 0:
905260a9803SDavid Howells 		/* the filename maps to something */
9062b0143b5SDavid Howells 		if (d_really_is_negative(dentry))
907c435ee34SDavid Howells 			goto out_bad_parent;
908c435ee34SDavid Howells 		inode = d_inode(dentry);
909c435ee34SDavid Howells 		if (is_bad_inode(inode)) {
910a455589fSAl Viro 			printk("kAFS: afs_d_revalidate: %pd2 has bad inode\n",
911a455589fSAl Viro 			       dentry);
912c435ee34SDavid Howells 			goto out_bad_parent;
9131da177e4SLinus Torvalds 		}
9141da177e4SLinus Torvalds 
915c435ee34SDavid Howells 		vnode = AFS_FS_I(inode);
916c435ee34SDavid Howells 
9171da177e4SLinus Torvalds 		/* if the vnode ID has changed, then the dirent points to a
9181da177e4SLinus Torvalds 		 * different file */
91908e0e7c8SDavid Howells 		if (fid.vnode != vnode->fid.vnode) {
920a455589fSAl Viro 			_debug("%pd: dirent changed [%u != %u]",
921a455589fSAl Viro 			       dentry, fid.vnode,
92208e0e7c8SDavid Howells 			       vnode->fid.vnode);
9231da177e4SLinus Torvalds 			goto not_found;
9241da177e4SLinus Torvalds 		}
9251da177e4SLinus Torvalds 
9261da177e4SLinus Torvalds 		/* if the vnode ID uniqifier has changed, then the file has
927260a9803SDavid Howells 		 * been deleted and replaced, and the original vnode ID has
928260a9803SDavid Howells 		 * been reused */
92908e0e7c8SDavid Howells 		if (fid.unique != vnode->fid.unique) {
930a455589fSAl Viro 			_debug("%pd: file deleted (uq %u -> %u I:%u)",
931a455589fSAl Viro 			       dentry, fid.unique,
9327a224228SJean Noel Cordenner 			       vnode->fid.unique,
933c435ee34SDavid Howells 			       vnode->vfs_inode.i_generation);
934c435ee34SDavid Howells 			write_seqlock(&vnode->cb_lock);
93508e0e7c8SDavid Howells 			set_bit(AFS_VNODE_DELETED, &vnode->flags);
936c435ee34SDavid Howells 			write_sequnlock(&vnode->cb_lock);
937260a9803SDavid Howells 			goto not_found;
938260a9803SDavid Howells 		}
939260a9803SDavid Howells 		goto out_valid;
940260a9803SDavid Howells 
941260a9803SDavid Howells 	case -ENOENT:
942260a9803SDavid Howells 		/* the filename is unknown */
943a455589fSAl Viro 		_debug("%pd: dirent not found", dentry);
9442b0143b5SDavid Howells 		if (d_really_is_positive(dentry))
945260a9803SDavid Howells 			goto not_found;
946260a9803SDavid Howells 		goto out_valid;
947260a9803SDavid Howells 
948260a9803SDavid Howells 	default:
949a455589fSAl Viro 		_debug("failed to iterate dir %pd: %d",
950a455589fSAl Viro 		       parent, ret);
951c435ee34SDavid Howells 		goto out_bad_parent;
9521da177e4SLinus Torvalds 	}
95308e0e7c8SDavid Howells 
9541da177e4SLinus Torvalds out_valid:
955a4ff7401SDavid Howells 	dentry->d_fsdata = (void *)dir_version;
9561da177e4SLinus Torvalds 	dput(parent);
95700d3b7a4SDavid Howells 	key_put(key);
9581da177e4SLinus Torvalds 	_leave(" = 1 [valid]");
9591da177e4SLinus Torvalds 	return 1;
9601da177e4SLinus Torvalds 
9611da177e4SLinus Torvalds 	/* the dirent, if it exists, now points to a different vnode */
9621da177e4SLinus Torvalds not_found:
9631da177e4SLinus Torvalds 	spin_lock(&dentry->d_lock);
9641da177e4SLinus Torvalds 	dentry->d_flags |= DCACHE_NFSFS_RENAMED;
9651da177e4SLinus Torvalds 	spin_unlock(&dentry->d_lock);
9661da177e4SLinus Torvalds 
967c435ee34SDavid Howells out_bad_parent:
968a455589fSAl Viro 	_debug("dropping dentry %pd2", dentry);
9691da177e4SLinus Torvalds 	dput(parent);
970c435ee34SDavid Howells out_bad:
97100d3b7a4SDavid Howells 	key_put(key);
9721da177e4SLinus Torvalds 
9731da177e4SLinus Torvalds 	_leave(" = 0 [bad]");
9741da177e4SLinus Torvalds 	return 0;
975ec26815aSDavid Howells }
9761da177e4SLinus Torvalds 
9771da177e4SLinus Torvalds /*
9781da177e4SLinus Torvalds  * allow the VFS to enquire as to whether a dentry should be unhashed (mustn't
9791da177e4SLinus Torvalds  * sleep)
9801da177e4SLinus Torvalds  * - called from dput() when d_count is going to 0.
9811da177e4SLinus Torvalds  * - return 1 to request dentry be unhashed, 0 otherwise
9821da177e4SLinus Torvalds  */
983fe15ce44SNick Piggin static int afs_d_delete(const struct dentry *dentry)
9841da177e4SLinus Torvalds {
985a455589fSAl Viro 	_enter("%pd", dentry);
9861da177e4SLinus Torvalds 
9871da177e4SLinus Torvalds 	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
9881da177e4SLinus Torvalds 		goto zap;
9891da177e4SLinus Torvalds 
9902b0143b5SDavid Howells 	if (d_really_is_positive(dentry) &&
9912b0143b5SDavid Howells 	    (test_bit(AFS_VNODE_DELETED,   &AFS_FS_I(d_inode(dentry))->flags) ||
9922b0143b5SDavid Howells 	     test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(d_inode(dentry))->flags)))
9931da177e4SLinus Torvalds 		goto zap;
9941da177e4SLinus Torvalds 
9951da177e4SLinus Torvalds 	_leave(" = 0 [keep]");
9961da177e4SLinus Torvalds 	return 0;
9971da177e4SLinus Torvalds 
9981da177e4SLinus Torvalds zap:
9991da177e4SLinus Torvalds 	_leave(" = 1 [zap]");
10001da177e4SLinus Torvalds 	return 1;
1001ec26815aSDavid Howells }
1002260a9803SDavid Howells 
1003260a9803SDavid Howells /*
1004260a9803SDavid Howells  * handle dentry release
1005260a9803SDavid Howells  */
100666c7e1d3SDavid Howells void afs_d_release(struct dentry *dentry)
1007260a9803SDavid Howells {
1008a455589fSAl Viro 	_enter("%pd", dentry);
1009260a9803SDavid Howells }
1010260a9803SDavid Howells 
1011260a9803SDavid Howells /*
1012d2ddc776SDavid Howells  * Create a new inode for create/mkdir/symlink
1013d2ddc776SDavid Howells  */
1014d2ddc776SDavid Howells static void afs_vnode_new_inode(struct afs_fs_cursor *fc,
1015d2ddc776SDavid Howells 				struct dentry *new_dentry,
1016d2ddc776SDavid Howells 				struct afs_fid *newfid,
1017d2ddc776SDavid Howells 				struct afs_file_status *newstatus,
1018d2ddc776SDavid Howells 				struct afs_callback *newcb)
1019d2ddc776SDavid Howells {
1020d2ddc776SDavid Howells 	struct inode *inode;
1021d2ddc776SDavid Howells 
1022d2ddc776SDavid Howells 	if (fc->ac.error < 0)
1023d2ddc776SDavid Howells 		return;
1024d2ddc776SDavid Howells 
1025bc1527dcSDavid Howells 	d_drop(new_dentry);
1026bc1527dcSDavid Howells 
1027d2ddc776SDavid Howells 	inode = afs_iget(fc->vnode->vfs_inode.i_sb, fc->key,
1028d2ddc776SDavid Howells 			 newfid, newstatus, newcb, fc->cbi);
1029d2ddc776SDavid Howells 	if (IS_ERR(inode)) {
1030d2ddc776SDavid Howells 		/* ENOMEM or EINTR at a really inconvenient time - just abandon
1031d2ddc776SDavid Howells 		 * the new directory on the server.
1032d2ddc776SDavid Howells 		 */
1033d2ddc776SDavid Howells 		fc->ac.error = PTR_ERR(inode);
1034d2ddc776SDavid Howells 		return;
1035d2ddc776SDavid Howells 	}
1036d2ddc776SDavid Howells 
1037bc1527dcSDavid Howells 	d_add(new_dentry, inode);
1038d2ddc776SDavid Howells }
1039d2ddc776SDavid Howells 
1040d2ddc776SDavid Howells /*
1041260a9803SDavid Howells  * create a directory on an AFS filesystem
1042260a9803SDavid Howells  */
104318bb1db3SAl Viro static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
1044260a9803SDavid Howells {
1045d2ddc776SDavid Howells 	struct afs_file_status newstatus;
1046d2ddc776SDavid Howells 	struct afs_fs_cursor fc;
1047d2ddc776SDavid Howells 	struct afs_callback newcb;
1048d2ddc776SDavid Howells 	struct afs_vnode *dvnode = AFS_FS_I(dir);
1049d2ddc776SDavid Howells 	struct afs_fid newfid;
1050260a9803SDavid Howells 	struct key *key;
1051260a9803SDavid Howells 	int ret;
1052260a9803SDavid Howells 
1053d2ddc776SDavid Howells 	mode |= S_IFDIR;
1054260a9803SDavid Howells 
1055a455589fSAl Viro 	_enter("{%x:%u},{%pd},%ho",
1056a455589fSAl Viro 	       dvnode->fid.vid, dvnode->fid.vnode, dentry, mode);
1057260a9803SDavid Howells 
1058260a9803SDavid Howells 	key = afs_request_key(dvnode->volume->cell);
1059260a9803SDavid Howells 	if (IS_ERR(key)) {
1060260a9803SDavid Howells 		ret = PTR_ERR(key);
1061260a9803SDavid Howells 		goto error;
1062260a9803SDavid Howells 	}
1063260a9803SDavid Howells 
1064d2ddc776SDavid Howells 	ret = -ERESTARTSYS;
1065d2ddc776SDavid Howells 	if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1066d2ddc776SDavid Howells 		while (afs_select_fileserver(&fc)) {
1067d2ddc776SDavid Howells 			fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
1068d2ddc776SDavid Howells 			afs_fs_create(&fc, dentry->d_name.name, mode,
1069d2ddc776SDavid Howells 				      &newfid, &newstatus, &newcb);
1070d2ddc776SDavid Howells 		}
1071d2ddc776SDavid Howells 
1072d2ddc776SDavid Howells 		afs_check_for_remote_deletion(&fc, fc.vnode);
1073d2ddc776SDavid Howells 		afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
1074d2ddc776SDavid Howells 		afs_vnode_new_inode(&fc, dentry, &newfid, &newstatus, &newcb);
1075d2ddc776SDavid Howells 		ret = afs_end_vnode_operation(&fc);
1076260a9803SDavid Howells 		if (ret < 0)
1077d2ddc776SDavid Howells 			goto error_key;
10784433b691SDavid Howells 	} else {
10794433b691SDavid Howells 		goto error_key;
1080260a9803SDavid Howells 	}
1081260a9803SDavid Howells 
1082260a9803SDavid Howells 	key_put(key);
1083260a9803SDavid Howells 	_leave(" = 0");
1084260a9803SDavid Howells 	return 0;
1085260a9803SDavid Howells 
1086d2ddc776SDavid Howells error_key:
1087260a9803SDavid Howells 	key_put(key);
1088260a9803SDavid Howells error:
1089260a9803SDavid Howells 	d_drop(dentry);
1090260a9803SDavid Howells 	_leave(" = %d", ret);
1091260a9803SDavid Howells 	return ret;
1092260a9803SDavid Howells }
1093260a9803SDavid Howells 
1094260a9803SDavid Howells /*
1095d2ddc776SDavid Howells  * Remove a subdir from a directory.
1096260a9803SDavid Howells  */
1097d2ddc776SDavid Howells static void afs_dir_remove_subdir(struct dentry *dentry)
1098260a9803SDavid Howells {
10992b0143b5SDavid Howells 	if (d_really_is_positive(dentry)) {
1100d2ddc776SDavid Howells 		struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
1101d2ddc776SDavid Howells 
1102260a9803SDavid Howells 		clear_nlink(&vnode->vfs_inode);
1103260a9803SDavid Howells 		set_bit(AFS_VNODE_DELETED, &vnode->flags);
1104c435ee34SDavid Howells 		clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
1105260a9803SDavid Howells 	}
1106260a9803SDavid Howells }
1107260a9803SDavid Howells 
1108260a9803SDavid Howells /*
1109d2ddc776SDavid Howells  * remove a directory from an AFS filesystem
1110260a9803SDavid Howells  */
1111d2ddc776SDavid Howells static int afs_rmdir(struct inode *dir, struct dentry *dentry)
1112260a9803SDavid Howells {
1113d2ddc776SDavid Howells 	struct afs_fs_cursor fc;
1114d2ddc776SDavid Howells 	struct afs_vnode *dvnode = AFS_FS_I(dir);
1115260a9803SDavid Howells 	struct key *key;
1116260a9803SDavid Howells 	int ret;
1117260a9803SDavid Howells 
1118a455589fSAl Viro 	_enter("{%x:%u},{%pd}",
1119a455589fSAl Viro 	       dvnode->fid.vid, dvnode->fid.vnode, dentry);
1120260a9803SDavid Howells 
1121260a9803SDavid Howells 	key = afs_request_key(dvnode->volume->cell);
1122260a9803SDavid Howells 	if (IS_ERR(key)) {
1123260a9803SDavid Howells 		ret = PTR_ERR(key);
1124260a9803SDavid Howells 		goto error;
1125260a9803SDavid Howells 	}
1126260a9803SDavid Howells 
1127d2ddc776SDavid Howells 	ret = -ERESTARTSYS;
1128d2ddc776SDavid Howells 	if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1129d2ddc776SDavid Howells 		while (afs_select_fileserver(&fc)) {
1130d2ddc776SDavid Howells 			fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
1131d2ddc776SDavid Howells 			afs_fs_remove(&fc, dentry->d_name.name, true);
1132260a9803SDavid Howells 		}
1133260a9803SDavid Howells 
1134d2ddc776SDavid Howells 		afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
1135d2ddc776SDavid Howells 		ret = afs_end_vnode_operation(&fc);
1136d2ddc776SDavid Howells 		if (ret == 0)
1137d2ddc776SDavid Howells 			afs_dir_remove_subdir(dentry);
1138260a9803SDavid Howells 	}
1139260a9803SDavid Howells 
1140260a9803SDavid Howells 	key_put(key);
1141d2ddc776SDavid Howells error:
1142d2ddc776SDavid Howells 	return ret;
1143d2ddc776SDavid Howells }
1144260a9803SDavid Howells 
1145d2ddc776SDavid Howells /*
1146d2ddc776SDavid Howells  * Remove a link to a file or symlink from a directory.
1147d2ddc776SDavid Howells  *
1148d2ddc776SDavid Howells  * If the file was not deleted due to excess hard links, the fileserver will
1149d2ddc776SDavid Howells  * break the callback promise on the file - if it had one - before it returns
1150d2ddc776SDavid Howells  * to us, and if it was deleted, it won't
1151d2ddc776SDavid Howells  *
1152d2ddc776SDavid Howells  * However, if we didn't have a callback promise outstanding, or it was
1153d2ddc776SDavid Howells  * outstanding on a different server, then it won't break it either...
1154d2ddc776SDavid Howells  */
1155440fbc3aSDavid Howells static int afs_dir_remove_link(struct dentry *dentry, struct key *key,
1156440fbc3aSDavid Howells 			       unsigned long d_version_before,
1157440fbc3aSDavid Howells 			       unsigned long d_version_after)
1158d2ddc776SDavid Howells {
1159440fbc3aSDavid Howells 	bool dir_valid;
1160d2ddc776SDavid Howells 	int ret = 0;
1161d2ddc776SDavid Howells 
1162440fbc3aSDavid Howells 	/* There were no intervening changes on the server if the version
1163440fbc3aSDavid Howells 	 * number we got back was incremented by exactly 1.
1164440fbc3aSDavid Howells 	 */
1165440fbc3aSDavid Howells 	dir_valid = (d_version_after == d_version_before + 1);
1166440fbc3aSDavid Howells 
1167d2ddc776SDavid Howells 	if (d_really_is_positive(dentry)) {
1168d2ddc776SDavid Howells 		struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
1169d2ddc776SDavid Howells 
1170440fbc3aSDavid Howells 		if (dir_valid) {
1171440fbc3aSDavid Howells 			drop_nlink(&vnode->vfs_inode);
1172440fbc3aSDavid Howells 			if (vnode->vfs_inode.i_nlink == 0) {
1173440fbc3aSDavid Howells 				set_bit(AFS_VNODE_DELETED, &vnode->flags);
1174440fbc3aSDavid Howells 				clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
1175440fbc3aSDavid Howells 			}
1176440fbc3aSDavid Howells 			ret = 0;
1177440fbc3aSDavid Howells 		} else {
1178440fbc3aSDavid Howells 			clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
1179440fbc3aSDavid Howells 
1180d2ddc776SDavid Howells 			if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
1181d2ddc776SDavid Howells 				kdebug("AFS_VNODE_DELETED");
1182d2ddc776SDavid Howells 
1183d2ddc776SDavid Howells 			ret = afs_validate(vnode, key);
1184d2ddc776SDavid Howells 			if (ret == -ESTALE)
1185d2ddc776SDavid Howells 				ret = 0;
1186440fbc3aSDavid Howells 		}
1187d2ddc776SDavid Howells 		_debug("nlink %d [val %d]", vnode->vfs_inode.i_nlink, ret);
1188d2ddc776SDavid Howells 	}
1189d2ddc776SDavid Howells 
1190d2ddc776SDavid Howells 	return ret;
1191d2ddc776SDavid Howells }
1192d2ddc776SDavid Howells 
1193d2ddc776SDavid Howells /*
1194d2ddc776SDavid Howells  * Remove a file or symlink from an AFS filesystem.
1195d2ddc776SDavid Howells  */
1196d2ddc776SDavid Howells static int afs_unlink(struct inode *dir, struct dentry *dentry)
1197d2ddc776SDavid Howells {
1198d2ddc776SDavid Howells 	struct afs_fs_cursor fc;
1199d2ddc776SDavid Howells 	struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode;
1200d2ddc776SDavid Howells 	struct key *key;
1201440fbc3aSDavid Howells 	unsigned long d_version = (unsigned long)dentry->d_fsdata;
1202d2ddc776SDavid Howells 	int ret;
1203d2ddc776SDavid Howells 
1204d2ddc776SDavid Howells 	_enter("{%x:%u},{%pd}",
1205d2ddc776SDavid Howells 	       dvnode->fid.vid, dvnode->fid.vnode, dentry);
1206d2ddc776SDavid Howells 
1207d2ddc776SDavid Howells 	if (dentry->d_name.len >= AFSNAMEMAX)
1208d2ddc776SDavid Howells 		return -ENAMETOOLONG;
1209d2ddc776SDavid Howells 
1210d2ddc776SDavid Howells 	key = afs_request_key(dvnode->volume->cell);
1211d2ddc776SDavid Howells 	if (IS_ERR(key)) {
1212d2ddc776SDavid Howells 		ret = PTR_ERR(key);
1213d2ddc776SDavid Howells 		goto error;
1214d2ddc776SDavid Howells 	}
1215d2ddc776SDavid Howells 
1216d2ddc776SDavid Howells 	/* Try to make sure we have a callback promise on the victim. */
1217d2ddc776SDavid Howells 	if (d_really_is_positive(dentry)) {
1218d2ddc776SDavid Howells 		vnode = AFS_FS_I(d_inode(dentry));
1219d2ddc776SDavid Howells 		ret = afs_validate(vnode, key);
1220d2ddc776SDavid Howells 		if (ret < 0)
1221d2ddc776SDavid Howells 			goto error_key;
1222d2ddc776SDavid Howells 	}
1223d2ddc776SDavid Howells 
1224d2ddc776SDavid Howells 	ret = -ERESTARTSYS;
1225d2ddc776SDavid Howells 	if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1226d2ddc776SDavid Howells 		while (afs_select_fileserver(&fc)) {
1227d2ddc776SDavid Howells 			fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
1228d2ddc776SDavid Howells 			afs_fs_remove(&fc, dentry->d_name.name, false);
1229d2ddc776SDavid Howells 		}
1230d2ddc776SDavid Howells 
1231d2ddc776SDavid Howells 		afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
1232d2ddc776SDavid Howells 		ret = afs_end_vnode_operation(&fc);
1233d2ddc776SDavid Howells 		if (ret == 0)
1234440fbc3aSDavid Howells 			ret = afs_dir_remove_link(
1235440fbc3aSDavid Howells 				dentry, key, d_version,
1236440fbc3aSDavid Howells 				(unsigned long)dvnode->status.data_version);
1237d2ddc776SDavid Howells 	}
1238d2ddc776SDavid Howells 
1239d2ddc776SDavid Howells error_key:
1240260a9803SDavid Howells 	key_put(key);
1241260a9803SDavid Howells error:
1242260a9803SDavid Howells 	_leave(" = %d", ret);
1243260a9803SDavid Howells 	return ret;
1244260a9803SDavid Howells }
1245260a9803SDavid Howells 
1246260a9803SDavid Howells /*
1247260a9803SDavid Howells  * create a regular file on an AFS filesystem
1248260a9803SDavid Howells  */
12494acdaf27SAl Viro static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
1250ebfc3b49SAl Viro 		      bool excl)
1251260a9803SDavid Howells {
1252d2ddc776SDavid Howells 	struct afs_fs_cursor fc;
1253d2ddc776SDavid Howells 	struct afs_file_status newstatus;
1254d2ddc776SDavid Howells 	struct afs_callback newcb;
125543dd388bSColin Ian King 	struct afs_vnode *dvnode = AFS_FS_I(dir);
1256d2ddc776SDavid Howells 	struct afs_fid newfid;
1257260a9803SDavid Howells 	struct key *key;
1258260a9803SDavid Howells 	int ret;
1259260a9803SDavid Howells 
1260d2ddc776SDavid Howells 	mode |= S_IFREG;
1261260a9803SDavid Howells 
1262a455589fSAl Viro 	_enter("{%x:%u},{%pd},%ho,",
1263a455589fSAl Viro 	       dvnode->fid.vid, dvnode->fid.vnode, dentry, mode);
1264260a9803SDavid Howells 
1265d2ddc776SDavid Howells 	ret = -ENAMETOOLONG;
1266d2ddc776SDavid Howells 	if (dentry->d_name.len >= AFSNAMEMAX)
1267d2ddc776SDavid Howells 		goto error;
1268d2ddc776SDavid Howells 
1269260a9803SDavid Howells 	key = afs_request_key(dvnode->volume->cell);
1270260a9803SDavid Howells 	if (IS_ERR(key)) {
1271260a9803SDavid Howells 		ret = PTR_ERR(key);
1272260a9803SDavid Howells 		goto error;
1273260a9803SDavid Howells 	}
1274260a9803SDavid Howells 
1275d2ddc776SDavid Howells 	ret = -ERESTARTSYS;
1276d2ddc776SDavid Howells 	if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1277d2ddc776SDavid Howells 		while (afs_select_fileserver(&fc)) {
1278d2ddc776SDavid Howells 			fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
1279d2ddc776SDavid Howells 			afs_fs_create(&fc, dentry->d_name.name, mode,
1280d2ddc776SDavid Howells 				      &newfid, &newstatus, &newcb);
1281d2ddc776SDavid Howells 		}
1282d2ddc776SDavid Howells 
1283d2ddc776SDavid Howells 		afs_check_for_remote_deletion(&fc, fc.vnode);
1284d2ddc776SDavid Howells 		afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
1285d2ddc776SDavid Howells 		afs_vnode_new_inode(&fc, dentry, &newfid, &newstatus, &newcb);
1286d2ddc776SDavid Howells 		ret = afs_end_vnode_operation(&fc);
1287260a9803SDavid Howells 		if (ret < 0)
1288d2ddc776SDavid Howells 			goto error_key;
12894433b691SDavid Howells 	} else {
12904433b691SDavid Howells 		goto error_key;
1291260a9803SDavid Howells 	}
1292260a9803SDavid Howells 
1293260a9803SDavid Howells 	key_put(key);
1294260a9803SDavid Howells 	_leave(" = 0");
1295260a9803SDavid Howells 	return 0;
1296260a9803SDavid Howells 
1297d2ddc776SDavid Howells error_key:
1298260a9803SDavid Howells 	key_put(key);
1299260a9803SDavid Howells error:
1300260a9803SDavid Howells 	d_drop(dentry);
1301260a9803SDavid Howells 	_leave(" = %d", ret);
1302260a9803SDavid Howells 	return ret;
1303260a9803SDavid Howells }
1304260a9803SDavid Howells 
1305260a9803SDavid Howells /*
1306260a9803SDavid Howells  * create a hard link between files in an AFS filesystem
1307260a9803SDavid Howells  */
1308260a9803SDavid Howells static int afs_link(struct dentry *from, struct inode *dir,
1309260a9803SDavid Howells 		    struct dentry *dentry)
1310260a9803SDavid Howells {
1311d2ddc776SDavid Howells 	struct afs_fs_cursor fc;
1312260a9803SDavid Howells 	struct afs_vnode *dvnode, *vnode;
1313260a9803SDavid Howells 	struct key *key;
1314260a9803SDavid Howells 	int ret;
1315260a9803SDavid Howells 
13162b0143b5SDavid Howells 	vnode = AFS_FS_I(d_inode(from));
1317260a9803SDavid Howells 	dvnode = AFS_FS_I(dir);
1318260a9803SDavid Howells 
1319a455589fSAl Viro 	_enter("{%x:%u},{%x:%u},{%pd}",
1320260a9803SDavid Howells 	       vnode->fid.vid, vnode->fid.vnode,
1321260a9803SDavid Howells 	       dvnode->fid.vid, dvnode->fid.vnode,
1322a455589fSAl Viro 	       dentry);
1323260a9803SDavid Howells 
1324d2ddc776SDavid Howells 	ret = -ENAMETOOLONG;
1325d2ddc776SDavid Howells 	if (dentry->d_name.len >= AFSNAMEMAX)
1326d2ddc776SDavid Howells 		goto error;
1327d2ddc776SDavid Howells 
1328260a9803SDavid Howells 	key = afs_request_key(dvnode->volume->cell);
1329260a9803SDavid Howells 	if (IS_ERR(key)) {
1330260a9803SDavid Howells 		ret = PTR_ERR(key);
1331260a9803SDavid Howells 		goto error;
1332260a9803SDavid Howells 	}
1333260a9803SDavid Howells 
1334d2ddc776SDavid Howells 	ret = -ERESTARTSYS;
1335d2ddc776SDavid Howells 	if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1336d2ddc776SDavid Howells 		if (mutex_lock_interruptible_nested(&vnode->io_lock, 1) < 0) {
1337d2ddc776SDavid Howells 			afs_end_vnode_operation(&fc);
1338bc1527dcSDavid Howells 			goto error_key;
1339d2ddc776SDavid Howells 		}
1340260a9803SDavid Howells 
1341d2ddc776SDavid Howells 		while (afs_select_fileserver(&fc)) {
1342d2ddc776SDavid Howells 			fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
1343d2ddc776SDavid Howells 			fc.cb_break_2 = vnode->cb_break + vnode->cb_s_break;
1344d2ddc776SDavid Howells 			afs_fs_link(&fc, vnode, dentry->d_name.name);
1345d2ddc776SDavid Howells 		}
1346d2ddc776SDavid Howells 
1347d2ddc776SDavid Howells 		afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
1348d2ddc776SDavid Howells 		afs_vnode_commit_status(&fc, vnode, fc.cb_break_2);
13497de9c6eeSAl Viro 		ihold(&vnode->vfs_inode);
1350260a9803SDavid Howells 		d_instantiate(dentry, &vnode->vfs_inode);
1351d2ddc776SDavid Howells 
1352d2ddc776SDavid Howells 		mutex_unlock(&vnode->io_lock);
1353d2ddc776SDavid Howells 		ret = afs_end_vnode_operation(&fc);
1354d2ddc776SDavid Howells 		if (ret < 0)
1355d2ddc776SDavid Howells 			goto error_key;
13564433b691SDavid Howells 	} else {
13574433b691SDavid Howells 		goto error_key;
1358d2ddc776SDavid Howells 	}
1359d2ddc776SDavid Howells 
1360260a9803SDavid Howells 	key_put(key);
1361260a9803SDavid Howells 	_leave(" = 0");
1362260a9803SDavid Howells 	return 0;
1363260a9803SDavid Howells 
1364d2ddc776SDavid Howells error_key:
1365260a9803SDavid Howells 	key_put(key);
1366260a9803SDavid Howells error:
1367260a9803SDavid Howells 	d_drop(dentry);
1368260a9803SDavid Howells 	_leave(" = %d", ret);
1369260a9803SDavid Howells 	return ret;
1370260a9803SDavid Howells }
1371260a9803SDavid Howells 
1372260a9803SDavid Howells /*
1373260a9803SDavid Howells  * create a symlink in an AFS filesystem
1374260a9803SDavid Howells  */
1375260a9803SDavid Howells static int afs_symlink(struct inode *dir, struct dentry *dentry,
1376260a9803SDavid Howells 		       const char *content)
1377260a9803SDavid Howells {
1378d2ddc776SDavid Howells 	struct afs_fs_cursor fc;
1379d2ddc776SDavid Howells 	struct afs_file_status newstatus;
1380d2ddc776SDavid Howells 	struct afs_vnode *dvnode = AFS_FS_I(dir);
1381d2ddc776SDavid Howells 	struct afs_fid newfid;
1382260a9803SDavid Howells 	struct key *key;
1383260a9803SDavid Howells 	int ret;
1384260a9803SDavid Howells 
1385a455589fSAl Viro 	_enter("{%x:%u},{%pd},%s",
1386a455589fSAl Viro 	       dvnode->fid.vid, dvnode->fid.vnode, dentry,
1387260a9803SDavid Howells 	       content);
1388260a9803SDavid Howells 
1389d2ddc776SDavid Howells 	ret = -ENAMETOOLONG;
1390d2ddc776SDavid Howells 	if (dentry->d_name.len >= AFSNAMEMAX)
1391d2ddc776SDavid Howells 		goto error;
1392d2ddc776SDavid Howells 
1393260a9803SDavid Howells 	ret = -EINVAL;
139445222b9eSDavid Howells 	if (strlen(content) >= AFSPATHMAX)
1395260a9803SDavid Howells 		goto error;
1396260a9803SDavid Howells 
1397260a9803SDavid Howells 	key = afs_request_key(dvnode->volume->cell);
1398260a9803SDavid Howells 	if (IS_ERR(key)) {
1399260a9803SDavid Howells 		ret = PTR_ERR(key);
1400260a9803SDavid Howells 		goto error;
1401260a9803SDavid Howells 	}
1402260a9803SDavid Howells 
1403d2ddc776SDavid Howells 	ret = -ERESTARTSYS;
1404d2ddc776SDavid Howells 	if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1405d2ddc776SDavid Howells 		while (afs_select_fileserver(&fc)) {
1406d2ddc776SDavid Howells 			fc.cb_break = dvnode->cb_break + dvnode->cb_s_break;
1407d2ddc776SDavid Howells 			afs_fs_symlink(&fc, dentry->d_name.name, content,
1408d2ddc776SDavid Howells 				       &newfid, &newstatus);
1409d2ddc776SDavid Howells 		}
1410d2ddc776SDavid Howells 
1411d2ddc776SDavid Howells 		afs_check_for_remote_deletion(&fc, fc.vnode);
1412d2ddc776SDavid Howells 		afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
1413d2ddc776SDavid Howells 		afs_vnode_new_inode(&fc, dentry, &newfid, &newstatus, NULL);
1414d2ddc776SDavid Howells 		ret = afs_end_vnode_operation(&fc);
1415260a9803SDavid Howells 		if (ret < 0)
1416d2ddc776SDavid Howells 			goto error_key;
14174433b691SDavid Howells 	} else {
14184433b691SDavid Howells 		goto error_key;
1419260a9803SDavid Howells 	}
1420260a9803SDavid Howells 
1421260a9803SDavid Howells 	key_put(key);
1422260a9803SDavid Howells 	_leave(" = 0");
1423260a9803SDavid Howells 	return 0;
1424260a9803SDavid Howells 
1425d2ddc776SDavid Howells error_key:
1426260a9803SDavid Howells 	key_put(key);
1427260a9803SDavid Howells error:
1428260a9803SDavid Howells 	d_drop(dentry);
1429260a9803SDavid Howells 	_leave(" = %d", ret);
1430260a9803SDavid Howells 	return ret;
1431260a9803SDavid Howells }
1432260a9803SDavid Howells 
1433260a9803SDavid Howells /*
1434260a9803SDavid Howells  * rename a file in an AFS filesystem and/or move it between directories
1435260a9803SDavid Howells  */
1436260a9803SDavid Howells static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
14371cd66c93SMiklos Szeredi 		      struct inode *new_dir, struct dentry *new_dentry,
14381cd66c93SMiklos Szeredi 		      unsigned int flags)
1439260a9803SDavid Howells {
1440d2ddc776SDavid Howells 	struct afs_fs_cursor fc;
1441260a9803SDavid Howells 	struct afs_vnode *orig_dvnode, *new_dvnode, *vnode;
1442260a9803SDavid Howells 	struct key *key;
1443260a9803SDavid Howells 	int ret;
1444260a9803SDavid Howells 
14451cd66c93SMiklos Szeredi 	if (flags)
14461cd66c93SMiklos Szeredi 		return -EINVAL;
14471cd66c93SMiklos Szeredi 
14482b0143b5SDavid Howells 	vnode = AFS_FS_I(d_inode(old_dentry));
1449260a9803SDavid Howells 	orig_dvnode = AFS_FS_I(old_dir);
1450260a9803SDavid Howells 	new_dvnode = AFS_FS_I(new_dir);
1451260a9803SDavid Howells 
1452a455589fSAl Viro 	_enter("{%x:%u},{%x:%u},{%x:%u},{%pd}",
1453260a9803SDavid Howells 	       orig_dvnode->fid.vid, orig_dvnode->fid.vnode,
1454260a9803SDavid Howells 	       vnode->fid.vid, vnode->fid.vnode,
1455260a9803SDavid Howells 	       new_dvnode->fid.vid, new_dvnode->fid.vnode,
1456a455589fSAl Viro 	       new_dentry);
1457260a9803SDavid Howells 
1458260a9803SDavid Howells 	key = afs_request_key(orig_dvnode->volume->cell);
1459260a9803SDavid Howells 	if (IS_ERR(key)) {
1460260a9803SDavid Howells 		ret = PTR_ERR(key);
1461260a9803SDavid Howells 		goto error;
1462260a9803SDavid Howells 	}
1463260a9803SDavid Howells 
1464d2ddc776SDavid Howells 	ret = -ERESTARTSYS;
1465d2ddc776SDavid Howells 	if (afs_begin_vnode_operation(&fc, orig_dvnode, key)) {
1466d2ddc776SDavid Howells 		if (orig_dvnode != new_dvnode) {
1467d2ddc776SDavid Howells 			if (mutex_lock_interruptible_nested(&new_dvnode->io_lock, 1) < 0) {
1468d2ddc776SDavid Howells 				afs_end_vnode_operation(&fc);
1469bc1527dcSDavid Howells 				goto error_key;
1470d2ddc776SDavid Howells 			}
1471d2ddc776SDavid Howells 		}
1472d2ddc776SDavid Howells 		while (afs_select_fileserver(&fc)) {
1473d2ddc776SDavid Howells 			fc.cb_break = orig_dvnode->cb_break + orig_dvnode->cb_s_break;
1474d2ddc776SDavid Howells 			fc.cb_break_2 = new_dvnode->cb_break + new_dvnode->cb_s_break;
1475d2ddc776SDavid Howells 			afs_fs_rename(&fc, old_dentry->d_name.name,
1476d2ddc776SDavid Howells 				      new_dvnode, new_dentry->d_name.name);
1477d2ddc776SDavid Howells 		}
1478d2ddc776SDavid Howells 
1479d2ddc776SDavid Howells 		afs_vnode_commit_status(&fc, orig_dvnode, fc.cb_break);
1480d2ddc776SDavid Howells 		afs_vnode_commit_status(&fc, new_dvnode, fc.cb_break_2);
1481d2ddc776SDavid Howells 		if (orig_dvnode != new_dvnode)
1482d2ddc776SDavid Howells 			mutex_unlock(&new_dvnode->io_lock);
1483d2ddc776SDavid Howells 		ret = afs_end_vnode_operation(&fc);
1484260a9803SDavid Howells 		if (ret < 0)
1485d2ddc776SDavid Howells 			goto error_key;
1486d2ddc776SDavid Howells 	}
1487d2ddc776SDavid Howells 
1488d2ddc776SDavid Howells error_key:
1489260a9803SDavid Howells 	key_put(key);
1490260a9803SDavid Howells error:
1491260a9803SDavid Howells 	_leave(" = %d", ret);
1492260a9803SDavid Howells 	return ret;
1493260a9803SDavid Howells }
1494