12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* dir.c: AFS filesystem directory handling 31da177e4SLinus Torvalds * 4f3ddee8dSDavid Howells * Copyright (C) 2002, 2018 Red Hat, Inc. All Rights Reserved. 51da177e4SLinus Torvalds * Written by David Howells (dhowells@redhat.com) 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 81da177e4SLinus Torvalds #include <linux/kernel.h> 91da177e4SLinus Torvalds #include <linux/fs.h> 1034286d66SNick Piggin #include <linux/namei.h> 111da177e4SLinus Torvalds #include <linux/pagemap.h> 12f3ddee8dSDavid Howells #include <linux/swap.h> 1300d3b7a4SDavid Howells #include <linux/ctype.h> 14e8edc6e0SAlexey Dobriyan #include <linux/sched.h> 15f3ddee8dSDavid Howells #include <linux/task_io_accounting_ops.h> 161da177e4SLinus Torvalds #include "internal.h" 17a58823acSDavid Howells #include "afs_fs.h" 184ea219a8SDavid Howells #include "xdr_fs.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); 2679ddbfa5SDavid Howells static void afs_d_iput(struct dentry *dentry, struct inode *inode); 275cf9dd55SDavid Howells static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen, 285cf9dd55SDavid Howells loff_t fpos, u64 ino, unsigned dtype); 29ac7576f4SMiklos Szeredi static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen, 30afefdbb2SDavid Howells loff_t fpos, u64 ino, unsigned dtype); 31549c7297SChristian Brauner static int afs_create(struct user_namespace *mnt_userns, struct inode *dir, 32549c7297SChristian Brauner struct dentry *dentry, umode_t mode, bool excl); 33549c7297SChristian Brauner static int afs_mkdir(struct user_namespace *mnt_userns, struct inode *dir, 34549c7297SChristian Brauner struct dentry *dentry, umode_t mode); 35260a9803SDavid Howells static int afs_rmdir(struct inode *dir, struct dentry *dentry); 36260a9803SDavid Howells static int afs_unlink(struct inode *dir, struct dentry *dentry); 37260a9803SDavid Howells static int afs_link(struct dentry *from, struct inode *dir, 38260a9803SDavid Howells struct dentry *dentry); 39549c7297SChristian Brauner static int afs_symlink(struct user_namespace *mnt_userns, struct inode *dir, 40549c7297SChristian Brauner struct dentry *dentry, const char *content); 41549c7297SChristian Brauner static int afs_rename(struct user_namespace *mnt_userns, struct inode *old_dir, 42549c7297SChristian Brauner struct dentry *old_dentry, struct inode *new_dir, 43549c7297SChristian Brauner struct dentry *new_dentry, unsigned int flags); 44f3ddee8dSDavid Howells static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags); 45f3ddee8dSDavid Howells static void afs_dir_invalidatepage(struct page *page, unsigned int offset, 46f3ddee8dSDavid Howells unsigned int length); 47f3ddee8dSDavid Howells 48f3ddee8dSDavid Howells static int afs_dir_set_page_dirty(struct page *page) 49f3ddee8dSDavid Howells { 50f3ddee8dSDavid Howells BUG(); /* This should never happen. */ 51f3ddee8dSDavid Howells } 521da177e4SLinus Torvalds 534b6f5d20SArjan van de Ven const struct file_operations afs_dir_file_operations = { 541da177e4SLinus Torvalds .open = afs_dir_open, 5500d3b7a4SDavid Howells .release = afs_release, 5629884effSAl Viro .iterate_shared = afs_readdir, 57e8d6c554SDavid Howells .lock = afs_lock, 583222a3e5SChristoph Hellwig .llseek = generic_file_llseek, 591da177e4SLinus Torvalds }; 601da177e4SLinus Torvalds 61754661f1SArjan van de Ven const struct inode_operations afs_dir_inode_operations = { 62260a9803SDavid Howells .create = afs_create, 63260a9803SDavid Howells .lookup = afs_lookup, 64260a9803SDavid Howells .link = afs_link, 65260a9803SDavid Howells .unlink = afs_unlink, 66260a9803SDavid Howells .symlink = afs_symlink, 67260a9803SDavid Howells .mkdir = afs_mkdir, 68260a9803SDavid Howells .rmdir = afs_rmdir, 692773bf00SMiklos Szeredi .rename = afs_rename, 7000d3b7a4SDavid Howells .permission = afs_permission, 71416351f2SDavid Howells .getattr = afs_getattr, 7231143d5dSDavid Howells .setattr = afs_setattr, 731da177e4SLinus Torvalds }; 741da177e4SLinus Torvalds 75f3ddee8dSDavid Howells const struct address_space_operations afs_dir_aops = { 76f3ddee8dSDavid Howells .set_page_dirty = afs_dir_set_page_dirty, 77f3ddee8dSDavid Howells .releasepage = afs_dir_releasepage, 78f3ddee8dSDavid Howells .invalidatepage = afs_dir_invalidatepage, 79f3ddee8dSDavid Howells }; 80f3ddee8dSDavid Howells 81d61dcce2SAl Viro const struct dentry_operations afs_fs_dentry_operations = { 821da177e4SLinus Torvalds .d_revalidate = afs_d_revalidate, 831da177e4SLinus Torvalds .d_delete = afs_d_delete, 84260a9803SDavid Howells .d_release = afs_d_release, 85d18610b0SDavid Howells .d_automount = afs_d_automount, 8679ddbfa5SDavid Howells .d_iput = afs_d_iput, 871da177e4SLinus Torvalds }; 881da177e4SLinus Torvalds 895cf9dd55SDavid Howells struct afs_lookup_one_cookie { 905cf9dd55SDavid Howells struct dir_context ctx; 915cf9dd55SDavid Howells struct qstr name; 925cf9dd55SDavid Howells bool found; 935cf9dd55SDavid Howells struct afs_fid fid; 945cf9dd55SDavid Howells }; 955cf9dd55SDavid Howells 96260a9803SDavid Howells struct afs_lookup_cookie { 971bbae9f8SAl Viro struct dir_context ctx; 981bbae9f8SAl Viro struct qstr name; 995cf9dd55SDavid Howells bool found; 1005cf9dd55SDavid Howells bool one_only; 1015cf9dd55SDavid Howells unsigned short nr_fids; 1025cf9dd55SDavid Howells struct afs_fid fids[50]; 1031da177e4SLinus Torvalds }; 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds /* 1061da177e4SLinus Torvalds * check that a directory page is valid 1071da177e4SLinus Torvalds */ 108f3ddee8dSDavid Howells static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page, 109f3ddee8dSDavid Howells loff_t i_size) 1101da177e4SLinus Torvalds { 11100317636SDavid Howells struct afs_xdr_dir_page *dbuf; 112f3ddee8dSDavid Howells loff_t latter, off; 1131da177e4SLinus Torvalds int tmp, qty; 1141da177e4SLinus Torvalds 115dab17c1aSDavid Howells /* Determine how many magic numbers there should be in this page, but 116dab17c1aSDavid Howells * we must take care because the directory may change size under us. 117dab17c1aSDavid Howells */ 118dab17c1aSDavid Howells off = page_offset(page); 119dab17c1aSDavid Howells if (i_size <= off) 120dab17c1aSDavid Howells goto checked; 121dab17c1aSDavid Howells 122dab17c1aSDavid Howells latter = i_size - off; 1231da177e4SLinus Torvalds if (latter >= PAGE_SIZE) 1241da177e4SLinus Torvalds qty = PAGE_SIZE; 1251da177e4SLinus Torvalds else 1261da177e4SLinus Torvalds qty = latter; 12700317636SDavid Howells qty /= sizeof(union afs_xdr_dir_block); 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds /* check them */ 13063a4681fSDavid Howells dbuf = kmap(page); 1311da177e4SLinus Torvalds for (tmp = 0; tmp < qty; tmp++) { 13200317636SDavid Howells if (dbuf->blocks[tmp].hdr.magic != AFS_DIR_MAGIC) { 133dab17c1aSDavid Howells printk("kAFS: %s(%lx): bad magic %d/%d is %04hx\n", 134f3ddee8dSDavid Howells __func__, dvnode->vfs_inode.i_ino, tmp, qty, 13500317636SDavid Howells ntohs(dbuf->blocks[tmp].hdr.magic)); 136f3ddee8dSDavid Howells trace_afs_dir_check_failed(dvnode, off, i_size); 13763a4681fSDavid Howells kunmap(page); 138f51375cdSDavid Howells trace_afs_file_error(dvnode, -EIO, afs_file_error_dir_bad_magic); 1391da177e4SLinus Torvalds goto error; 1401da177e4SLinus Torvalds } 14163a4681fSDavid Howells 14263a4681fSDavid Howells /* Make sure each block is NUL terminated so we can reasonably 14363a4681fSDavid Howells * use string functions on it. The filenames in the page 14463a4681fSDavid Howells * *should* be NUL-terminated anyway. 14563a4681fSDavid Howells */ 14663a4681fSDavid Howells ((u8 *)&dbuf->blocks[tmp])[AFS_DIR_BLOCK_SIZE - 1] = 0; 1471da177e4SLinus Torvalds } 1481da177e4SLinus Torvalds 14963a4681fSDavid Howells kunmap(page); 15063a4681fSDavid Howells 151dab17c1aSDavid Howells checked: 152f3ddee8dSDavid Howells afs_stat_v(dvnode, n_read_dir); 153be5b82dbSAl Viro return true; 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds error: 156be5b82dbSAl Viro return false; 157ec26815aSDavid Howells } 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds /* 160445b1028SDavid Howells * Check the contents of a directory that we've just read. 161445b1028SDavid Howells */ 162445b1028SDavid Howells static bool afs_dir_check_pages(struct afs_vnode *dvnode, struct afs_read *req) 163445b1028SDavid Howells { 164445b1028SDavid Howells struct afs_xdr_dir_page *dbuf; 165445b1028SDavid Howells unsigned int i, j, qty = PAGE_SIZE / sizeof(union afs_xdr_dir_block); 166445b1028SDavid Howells 167445b1028SDavid Howells for (i = 0; i < req->nr_pages; i++) 168445b1028SDavid Howells if (!afs_dir_check_page(dvnode, req->pages[i], req->actual_len)) 169445b1028SDavid Howells goto bad; 170445b1028SDavid Howells return true; 171445b1028SDavid Howells 172445b1028SDavid Howells bad: 173445b1028SDavid Howells pr_warn("DIR %llx:%llx f=%llx l=%llx al=%llx r=%llx\n", 174445b1028SDavid Howells dvnode->fid.vid, dvnode->fid.vnode, 175445b1028SDavid Howells req->file_size, req->len, req->actual_len, req->remain); 176445b1028SDavid Howells pr_warn("DIR %llx %x %x %x\n", 177445b1028SDavid Howells req->pos, req->index, req->nr_pages, req->offset); 178445b1028SDavid Howells 179445b1028SDavid Howells for (i = 0; i < req->nr_pages; i++) { 180445b1028SDavid Howells dbuf = kmap(req->pages[i]); 181445b1028SDavid Howells for (j = 0; j < qty; j++) { 182445b1028SDavid Howells union afs_xdr_dir_block *block = &dbuf->blocks[j]; 183445b1028SDavid Howells 184445b1028SDavid Howells pr_warn("[%02x] %32phN\n", i * qty + j, block); 185445b1028SDavid Howells } 186445b1028SDavid Howells kunmap(req->pages[i]); 187445b1028SDavid Howells } 188445b1028SDavid Howells return false; 189445b1028SDavid Howells } 190445b1028SDavid Howells 191445b1028SDavid Howells /* 1921da177e4SLinus Torvalds * open an AFS directory file 1931da177e4SLinus Torvalds */ 1941da177e4SLinus Torvalds static int afs_dir_open(struct inode *inode, struct file *file) 1951da177e4SLinus Torvalds { 1961da177e4SLinus Torvalds _enter("{%lu}", inode->i_ino); 1971da177e4SLinus Torvalds 19800317636SDavid Howells BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); 19900317636SDavid Howells BUILD_BUG_ON(sizeof(union afs_xdr_dirent) != 32); 2001da177e4SLinus Torvalds 20108e0e7c8SDavid Howells if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags)) 2021da177e4SLinus Torvalds return -ENOENT; 2031da177e4SLinus Torvalds 20400d3b7a4SDavid Howells return afs_open(inode, file); 205ec26815aSDavid Howells } 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds /* 208f3ddee8dSDavid Howells * Read the directory into the pagecache in one go, scrubbing the previous 209f3ddee8dSDavid Howells * contents. The list of pages is returned, pinning them so that they don't 210f3ddee8dSDavid Howells * get reclaimed during the iteration. 211f3ddee8dSDavid Howells */ 212f3ddee8dSDavid Howells static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) 213b61f7dcfSDavid Howells __acquires(&dvnode->validate_lock) 214f3ddee8dSDavid Howells { 215f3ddee8dSDavid Howells struct afs_read *req; 216f3ddee8dSDavid Howells loff_t i_size; 217f3ddee8dSDavid Howells int nr_pages, nr_inline, i, n; 218f3ddee8dSDavid Howells int ret = -ENOMEM; 219f3ddee8dSDavid Howells 220f3ddee8dSDavid Howells retry: 221f3ddee8dSDavid Howells i_size = i_size_read(&dvnode->vfs_inode); 222f3ddee8dSDavid Howells if (i_size < 2048) 223f51375cdSDavid Howells return ERR_PTR(afs_bad(dvnode, afs_file_error_dir_small)); 224f51375cdSDavid Howells if (i_size > 2048 * 1024) { 225f51375cdSDavid Howells trace_afs_file_error(dvnode, -EFBIG, afs_file_error_dir_big); 226f3ddee8dSDavid Howells return ERR_PTR(-EFBIG); 227f51375cdSDavid Howells } 228f3ddee8dSDavid Howells 229f3ddee8dSDavid Howells _enter("%llu", i_size); 230f3ddee8dSDavid Howells 231f3ddee8dSDavid Howells /* Get a request record to hold the page list. We want to hold it 232f3ddee8dSDavid Howells * inline if we can, but we don't want to make an order 1 allocation. 233f3ddee8dSDavid Howells */ 234f3ddee8dSDavid Howells nr_pages = (i_size + PAGE_SIZE - 1) / PAGE_SIZE; 235f3ddee8dSDavid Howells nr_inline = nr_pages; 236f3ddee8dSDavid Howells if (nr_inline > (PAGE_SIZE - sizeof(*req)) / sizeof(struct page *)) 237f3ddee8dSDavid Howells nr_inline = 0; 238f3ddee8dSDavid Howells 239ee102584SZhengyuan Liu req = kzalloc(struct_size(req, array, nr_inline), GFP_KERNEL); 240f3ddee8dSDavid Howells if (!req) 241f3ddee8dSDavid Howells return ERR_PTR(-ENOMEM); 242f3ddee8dSDavid Howells 243f3ddee8dSDavid Howells refcount_set(&req->usage, 1); 244*c69bf479SDavid Howells req->key = key_get(key); 245f3ddee8dSDavid Howells req->nr_pages = nr_pages; 246f3ddee8dSDavid Howells req->actual_len = i_size; /* May change */ 247f3ddee8dSDavid Howells req->len = nr_pages * PAGE_SIZE; /* We can ask for more than there is */ 248f3ddee8dSDavid Howells req->data_version = dvnode->status.data_version; /* May change */ 249f3ddee8dSDavid Howells if (nr_inline > 0) { 250f3ddee8dSDavid Howells req->pages = req->array; 251f3ddee8dSDavid Howells } else { 252f3ddee8dSDavid Howells req->pages = kcalloc(nr_pages, sizeof(struct page *), 253f3ddee8dSDavid Howells GFP_KERNEL); 254f3ddee8dSDavid Howells if (!req->pages) 255f3ddee8dSDavid Howells goto error; 256f3ddee8dSDavid Howells } 257f3ddee8dSDavid Howells 258f3ddee8dSDavid Howells /* Get a list of all the pages that hold or will hold the directory 259f3ddee8dSDavid Howells * content. We need to fill in any gaps that we might find where the 260f3ddee8dSDavid Howells * memory reclaimer has been at work. If there are any gaps, we will 261f3ddee8dSDavid Howells * need to reread the entire directory contents. 262f3ddee8dSDavid Howells */ 263f3ddee8dSDavid Howells i = 0; 264f3ddee8dSDavid Howells do { 265f3ddee8dSDavid Howells n = find_get_pages_contig(dvnode->vfs_inode.i_mapping, i, 266f3ddee8dSDavid Howells req->nr_pages - i, 267f3ddee8dSDavid Howells req->pages + i); 268f3ddee8dSDavid Howells _debug("find %u at %u/%u", n, i, req->nr_pages); 269f3ddee8dSDavid Howells if (n == 0) { 270f3ddee8dSDavid Howells gfp_t gfp = dvnode->vfs_inode.i_mapping->gfp_mask; 271f3ddee8dSDavid Howells 272f3ddee8dSDavid Howells if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) 273f3ddee8dSDavid Howells afs_stat_v(dvnode, n_inval); 274f3ddee8dSDavid Howells 275f3ddee8dSDavid Howells ret = -ENOMEM; 276f3ddee8dSDavid Howells req->pages[i] = __page_cache_alloc(gfp); 277f3ddee8dSDavid Howells if (!req->pages[i]) 278f3ddee8dSDavid Howells goto error; 279f3ddee8dSDavid Howells ret = add_to_page_cache_lru(req->pages[i], 280f3ddee8dSDavid Howells dvnode->vfs_inode.i_mapping, 281f3ddee8dSDavid Howells i, gfp); 282f3ddee8dSDavid Howells if (ret < 0) 283f3ddee8dSDavid Howells goto error; 284f3ddee8dSDavid Howells 285fa04a40bSDavid Howells attach_page_private(req->pages[i], (void *)1); 286f3ddee8dSDavid Howells unlock_page(req->pages[i]); 287f3ddee8dSDavid Howells i++; 288f3ddee8dSDavid Howells } else { 289f3ddee8dSDavid Howells i += n; 290f3ddee8dSDavid Howells } 291f3ddee8dSDavid Howells } while (i < req->nr_pages); 292f3ddee8dSDavid Howells 293f3ddee8dSDavid Howells /* If we're going to reload, we need to lock all the pages to prevent 294f3ddee8dSDavid Howells * races. 295f3ddee8dSDavid Howells */ 296f3ddee8dSDavid Howells ret = -ERESTARTSYS; 297b61f7dcfSDavid Howells if (down_read_killable(&dvnode->validate_lock) < 0) 298b61f7dcfSDavid Howells goto error; 299f3ddee8dSDavid Howells 300f3ddee8dSDavid Howells if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) 301f3ddee8dSDavid Howells goto success; 302f3ddee8dSDavid Howells 303b61f7dcfSDavid Howells up_read(&dvnode->validate_lock); 304b61f7dcfSDavid Howells if (down_write_killable(&dvnode->validate_lock) < 0) 305b61f7dcfSDavid Howells goto error; 306b61f7dcfSDavid Howells 307b61f7dcfSDavid Howells if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { 30899987c56SDavid Howells trace_afs_reload_dir(dvnode); 309*c69bf479SDavid Howells ret = afs_fetch_data(dvnode, req); 310f3ddee8dSDavid Howells if (ret < 0) 311b61f7dcfSDavid Howells goto error_unlock; 312f3ddee8dSDavid Howells 313f3ddee8dSDavid Howells task_io_account_read(PAGE_SIZE * req->nr_pages); 314f3ddee8dSDavid Howells 315f3ddee8dSDavid Howells if (req->len < req->file_size) 316f3ddee8dSDavid Howells goto content_has_grown; 317f3ddee8dSDavid Howells 318f3ddee8dSDavid Howells /* Validate the data we just read. */ 319f3ddee8dSDavid Howells ret = -EIO; 320445b1028SDavid Howells if (!afs_dir_check_pages(dvnode, req)) 321b61f7dcfSDavid Howells goto error_unlock; 322f3ddee8dSDavid Howells 323f3ddee8dSDavid Howells // TODO: Trim excess pages 324f3ddee8dSDavid Howells 325f3ddee8dSDavid Howells set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags); 326f3ddee8dSDavid Howells } 327f3ddee8dSDavid Howells 328b61f7dcfSDavid Howells downgrade_write(&dvnode->validate_lock); 329f3ddee8dSDavid Howells success: 330f3ddee8dSDavid Howells return req; 331f3ddee8dSDavid Howells 332f3ddee8dSDavid Howells error_unlock: 333b61f7dcfSDavid Howells up_write(&dvnode->validate_lock); 334f3ddee8dSDavid Howells error: 335f3ddee8dSDavid Howells afs_put_read(req); 336f3ddee8dSDavid Howells _leave(" = %d", ret); 337f3ddee8dSDavid Howells return ERR_PTR(ret); 338f3ddee8dSDavid Howells 339f3ddee8dSDavid Howells content_has_grown: 340b61f7dcfSDavid Howells up_write(&dvnode->validate_lock); 341f3ddee8dSDavid Howells afs_put_read(req); 342f3ddee8dSDavid Howells goto retry; 343f3ddee8dSDavid Howells } 344f3ddee8dSDavid Howells 345f3ddee8dSDavid Howells /* 3461da177e4SLinus Torvalds * deal with one block in an AFS directory 3471da177e4SLinus Torvalds */ 348f51375cdSDavid Howells static int afs_dir_iterate_block(struct afs_vnode *dvnode, 349f51375cdSDavid Howells struct dir_context *ctx, 35000317636SDavid Howells union afs_xdr_dir_block *block, 3511bbae9f8SAl Viro unsigned blkoff) 3521da177e4SLinus Torvalds { 35300317636SDavid Howells union afs_xdr_dirent *dire; 354366911cdSDavid Howells unsigned offset, next, curr, nr_slots; 3551da177e4SLinus Torvalds size_t nlen; 3561bbae9f8SAl Viro int tmp; 3571da177e4SLinus Torvalds 3581bbae9f8SAl Viro _enter("%u,%x,%p,,",(unsigned)ctx->pos,blkoff,block); 3591da177e4SLinus Torvalds 36000317636SDavid Howells curr = (ctx->pos - blkoff) / sizeof(union afs_xdr_dirent); 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds /* walk through the block, an entry at a time */ 3634ea219a8SDavid Howells for (offset = (blkoff == 0 ? AFS_DIR_RESV_BLOCKS0 : AFS_DIR_RESV_BLOCKS); 3644ea219a8SDavid Howells offset < AFS_DIR_SLOTS_PER_BLOCK; 3651da177e4SLinus Torvalds offset = next 3661da177e4SLinus Torvalds ) { 3671da177e4SLinus Torvalds /* skip entries marked unused in the bitmap */ 36800317636SDavid Howells if (!(block->hdr.bitmap[offset / 8] & 3691da177e4SLinus Torvalds (1 << (offset % 8)))) { 3705b5e0928SAlexey Dobriyan _debug("ENT[%zu.%u]: unused", 37100317636SDavid Howells blkoff / sizeof(union afs_xdr_dir_block), offset); 372366911cdSDavid Howells next = offset + 1; 3731da177e4SLinus Torvalds if (offset >= curr) 3741bbae9f8SAl Viro ctx->pos = blkoff + 37500317636SDavid Howells next * sizeof(union afs_xdr_dirent); 3761da177e4SLinus Torvalds continue; 3771da177e4SLinus Torvalds } 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds /* got a valid entry */ 3801da177e4SLinus Torvalds dire = &block->dirents[offset]; 3811da177e4SLinus Torvalds nlen = strnlen(dire->u.name, 3821da177e4SLinus Torvalds sizeof(*block) - 38300317636SDavid Howells offset * sizeof(union afs_xdr_dirent)); 384366911cdSDavid Howells if (nlen > AFSNAMEMAX - 1) { 385366911cdSDavid Howells _debug("ENT[%zu]: name too long (len %u/%zu)", 386366911cdSDavid Howells blkoff / sizeof(union afs_xdr_dir_block), 387366911cdSDavid Howells offset, nlen); 388366911cdSDavid Howells return afs_bad(dvnode, afs_file_error_dir_name_too_long); 389366911cdSDavid Howells } 3901da177e4SLinus Torvalds 3915b5e0928SAlexey Dobriyan _debug("ENT[%zu.%u]: %s %zu \"%s\"", 39200317636SDavid Howells blkoff / sizeof(union afs_xdr_dir_block), offset, 3931da177e4SLinus Torvalds (offset < curr ? "skip" : "fill"), 3941da177e4SLinus Torvalds nlen, dire->u.name); 3951da177e4SLinus Torvalds 396366911cdSDavid Howells nr_slots = afs_dir_calc_slots(nlen); 397366911cdSDavid Howells next = offset + nr_slots; 398366911cdSDavid Howells if (next > AFS_DIR_SLOTS_PER_BLOCK) { 3995b5e0928SAlexey Dobriyan _debug("ENT[%zu.%u]:" 400366911cdSDavid Howells " %u extends beyond end dir block" 401366911cdSDavid Howells " (len %zu)", 40200317636SDavid Howells blkoff / sizeof(union afs_xdr_dir_block), 403366911cdSDavid Howells offset, next, nlen); 404f51375cdSDavid Howells return afs_bad(dvnode, afs_file_error_dir_over_end); 4051da177e4SLinus Torvalds } 406366911cdSDavid Howells 407366911cdSDavid Howells /* Check that the name-extension dirents are all allocated */ 408366911cdSDavid Howells for (tmp = 1; tmp < nr_slots; tmp++) { 409366911cdSDavid Howells unsigned int ix = offset + tmp; 410366911cdSDavid Howells if (!(block->hdr.bitmap[ix / 8] & (1 << (ix % 8)))) { 411366911cdSDavid Howells _debug("ENT[%zu.u]:" 412366911cdSDavid Howells " %u unmarked extension (%u/%u)", 41300317636SDavid Howells blkoff / sizeof(union afs_xdr_dir_block), 414366911cdSDavid Howells offset, tmp, nr_slots); 415f51375cdSDavid Howells return afs_bad(dvnode, afs_file_error_dir_unmarked_ext); 4161da177e4SLinus Torvalds } 4171da177e4SLinus Torvalds } 4181da177e4SLinus Torvalds 4191da177e4SLinus Torvalds /* skip if starts before the current position */ 4201da177e4SLinus Torvalds if (offset < curr) 4211da177e4SLinus Torvalds continue; 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds /* found the next entry */ 4241bbae9f8SAl Viro if (!dir_emit(ctx, dire->u.name, nlen, 4251da177e4SLinus Torvalds ntohl(dire->u.vnode), 4265cf9dd55SDavid Howells (ctx->actor == afs_lookup_filldir || 4275cf9dd55SDavid Howells ctx->actor == afs_lookup_one_filldir)? 4281bbae9f8SAl Viro ntohl(dire->u.unique) : DT_UNKNOWN)) { 4291da177e4SLinus Torvalds _leave(" = 0 [full]"); 4301da177e4SLinus Torvalds return 0; 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds 43300317636SDavid Howells ctx->pos = blkoff + next * sizeof(union afs_xdr_dirent); 4341da177e4SLinus Torvalds } 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds _leave(" = 1 [more]"); 4371da177e4SLinus Torvalds return 1; 438ec26815aSDavid Howells } 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds /* 44108e0e7c8SDavid Howells * iterate through the data blob that lists the contents of an AFS directory 4421da177e4SLinus Torvalds */ 4431bbae9f8SAl Viro static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, 4449dd0b82eSDavid Howells struct key *key, afs_dataversion_t *_dir_version) 4451da177e4SLinus Torvalds { 446f3ddee8dSDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir); 44700317636SDavid Howells struct afs_xdr_dir_page *dbuf; 44800317636SDavid Howells union afs_xdr_dir_block *dblock; 449f3ddee8dSDavid Howells struct afs_read *req; 4501da177e4SLinus Torvalds struct page *page; 4511da177e4SLinus Torvalds unsigned blkoff, limit; 4521da177e4SLinus Torvalds int ret; 4531da177e4SLinus Torvalds 4541bbae9f8SAl Viro _enter("{%lu},%u,,", dir->i_ino, (unsigned)ctx->pos); 4551da177e4SLinus Torvalds 45608e0e7c8SDavid Howells if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) { 4571da177e4SLinus Torvalds _leave(" = -ESTALE"); 4581da177e4SLinus Torvalds return -ESTALE; 4591da177e4SLinus Torvalds } 4601da177e4SLinus Torvalds 461f3ddee8dSDavid Howells req = afs_read_dir(dvnode, key); 462f3ddee8dSDavid Howells if (IS_ERR(req)) 463f3ddee8dSDavid Howells return PTR_ERR(req); 4649dd0b82eSDavid Howells *_dir_version = req->data_version; 465f3ddee8dSDavid Howells 4661da177e4SLinus Torvalds /* round the file position up to the next entry boundary */ 46700317636SDavid Howells ctx->pos += sizeof(union afs_xdr_dirent) - 1; 46800317636SDavid Howells ctx->pos &= ~(sizeof(union afs_xdr_dirent) - 1); 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds /* walk through the blocks in sequence */ 4711da177e4SLinus Torvalds ret = 0; 472f3ddee8dSDavid Howells while (ctx->pos < req->actual_len) { 47300317636SDavid Howells blkoff = ctx->pos & ~(sizeof(union afs_xdr_dir_block) - 1); 4741da177e4SLinus Torvalds 475f3ddee8dSDavid Howells /* Fetch the appropriate page from the directory and re-add it 476f3ddee8dSDavid Howells * to the LRU. 477f3ddee8dSDavid Howells */ 478f3ddee8dSDavid Howells page = req->pages[blkoff / PAGE_SIZE]; 479f3ddee8dSDavid Howells if (!page) { 480f51375cdSDavid Howells ret = afs_bad(dvnode, afs_file_error_dir_missing_page); 4811da177e4SLinus Torvalds break; 4821da177e4SLinus Torvalds } 483f3ddee8dSDavid Howells mark_page_accessed(page); 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds limit = blkoff & ~(PAGE_SIZE - 1); 4861da177e4SLinus Torvalds 487f3ddee8dSDavid Howells dbuf = kmap(page); 4881da177e4SLinus Torvalds 4891da177e4SLinus Torvalds /* deal with the individual blocks stashed on this page */ 4901da177e4SLinus Torvalds do { 4911da177e4SLinus Torvalds dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) / 49200317636SDavid Howells sizeof(union afs_xdr_dir_block)]; 493f51375cdSDavid Howells ret = afs_dir_iterate_block(dvnode, ctx, dblock, blkoff); 4941da177e4SLinus Torvalds if (ret != 1) { 495f3ddee8dSDavid Howells kunmap(page); 4961da177e4SLinus Torvalds goto out; 4971da177e4SLinus Torvalds } 4981da177e4SLinus Torvalds 49900317636SDavid Howells blkoff += sizeof(union afs_xdr_dir_block); 5001da177e4SLinus Torvalds 5011bbae9f8SAl Viro } while (ctx->pos < dir->i_size && blkoff < limit); 5021da177e4SLinus Torvalds 503f3ddee8dSDavid Howells kunmap(page); 5041da177e4SLinus Torvalds ret = 0; 5051da177e4SLinus Torvalds } 5061da177e4SLinus Torvalds 5071da177e4SLinus Torvalds out: 508b61f7dcfSDavid Howells up_read(&dvnode->validate_lock); 509f3ddee8dSDavid Howells afs_put_read(req); 5101da177e4SLinus Torvalds _leave(" = %d", ret); 5111da177e4SLinus Torvalds return ret; 512ec26815aSDavid Howells } 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds /* 5151da177e4SLinus Torvalds * read an AFS directory 5161da177e4SLinus Torvalds */ 5171bbae9f8SAl Viro static int afs_readdir(struct file *file, struct dir_context *ctx) 5181da177e4SLinus Torvalds { 5199dd0b82eSDavid Howells afs_dataversion_t dir_version; 5209dd0b82eSDavid Howells 5219dd0b82eSDavid Howells return afs_dir_iterate(file_inode(file), ctx, afs_file_key(file), 5229dd0b82eSDavid Howells &dir_version); 523ec26815aSDavid Howells } 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds /* 5265cf9dd55SDavid Howells * Search the directory for a single name 5271da177e4SLinus Torvalds * - if afs_dir_iterate_block() spots this function, it'll pass the FID 5281da177e4SLinus Torvalds * uniquifier through dtype 5291da177e4SLinus Torvalds */ 5305cf9dd55SDavid Howells static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name, 531ac7576f4SMiklos Szeredi int nlen, loff_t fpos, u64 ino, unsigned dtype) 5321da177e4SLinus Torvalds { 5335cf9dd55SDavid Howells struct afs_lookup_one_cookie *cookie = 5345cf9dd55SDavid Howells container_of(ctx, struct afs_lookup_one_cookie, ctx); 5351da177e4SLinus Torvalds 5361bbae9f8SAl Viro _enter("{%s,%u},%s,%u,,%llu,%u", 5371bbae9f8SAl Viro cookie->name.name, cookie->name.len, name, nlen, 538ba3e0e1aSDavid S. Miller (unsigned long long) ino, dtype); 5391da177e4SLinus Torvalds 54008e0e7c8SDavid Howells /* insanity checks first */ 54100317636SDavid Howells BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); 54200317636SDavid Howells BUILD_BUG_ON(sizeof(union afs_xdr_dirent) != 32); 54308e0e7c8SDavid Howells 5441bbae9f8SAl Viro if (cookie->name.len != nlen || 5451bbae9f8SAl Viro memcmp(cookie->name.name, name, nlen) != 0) { 5461da177e4SLinus Torvalds _leave(" = 0 [no]"); 5471da177e4SLinus Torvalds return 0; 5481da177e4SLinus Torvalds } 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds cookie->fid.vnode = ino; 5511da177e4SLinus Torvalds cookie->fid.unique = dtype; 5521da177e4SLinus Torvalds cookie->found = 1; 5531da177e4SLinus Torvalds 5541da177e4SLinus Torvalds _leave(" = -1 [found]"); 5551da177e4SLinus Torvalds return -1; 556ec26815aSDavid Howells } 5571da177e4SLinus Torvalds 5581da177e4SLinus Torvalds /* 5595cf9dd55SDavid Howells * Do a lookup of a single name in a directory 560260a9803SDavid Howells * - just returns the FID the dentry name maps to if found 5611da177e4SLinus Torvalds */ 5625cf9dd55SDavid Howells static int afs_do_lookup_one(struct inode *dir, struct dentry *dentry, 5639dd0b82eSDavid Howells struct afs_fid *fid, struct key *key, 5649dd0b82eSDavid Howells afs_dataversion_t *_dir_version) 5651da177e4SLinus Torvalds { 5661bbae9f8SAl Viro struct afs_super_info *as = dir->i_sb->s_fs_info; 5675cf9dd55SDavid Howells struct afs_lookup_one_cookie cookie = { 5685cf9dd55SDavid Howells .ctx.actor = afs_lookup_one_filldir, 5691bbae9f8SAl Viro .name = dentry->d_name, 5701bbae9f8SAl Viro .fid.vid = as->volume->vid 5711bbae9f8SAl Viro }; 5721da177e4SLinus Torvalds int ret; 5731da177e4SLinus Torvalds 574a455589fSAl Viro _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry); 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds /* search the directory */ 5779dd0b82eSDavid Howells ret = afs_dir_iterate(dir, &cookie.ctx, key, _dir_version); 5781da177e4SLinus Torvalds if (ret < 0) { 57908e0e7c8SDavid Howells _leave(" = %d [iter]", ret); 58008e0e7c8SDavid Howells return ret; 5811da177e4SLinus Torvalds } 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds ret = -ENOENT; 5841da177e4SLinus Torvalds if (!cookie.found) { 58508e0e7c8SDavid Howells _leave(" = -ENOENT [not found]"); 58608e0e7c8SDavid Howells return -ENOENT; 58708e0e7c8SDavid Howells } 58808e0e7c8SDavid Howells 58908e0e7c8SDavid Howells *fid = cookie.fid; 5903b6492dfSDavid Howells _leave(" = 0 { vn=%llu u=%u }", fid->vnode, fid->unique); 59108e0e7c8SDavid Howells return 0; 59208e0e7c8SDavid Howells } 59308e0e7c8SDavid Howells 59408e0e7c8SDavid Howells /* 5955cf9dd55SDavid Howells * search the directory for a name 5965cf9dd55SDavid Howells * - if afs_dir_iterate_block() spots this function, it'll pass the FID 5975cf9dd55SDavid Howells * uniquifier through dtype 5985cf9dd55SDavid Howells */ 5995cf9dd55SDavid Howells static int afs_lookup_filldir(struct dir_context *ctx, const char *name, 6005cf9dd55SDavid Howells int nlen, loff_t fpos, u64 ino, unsigned dtype) 6015cf9dd55SDavid Howells { 6025cf9dd55SDavid Howells struct afs_lookup_cookie *cookie = 6035cf9dd55SDavid Howells container_of(ctx, struct afs_lookup_cookie, ctx); 6045cf9dd55SDavid Howells int ret; 6055cf9dd55SDavid Howells 6065cf9dd55SDavid Howells _enter("{%s,%u},%s,%u,,%llu,%u", 6075cf9dd55SDavid Howells cookie->name.name, cookie->name.len, name, nlen, 6085cf9dd55SDavid Howells (unsigned long long) ino, dtype); 6095cf9dd55SDavid Howells 6105cf9dd55SDavid Howells /* insanity checks first */ 61100317636SDavid Howells BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); 61200317636SDavid Howells BUILD_BUG_ON(sizeof(union afs_xdr_dirent) != 32); 6135cf9dd55SDavid Howells 6145cf9dd55SDavid Howells if (cookie->found) { 6155cf9dd55SDavid Howells if (cookie->nr_fids < 50) { 6165cf9dd55SDavid Howells cookie->fids[cookie->nr_fids].vnode = ino; 6175cf9dd55SDavid Howells cookie->fids[cookie->nr_fids].unique = dtype; 6185cf9dd55SDavid Howells cookie->nr_fids++; 6195cf9dd55SDavid Howells } 6205cf9dd55SDavid Howells } else if (cookie->name.len == nlen && 6215cf9dd55SDavid Howells memcmp(cookie->name.name, name, nlen) == 0) { 622e49c7b2fSDavid Howells cookie->fids[1].vnode = ino; 623e49c7b2fSDavid Howells cookie->fids[1].unique = dtype; 6245cf9dd55SDavid Howells cookie->found = 1; 6255cf9dd55SDavid Howells if (cookie->one_only) 6265cf9dd55SDavid Howells return -1; 6275cf9dd55SDavid Howells } 6285cf9dd55SDavid Howells 6295cf9dd55SDavid Howells ret = cookie->nr_fids >= 50 ? -1 : 0; 6305cf9dd55SDavid Howells _leave(" = %d", ret); 6315cf9dd55SDavid Howells return ret; 6325cf9dd55SDavid Howells } 6335cf9dd55SDavid Howells 6345cf9dd55SDavid Howells /* 635e49c7b2fSDavid Howells * Deal with the result of a successful lookup operation. Turn all the files 636e49c7b2fSDavid Howells * into inodes and save the first one - which is the one we actually want. 637e49c7b2fSDavid Howells */ 638e49c7b2fSDavid Howells static void afs_do_lookup_success(struct afs_operation *op) 639e49c7b2fSDavid Howells { 640e49c7b2fSDavid Howells struct afs_vnode_param *vp; 641e49c7b2fSDavid Howells struct afs_vnode *vnode; 642e49c7b2fSDavid Howells struct inode *inode; 643e49c7b2fSDavid Howells u32 abort_code; 644e49c7b2fSDavid Howells int i; 645e49c7b2fSDavid Howells 646e49c7b2fSDavid Howells _enter(""); 647e49c7b2fSDavid Howells 648e49c7b2fSDavid Howells for (i = 0; i < op->nr_files; i++) { 649e49c7b2fSDavid Howells switch (i) { 650e49c7b2fSDavid Howells case 0: 651e49c7b2fSDavid Howells vp = &op->file[0]; 652e49c7b2fSDavid Howells abort_code = vp->scb.status.abort_code; 653e49c7b2fSDavid Howells if (abort_code != 0) { 65444767c35SDavid Howells op->ac.abort_code = abort_code; 655e49c7b2fSDavid Howells op->error = afs_abort_to_error(abort_code); 656e49c7b2fSDavid Howells } 657e49c7b2fSDavid Howells break; 658e49c7b2fSDavid Howells 659e49c7b2fSDavid Howells case 1: 660e49c7b2fSDavid Howells vp = &op->file[1]; 661e49c7b2fSDavid Howells break; 662e49c7b2fSDavid Howells 663e49c7b2fSDavid Howells default: 664e49c7b2fSDavid Howells vp = &op->more_files[i - 2]; 665e49c7b2fSDavid Howells break; 666e49c7b2fSDavid Howells } 667e49c7b2fSDavid Howells 668e49c7b2fSDavid Howells if (!vp->scb.have_status && !vp->scb.have_error) 669e49c7b2fSDavid Howells continue; 670e49c7b2fSDavid Howells 671e49c7b2fSDavid Howells _debug("do [%u]", i); 672e49c7b2fSDavid Howells if (vp->vnode) { 673e49c7b2fSDavid Howells if (!test_bit(AFS_VNODE_UNSET, &vp->vnode->flags)) 674e49c7b2fSDavid Howells afs_vnode_commit_status(op, vp); 675e49c7b2fSDavid Howells } else if (vp->scb.status.abort_code == 0) { 676e49c7b2fSDavid Howells inode = afs_iget(op, vp); 677e49c7b2fSDavid Howells if (!IS_ERR(inode)) { 678e49c7b2fSDavid Howells vnode = AFS_FS_I(inode); 679e49c7b2fSDavid Howells afs_cache_permit(vnode, op->key, 680e49c7b2fSDavid Howells 0 /* Assume vnode->cb_break is 0 */ + 681e49c7b2fSDavid Howells op->cb_v_break, 682e49c7b2fSDavid Howells &vp->scb); 683e49c7b2fSDavid Howells vp->vnode = vnode; 684e49c7b2fSDavid Howells vp->put_vnode = true; 685e49c7b2fSDavid Howells } 686e49c7b2fSDavid Howells } else { 687e49c7b2fSDavid Howells _debug("- abort %d %llx:%llx.%x", 688e49c7b2fSDavid Howells vp->scb.status.abort_code, 689e49c7b2fSDavid Howells vp->fid.vid, vp->fid.vnode, vp->fid.unique); 690e49c7b2fSDavid Howells } 691e49c7b2fSDavid Howells } 692e49c7b2fSDavid Howells 693e49c7b2fSDavid Howells _leave(""); 694e49c7b2fSDavid Howells } 695e49c7b2fSDavid Howells 696e49c7b2fSDavid Howells static const struct afs_operation_ops afs_inline_bulk_status_operation = { 697e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_inline_bulk_status, 698e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_inline_bulk_status, 699e49c7b2fSDavid Howells .success = afs_do_lookup_success, 700e49c7b2fSDavid Howells }; 701e49c7b2fSDavid Howells 702b6489a49SDavid Howells static const struct afs_operation_ops afs_lookup_fetch_status_operation = { 703e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_fetch_status, 704e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_fetch_status, 705e49c7b2fSDavid Howells .success = afs_do_lookup_success, 706728279a5SDavid Howells .aborted = afs_check_for_remote_deletion, 707e49c7b2fSDavid Howells }; 708e49c7b2fSDavid Howells 709e49c7b2fSDavid Howells /* 71020325960SDavid Howells * See if we know that the server we expect to use doesn't support 71120325960SDavid Howells * FS.InlineBulkStatus. 71220325960SDavid Howells */ 71320325960SDavid Howells static bool afs_server_supports_ibulk(struct afs_vnode *dvnode) 71420325960SDavid Howells { 71520325960SDavid Howells struct afs_server_list *slist; 71620325960SDavid Howells struct afs_volume *volume = dvnode->volume; 71720325960SDavid Howells struct afs_server *server; 71820325960SDavid Howells bool ret = true; 71920325960SDavid Howells int i; 72020325960SDavid Howells 72120325960SDavid Howells if (!test_bit(AFS_VOLUME_MAYBE_NO_IBULK, &volume->flags)) 72220325960SDavid Howells return true; 72320325960SDavid Howells 72420325960SDavid Howells rcu_read_lock(); 72520325960SDavid Howells slist = rcu_dereference(volume->servers); 72620325960SDavid Howells 72720325960SDavid Howells for (i = 0; i < slist->nr_servers; i++) { 72820325960SDavid Howells server = slist->servers[i].server; 72920325960SDavid Howells if (server == dvnode->cb_server) { 73020325960SDavid Howells if (test_bit(AFS_SERVER_FL_NO_IBULK, &server->flags)) 73120325960SDavid Howells ret = false; 73220325960SDavid Howells break; 73320325960SDavid Howells } 73420325960SDavid Howells } 73520325960SDavid Howells 73620325960SDavid Howells rcu_read_unlock(); 73720325960SDavid Howells return ret; 73820325960SDavid Howells } 73920325960SDavid Howells 74020325960SDavid Howells /* 7415cf9dd55SDavid Howells * Do a lookup in a directory. We make use of bulk lookup to query a slew of 7425cf9dd55SDavid Howells * files in one go and create inodes for them. The inode of the file we were 7435cf9dd55SDavid Howells * asked for is returned. 7445cf9dd55SDavid Howells */ 7455cf9dd55SDavid Howells static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, 7465cf9dd55SDavid Howells struct key *key) 7475cf9dd55SDavid Howells { 7485cf9dd55SDavid Howells struct afs_lookup_cookie *cookie; 749e49c7b2fSDavid Howells struct afs_vnode_param *vp; 750e49c7b2fSDavid Howells struct afs_operation *op; 75139db9815SDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode; 75239db9815SDavid Howells struct inode *inode = NULL, *ti; 7539dd0b82eSDavid Howells afs_dataversion_t data_version = READ_ONCE(dvnode->status.data_version); 754e49c7b2fSDavid Howells long ret; 755e49c7b2fSDavid Howells int i; 7565cf9dd55SDavid Howells 7575cf9dd55SDavid Howells _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry); 7585cf9dd55SDavid Howells 7595cf9dd55SDavid Howells cookie = kzalloc(sizeof(struct afs_lookup_cookie), GFP_KERNEL); 7605cf9dd55SDavid Howells if (!cookie) 7615cf9dd55SDavid Howells return ERR_PTR(-ENOMEM); 7625cf9dd55SDavid Howells 763e49c7b2fSDavid Howells for (i = 0; i < ARRAY_SIZE(cookie->fids); i++) 764e49c7b2fSDavid Howells cookie->fids[i].vid = dvnode->fid.vid; 7655cf9dd55SDavid Howells cookie->ctx.actor = afs_lookup_filldir; 7665cf9dd55SDavid Howells cookie->name = dentry->d_name; 76713fcc635SDavid Howells cookie->nr_fids = 2; /* slot 0 is saved for the fid we actually want 76813fcc635SDavid Howells * and slot 1 for the directory */ 7695cf9dd55SDavid Howells 77020325960SDavid Howells if (!afs_server_supports_ibulk(dvnode)) 7715cf9dd55SDavid Howells cookie->one_only = true; 7725cf9dd55SDavid Howells 7735cf9dd55SDavid Howells /* search the directory */ 7749dd0b82eSDavid Howells ret = afs_dir_iterate(dir, &cookie->ctx, key, &data_version); 775e49c7b2fSDavid Howells if (ret < 0) 7765cf9dd55SDavid Howells goto out; 7775cf9dd55SDavid Howells 7789dd0b82eSDavid Howells dentry->d_fsdata = (void *)(unsigned long)data_version; 7799dd0b82eSDavid Howells 780e49c7b2fSDavid Howells ret = -ENOENT; 7815cf9dd55SDavid Howells if (!cookie->found) 7825cf9dd55SDavid Howells goto out; 7835cf9dd55SDavid Howells 7845cf9dd55SDavid Howells /* Check to see if we already have an inode for the primary fid. */ 785e49c7b2fSDavid Howells inode = ilookup5(dir->i_sb, cookie->fids[1].vnode, 786e49c7b2fSDavid Howells afs_ilookup5_test_by_fid, &cookie->fids[1]); 7875cf9dd55SDavid Howells if (inode) 788e49c7b2fSDavid Howells goto out; /* We do */ 789e49c7b2fSDavid Howells 790e49c7b2fSDavid Howells /* Okay, we didn't find it. We need to query the server - and whilst 791e49c7b2fSDavid Howells * we're doing that, we're going to attempt to look up a bunch of other 792e49c7b2fSDavid Howells * vnodes also. 793e49c7b2fSDavid Howells */ 794e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, dvnode->volume); 795e49c7b2fSDavid Howells if (IS_ERR(op)) { 796e49c7b2fSDavid Howells ret = PTR_ERR(op); 7975cf9dd55SDavid Howells goto out; 798e49c7b2fSDavid Howells } 799e49c7b2fSDavid Howells 800e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, dvnode); 801e49c7b2fSDavid Howells afs_op_set_fid(op, 1, &cookie->fids[1]); 802e49c7b2fSDavid Howells 803e49c7b2fSDavid Howells op->nr_files = cookie->nr_fids; 804e49c7b2fSDavid Howells _debug("nr_files %u", op->nr_files); 8055cf9dd55SDavid Howells 8065cf9dd55SDavid Howells /* Need space for examining all the selected files */ 807e49c7b2fSDavid Howells op->error = -ENOMEM; 808e49c7b2fSDavid Howells if (op->nr_files > 2) { 809e49c7b2fSDavid Howells op->more_files = kvcalloc(op->nr_files - 2, 810e49c7b2fSDavid Howells sizeof(struct afs_vnode_param), 8115cf9dd55SDavid Howells GFP_KERNEL); 812e49c7b2fSDavid Howells if (!op->more_files) 813e49c7b2fSDavid Howells goto out_op; 8145cf9dd55SDavid Howells 815e49c7b2fSDavid Howells for (i = 2; i < op->nr_files; i++) { 816e49c7b2fSDavid Howells vp = &op->more_files[i - 2]; 817e49c7b2fSDavid Howells vp->fid = cookie->fids[i]; 81839db9815SDavid Howells 81939db9815SDavid Howells /* Find any inodes that already exist and get their 82039db9815SDavid Howells * callback counters. 82139db9815SDavid Howells */ 822e49c7b2fSDavid Howells ti = ilookup5_nowait(dir->i_sb, vp->fid.vnode, 823e49c7b2fSDavid Howells afs_ilookup5_test_by_fid, &vp->fid); 82439db9815SDavid Howells if (!IS_ERR_OR_NULL(ti)) { 82539db9815SDavid Howells vnode = AFS_FS_I(ti); 826e49c7b2fSDavid Howells vp->dv_before = vnode->status.data_version; 827e49c7b2fSDavid Howells vp->cb_break_before = afs_calc_vnode_cb_break(vnode); 828e49c7b2fSDavid Howells vp->vnode = vnode; 829e49c7b2fSDavid Howells vp->put_vnode = true; 830a9e5c87cSDavid Howells vp->speculative = true; /* vnode not locked */ 831e49c7b2fSDavid Howells } 83239db9815SDavid Howells } 83339db9815SDavid Howells } 83439db9815SDavid Howells 8355cf9dd55SDavid Howells /* Try FS.InlineBulkStatus first. Abort codes for the individual 8365cf9dd55SDavid Howells * lookups contained therein are stored in the reply without aborting 8375cf9dd55SDavid Howells * the whole operation. 8385cf9dd55SDavid Howells */ 839e49c7b2fSDavid Howells op->error = -ENOTSUPP; 840e49c7b2fSDavid Howells if (!cookie->one_only) { 841e49c7b2fSDavid Howells op->ops = &afs_inline_bulk_status_operation; 842e49c7b2fSDavid Howells afs_begin_vnode_operation(op); 843e49c7b2fSDavid Howells afs_wait_for_operation(op); 8445cf9dd55SDavid Howells } 8455cf9dd55SDavid Howells 846e49c7b2fSDavid Howells if (op->error == -ENOTSUPP) { 847e49c7b2fSDavid Howells /* We could try FS.BulkStatus next, but this aborts the entire 848e49c7b2fSDavid Howells * op if any of the lookups fails - so, for the moment, revert 849e49c7b2fSDavid Howells * to FS.FetchStatus for op->file[1]. 8505cf9dd55SDavid Howells */ 851e49c7b2fSDavid Howells op->fetch_status.which = 1; 852f8ea5c7bSDavid Howells op->ops = &afs_lookup_fetch_status_operation; 853e49c7b2fSDavid Howells afs_begin_vnode_operation(op); 854e49c7b2fSDavid Howells afs_wait_for_operation(op); 855e49c7b2fSDavid Howells } 856e49c7b2fSDavid Howells inode = ERR_PTR(op->error); 857e49c7b2fSDavid Howells 858e49c7b2fSDavid Howells out_op: 859e49c7b2fSDavid Howells if (op->error == 0) { 860e49c7b2fSDavid Howells inode = &op->file[1].vnode->vfs_inode; 861e49c7b2fSDavid Howells op->file[1].vnode = NULL; 8625cf9dd55SDavid Howells } 8635cf9dd55SDavid Howells 864e49c7b2fSDavid Howells if (op->file[0].scb.have_status) 865e49c7b2fSDavid Howells dentry->d_fsdata = (void *)(unsigned long)op->file[0].scb.status.data_version; 866e49c7b2fSDavid Howells else 867e49c7b2fSDavid Howells dentry->d_fsdata = (void *)(unsigned long)op->file[0].dv_before; 868e49c7b2fSDavid Howells ret = afs_put_operation(op); 8695cf9dd55SDavid Howells out: 8705cf9dd55SDavid Howells kfree(cookie); 871e49c7b2fSDavid Howells _leave(""); 872e49c7b2fSDavid Howells return inode ?: ERR_PTR(ret); 8735cf9dd55SDavid Howells } 8745cf9dd55SDavid Howells 8755cf9dd55SDavid Howells /* 8766f8880d8SDavid Howells * Look up an entry in a directory with @sys substitution. 8776f8880d8SDavid Howells */ 8786f8880d8SDavid Howells static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry, 8796f8880d8SDavid Howells struct key *key) 8806f8880d8SDavid Howells { 8816f8880d8SDavid Howells struct afs_sysnames *subs; 8826f8880d8SDavid Howells struct afs_net *net = afs_i2net(dir); 8836f8880d8SDavid Howells struct dentry *ret; 8846f8880d8SDavid Howells char *buf, *p, *name; 8856f8880d8SDavid Howells int len, i; 8866f8880d8SDavid Howells 8876f8880d8SDavid Howells _enter(""); 8886f8880d8SDavid Howells 8896f8880d8SDavid Howells ret = ERR_PTR(-ENOMEM); 8906f8880d8SDavid Howells p = buf = kmalloc(AFSNAMEMAX, GFP_KERNEL); 8916f8880d8SDavid Howells if (!buf) 8926f8880d8SDavid Howells goto out_p; 8936f8880d8SDavid Howells if (dentry->d_name.len > 4) { 8946f8880d8SDavid Howells memcpy(p, dentry->d_name.name, dentry->d_name.len - 4); 8956f8880d8SDavid Howells p += dentry->d_name.len - 4; 8966f8880d8SDavid Howells } 8976f8880d8SDavid Howells 8986f8880d8SDavid Howells /* There is an ordered list of substitutes that we have to try. */ 8996f8880d8SDavid Howells read_lock(&net->sysnames_lock); 9006f8880d8SDavid Howells subs = net->sysnames; 9016f8880d8SDavid Howells refcount_inc(&subs->usage); 9026f8880d8SDavid Howells read_unlock(&net->sysnames_lock); 9036f8880d8SDavid Howells 9046f8880d8SDavid Howells for (i = 0; i < subs->nr; i++) { 9056f8880d8SDavid Howells name = subs->subs[i]; 9066f8880d8SDavid Howells len = dentry->d_name.len - 4 + strlen(name); 9076f8880d8SDavid Howells if (len >= AFSNAMEMAX) { 9086f8880d8SDavid Howells ret = ERR_PTR(-ENAMETOOLONG); 9096f8880d8SDavid Howells goto out_s; 9106f8880d8SDavid Howells } 9116f8880d8SDavid Howells 9126f8880d8SDavid Howells strcpy(p, name); 9136f8880d8SDavid Howells ret = lookup_one_len(buf, dentry->d_parent, len); 9146f8880d8SDavid Howells if (IS_ERR(ret) || d_is_positive(ret)) 9156f8880d8SDavid Howells goto out_s; 9166f8880d8SDavid Howells dput(ret); 9176f8880d8SDavid Howells } 9186f8880d8SDavid Howells 9196f8880d8SDavid Howells /* We don't want to d_add() the @sys dentry here as we don't want to 9206f8880d8SDavid Howells * the cached dentry to hide changes to the sysnames list. 9216f8880d8SDavid Howells */ 9226f8880d8SDavid Howells ret = NULL; 9236f8880d8SDavid Howells out_s: 9246f8880d8SDavid Howells afs_put_sysnames(subs); 9256f8880d8SDavid Howells kfree(buf); 9266f8880d8SDavid Howells out_p: 9276f8880d8SDavid Howells key_put(key); 9286f8880d8SDavid Howells return ret; 9296f8880d8SDavid Howells } 9306f8880d8SDavid Howells 9316f8880d8SDavid Howells /* 93208e0e7c8SDavid Howells * look up an entry in a directory 93308e0e7c8SDavid Howells */ 934260a9803SDavid Howells static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, 93500cd8dd3SAl Viro unsigned int flags) 93608e0e7c8SDavid Howells { 9375cf9dd55SDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir); 93840a708bdSDavid Howells struct afs_fid fid = {}; 93908e0e7c8SDavid Howells struct inode *inode; 94034b2a88fSAl Viro struct dentry *d; 94100d3b7a4SDavid Howells struct key *key; 94208e0e7c8SDavid Howells int ret; 94308e0e7c8SDavid Howells 9443b6492dfSDavid Howells _enter("{%llx:%llu},%p{%pd},", 9455cf9dd55SDavid Howells dvnode->fid.vid, dvnode->fid.vnode, dentry, dentry); 946260a9803SDavid Howells 9472b0143b5SDavid Howells ASSERTCMP(d_inode(dentry), ==, NULL); 94808e0e7c8SDavid Howells 94945222b9eSDavid Howells if (dentry->d_name.len >= AFSNAMEMAX) { 95008e0e7c8SDavid Howells _leave(" = -ENAMETOOLONG"); 95108e0e7c8SDavid Howells return ERR_PTR(-ENAMETOOLONG); 95208e0e7c8SDavid Howells } 95308e0e7c8SDavid Howells 9545cf9dd55SDavid Howells if (test_bit(AFS_VNODE_DELETED, &dvnode->flags)) { 95508e0e7c8SDavid Howells _leave(" = -ESTALE"); 95608e0e7c8SDavid Howells return ERR_PTR(-ESTALE); 95708e0e7c8SDavid Howells } 95808e0e7c8SDavid Howells 9595cf9dd55SDavid Howells key = afs_request_key(dvnode->volume->cell); 96000d3b7a4SDavid Howells if (IS_ERR(key)) { 96100d3b7a4SDavid Howells _leave(" = %ld [key]", PTR_ERR(key)); 962e231c2eeSDavid Howells return ERR_CAST(key); 96300d3b7a4SDavid Howells } 96400d3b7a4SDavid Howells 9655cf9dd55SDavid Howells ret = afs_validate(dvnode, key); 96608e0e7c8SDavid Howells if (ret < 0) { 96700d3b7a4SDavid Howells key_put(key); 968260a9803SDavid Howells _leave(" = %d [val]", ret); 9691da177e4SLinus Torvalds return ERR_PTR(ret); 9701da177e4SLinus Torvalds } 9711da177e4SLinus Torvalds 9726f8880d8SDavid Howells if (dentry->d_name.len >= 4 && 9736f8880d8SDavid Howells dentry->d_name.name[dentry->d_name.len - 4] == '@' && 9746f8880d8SDavid Howells dentry->d_name.name[dentry->d_name.len - 3] == 's' && 9756f8880d8SDavid Howells dentry->d_name.name[dentry->d_name.len - 2] == 'y' && 9766f8880d8SDavid Howells dentry->d_name.name[dentry->d_name.len - 1] == 's') 9776f8880d8SDavid Howells return afs_lookup_atsys(dir, dentry, key); 9786f8880d8SDavid Howells 979d55b4da4SDavid Howells afs_stat_v(dvnode, n_lookup); 9805cf9dd55SDavid Howells inode = afs_do_lookup(dir, dentry, key); 98134b2a88fSAl Viro key_put(key); 982f52b83b0SDavid Howells if (inode == ERR_PTR(-ENOENT)) 9835cf9dd55SDavid Howells inode = afs_try_auto_mntpt(dentry, dir); 98440a708bdSDavid Howells 98540a708bdSDavid Howells if (!IS_ERR_OR_NULL(inode)) 98640a708bdSDavid Howells fid = AFS_FS_I(inode)->fid; 98740a708bdSDavid Howells 988fed79fd7SDavid Howells _debug("splice %p", dentry->d_inode); 98934b2a88fSAl Viro d = d_splice_alias(inode, dentry); 99080548b03SDavid Howells if (!IS_ERR_OR_NULL(d)) { 99134b2a88fSAl Viro d->d_fsdata = dentry->d_fsdata; 99240a708bdSDavid Howells trace_afs_lookup(dvnode, &d->d_name, &fid); 99380548b03SDavid Howells } else { 99440a708bdSDavid Howells trace_afs_lookup(dvnode, &dentry->d_name, &fid); 99580548b03SDavid Howells } 996e49c7b2fSDavid Howells _leave(""); 99734b2a88fSAl Viro return d; 998ec26815aSDavid Howells } 9991da177e4SLinus Torvalds 10001da177e4SLinus Torvalds /* 1001a0753c29SDavid Howells * Check the validity of a dentry under RCU conditions. 1002a0753c29SDavid Howells */ 1003a0753c29SDavid Howells static int afs_d_revalidate_rcu(struct dentry *dentry) 1004a0753c29SDavid Howells { 1005a0753c29SDavid Howells struct afs_vnode *dvnode, *vnode; 1006a0753c29SDavid Howells struct dentry *parent; 1007a0753c29SDavid Howells struct inode *dir, *inode; 1008a0753c29SDavid Howells long dir_version, de_version; 1009a0753c29SDavid Howells 1010a0753c29SDavid Howells _enter("%p", dentry); 1011a0753c29SDavid Howells 1012a0753c29SDavid Howells /* Check the parent directory is still valid first. */ 1013a0753c29SDavid Howells parent = READ_ONCE(dentry->d_parent); 1014a0753c29SDavid Howells dir = d_inode_rcu(parent); 1015a0753c29SDavid Howells if (!dir) 1016a0753c29SDavid Howells return -ECHILD; 1017a0753c29SDavid Howells dvnode = AFS_FS_I(dir); 1018a0753c29SDavid Howells if (test_bit(AFS_VNODE_DELETED, &dvnode->flags)) 1019a0753c29SDavid Howells return -ECHILD; 1020a0753c29SDavid Howells 1021a0753c29SDavid Howells if (!afs_check_validity(dvnode)) 1022a0753c29SDavid Howells return -ECHILD; 1023a0753c29SDavid Howells 1024a0753c29SDavid Howells /* We only need to invalidate a dentry if the server's copy changed 1025a0753c29SDavid Howells * behind our back. If we made the change, it's no problem. Note that 1026a0753c29SDavid Howells * on a 32-bit system, we only have 32 bits in the dentry to store the 1027a0753c29SDavid Howells * version. 1028a0753c29SDavid Howells */ 1029a0753c29SDavid Howells dir_version = (long)READ_ONCE(dvnode->status.data_version); 1030a0753c29SDavid Howells de_version = (long)READ_ONCE(dentry->d_fsdata); 1031a0753c29SDavid Howells if (de_version != dir_version) { 1032a0753c29SDavid Howells dir_version = (long)READ_ONCE(dvnode->invalid_before); 1033a0753c29SDavid Howells if (de_version - dir_version < 0) 1034a0753c29SDavid Howells return -ECHILD; 1035a0753c29SDavid Howells } 1036a0753c29SDavid Howells 1037a0753c29SDavid Howells /* Check to see if the vnode referred to by the dentry still 1038a0753c29SDavid Howells * has a callback. 1039a0753c29SDavid Howells */ 1040a0753c29SDavid Howells if (d_really_is_positive(dentry)) { 1041a0753c29SDavid Howells inode = d_inode_rcu(dentry); 1042a0753c29SDavid Howells if (inode) { 1043a0753c29SDavid Howells vnode = AFS_FS_I(inode); 1044a0753c29SDavid Howells if (!afs_check_validity(vnode)) 1045a0753c29SDavid Howells return -ECHILD; 1046a0753c29SDavid Howells } 1047a0753c29SDavid Howells } 1048a0753c29SDavid Howells 1049a0753c29SDavid Howells return 1; /* Still valid */ 1050a0753c29SDavid Howells } 1051a0753c29SDavid Howells 1052a0753c29SDavid Howells /* 10531da177e4SLinus Torvalds * check that a dentry lookup hit has found a valid entry 10541da177e4SLinus Torvalds * - NOTE! the hit can be a negative hit too, so we can't assume we have an 10551da177e4SLinus Torvalds * inode 10561da177e4SLinus Torvalds */ 10570b728e19SAl Viro static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) 10581da177e4SLinus Torvalds { 1059260a9803SDavid Howells struct afs_vnode *vnode, *dir; 10603f649ab7SKees Cook struct afs_fid fid; 10611da177e4SLinus Torvalds struct dentry *parent; 1062c435ee34SDavid Howells struct inode *inode; 106300d3b7a4SDavid Howells struct key *key; 106440fc8102SDavid Howells afs_dataversion_t dir_version, invalid_before; 10659dd0b82eSDavid Howells long de_version; 10661da177e4SLinus Torvalds int ret; 10671da177e4SLinus Torvalds 10680b728e19SAl Viro if (flags & LOOKUP_RCU) 1069a0753c29SDavid Howells return afs_d_revalidate_rcu(dentry); 107034286d66SNick Piggin 1071c435ee34SDavid Howells if (d_really_is_positive(dentry)) { 10722b0143b5SDavid Howells vnode = AFS_FS_I(d_inode(dentry)); 10733b6492dfSDavid Howells _enter("{v={%llx:%llu} n=%pd fl=%lx},", 1074a455589fSAl Viro vnode->fid.vid, vnode->fid.vnode, dentry, 1075260a9803SDavid Howells vnode->flags); 1076c435ee34SDavid Howells } else { 1077a455589fSAl Viro _enter("{neg n=%pd}", dentry); 1078c435ee34SDavid Howells } 10791da177e4SLinus Torvalds 1080260a9803SDavid Howells key = afs_request_key(AFS_FS_S(dentry->d_sb)->volume->cell); 108100d3b7a4SDavid Howells if (IS_ERR(key)) 108200d3b7a4SDavid Howells key = NULL; 108300d3b7a4SDavid Howells 1084c435ee34SDavid Howells if (d_really_is_positive(dentry)) { 1085c435ee34SDavid Howells inode = d_inode(dentry); 1086c435ee34SDavid Howells if (inode) { 1087c435ee34SDavid Howells vnode = AFS_FS_I(inode); 1088c435ee34SDavid Howells afs_validate(vnode, key); 1089c435ee34SDavid Howells if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) 1090c435ee34SDavid Howells goto out_bad; 1091c435ee34SDavid Howells } 1092c435ee34SDavid Howells } 1093c435ee34SDavid Howells 10941da177e4SLinus Torvalds /* lock down the parent dentry so we can peer at it */ 109508e0e7c8SDavid Howells parent = dget_parent(dentry); 10962b0143b5SDavid Howells dir = AFS_FS_I(d_inode(parent)); 10971da177e4SLinus Torvalds 1098260a9803SDavid Howells /* validate the parent directory */ 1099260a9803SDavid Howells afs_validate(dir, key); 1100260a9803SDavid Howells 1101260a9803SDavid Howells if (test_bit(AFS_VNODE_DELETED, &dir->flags)) { 1102a455589fSAl Viro _debug("%pd: parent dir deleted", dentry); 1103c435ee34SDavid Howells goto out_bad_parent; 11041da177e4SLinus Torvalds } 11051da177e4SLinus Torvalds 1106a4ff7401SDavid Howells /* We only need to invalidate a dentry if the server's copy changed 1107a4ff7401SDavid Howells * behind our back. If we made the change, it's no problem. Note that 1108a4ff7401SDavid Howells * on a 32-bit system, we only have 32 bits in the dentry to store the 1109a4ff7401SDavid Howells * version. 1110a4ff7401SDavid Howells */ 11119dd0b82eSDavid Howells dir_version = dir->status.data_version; 1112a4ff7401SDavid Howells de_version = (long)dentry->d_fsdata; 11139dd0b82eSDavid Howells if (de_version == (long)dir_version) 11145dc84855SDavid Howells goto out_valid_noupdate; 1115a4ff7401SDavid Howells 111640fc8102SDavid Howells invalid_before = dir->invalid_before; 111740fc8102SDavid Howells if (de_version - (long)invalid_before >= 0) 1118a4ff7401SDavid Howells goto out_valid; 1119260a9803SDavid Howells 112008e0e7c8SDavid Howells _debug("dir modified"); 1121d55b4da4SDavid Howells afs_stat_v(dir, n_reval); 11221da177e4SLinus Torvalds 11231da177e4SLinus Torvalds /* search the directory for this vnode */ 11249dd0b82eSDavid Howells ret = afs_do_lookup_one(&dir->vfs_inode, dentry, &fid, key, &dir_version); 1125260a9803SDavid Howells switch (ret) { 1126260a9803SDavid Howells case 0: 1127260a9803SDavid Howells /* the filename maps to something */ 11282b0143b5SDavid Howells if (d_really_is_negative(dentry)) 1129c435ee34SDavid Howells goto out_bad_parent; 1130c435ee34SDavid Howells inode = d_inode(dentry); 1131c435ee34SDavid Howells if (is_bad_inode(inode)) { 1132a455589fSAl Viro printk("kAFS: afs_d_revalidate: %pd2 has bad inode\n", 1133a455589fSAl Viro dentry); 1134c435ee34SDavid Howells goto out_bad_parent; 11351da177e4SLinus Torvalds } 11361da177e4SLinus Torvalds 1137c435ee34SDavid Howells vnode = AFS_FS_I(inode); 1138c435ee34SDavid Howells 11391da177e4SLinus Torvalds /* if the vnode ID has changed, then the dirent points to a 11401da177e4SLinus Torvalds * different file */ 114108e0e7c8SDavid Howells if (fid.vnode != vnode->fid.vnode) { 11423b6492dfSDavid Howells _debug("%pd: dirent changed [%llu != %llu]", 1143a455589fSAl Viro dentry, fid.vnode, 114408e0e7c8SDavid Howells vnode->fid.vnode); 11451da177e4SLinus Torvalds goto not_found; 11461da177e4SLinus Torvalds } 11471da177e4SLinus Torvalds 11481da177e4SLinus Torvalds /* if the vnode ID uniqifier has changed, then the file has 1149260a9803SDavid Howells * been deleted and replaced, and the original vnode ID has 1150260a9803SDavid Howells * been reused */ 115108e0e7c8SDavid Howells if (fid.unique != vnode->fid.unique) { 1152a455589fSAl Viro _debug("%pd: file deleted (uq %u -> %u I:%u)", 1153a455589fSAl Viro dentry, fid.unique, 11547a224228SJean Noel Cordenner vnode->fid.unique, 1155c435ee34SDavid Howells vnode->vfs_inode.i_generation); 1156c435ee34SDavid Howells write_seqlock(&vnode->cb_lock); 115708e0e7c8SDavid Howells set_bit(AFS_VNODE_DELETED, &vnode->flags); 1158c435ee34SDavid Howells write_sequnlock(&vnode->cb_lock); 1159260a9803SDavid Howells goto not_found; 1160260a9803SDavid Howells } 1161260a9803SDavid Howells goto out_valid; 1162260a9803SDavid Howells 1163260a9803SDavid Howells case -ENOENT: 1164260a9803SDavid Howells /* the filename is unknown */ 1165a455589fSAl Viro _debug("%pd: dirent not found", dentry); 11662b0143b5SDavid Howells if (d_really_is_positive(dentry)) 1167260a9803SDavid Howells goto not_found; 1168260a9803SDavid Howells goto out_valid; 1169260a9803SDavid Howells 1170260a9803SDavid Howells default: 1171a455589fSAl Viro _debug("failed to iterate dir %pd: %d", 1172a455589fSAl Viro parent, ret); 1173c435ee34SDavid Howells goto out_bad_parent; 11741da177e4SLinus Torvalds } 117508e0e7c8SDavid Howells 11761da177e4SLinus Torvalds out_valid: 11779dd0b82eSDavid Howells dentry->d_fsdata = (void *)(unsigned long)dir_version; 11785dc84855SDavid Howells out_valid_noupdate: 11791da177e4SLinus Torvalds dput(parent); 118000d3b7a4SDavid Howells key_put(key); 11811da177e4SLinus Torvalds _leave(" = 1 [valid]"); 11821da177e4SLinus Torvalds return 1; 11831da177e4SLinus Torvalds 11841da177e4SLinus Torvalds /* the dirent, if it exists, now points to a different vnode */ 11851da177e4SLinus Torvalds not_found: 11861da177e4SLinus Torvalds spin_lock(&dentry->d_lock); 11871da177e4SLinus Torvalds dentry->d_flags |= DCACHE_NFSFS_RENAMED; 11881da177e4SLinus Torvalds spin_unlock(&dentry->d_lock); 11891da177e4SLinus Torvalds 1190c435ee34SDavid Howells out_bad_parent: 1191a455589fSAl Viro _debug("dropping dentry %pd2", dentry); 11921da177e4SLinus Torvalds dput(parent); 1193c435ee34SDavid Howells out_bad: 119400d3b7a4SDavid Howells key_put(key); 11951da177e4SLinus Torvalds 11961da177e4SLinus Torvalds _leave(" = 0 [bad]"); 11971da177e4SLinus Torvalds return 0; 1198ec26815aSDavid Howells } 11991da177e4SLinus Torvalds 12001da177e4SLinus Torvalds /* 12011da177e4SLinus Torvalds * allow the VFS to enquire as to whether a dentry should be unhashed (mustn't 12021da177e4SLinus Torvalds * sleep) 12031da177e4SLinus Torvalds * - called from dput() when d_count is going to 0. 12041da177e4SLinus Torvalds * - return 1 to request dentry be unhashed, 0 otherwise 12051da177e4SLinus Torvalds */ 1206fe15ce44SNick Piggin static int afs_d_delete(const struct dentry *dentry) 12071da177e4SLinus Torvalds { 1208a455589fSAl Viro _enter("%pd", dentry); 12091da177e4SLinus Torvalds 12101da177e4SLinus Torvalds if (dentry->d_flags & DCACHE_NFSFS_RENAMED) 12111da177e4SLinus Torvalds goto zap; 12121da177e4SLinus Torvalds 12132b0143b5SDavid Howells if (d_really_is_positive(dentry) && 12142b0143b5SDavid Howells (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(d_inode(dentry))->flags) || 12152b0143b5SDavid Howells test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(d_inode(dentry))->flags))) 12161da177e4SLinus Torvalds goto zap; 12171da177e4SLinus Torvalds 12181da177e4SLinus Torvalds _leave(" = 0 [keep]"); 12191da177e4SLinus Torvalds return 0; 12201da177e4SLinus Torvalds 12211da177e4SLinus Torvalds zap: 12221da177e4SLinus Torvalds _leave(" = 1 [zap]"); 12231da177e4SLinus Torvalds return 1; 1224ec26815aSDavid Howells } 1225260a9803SDavid Howells 1226260a9803SDavid Howells /* 122779ddbfa5SDavid Howells * Clean up sillyrename files on dentry removal. 122879ddbfa5SDavid Howells */ 122979ddbfa5SDavid Howells static void afs_d_iput(struct dentry *dentry, struct inode *inode) 123079ddbfa5SDavid Howells { 123179ddbfa5SDavid Howells if (dentry->d_flags & DCACHE_NFSFS_RENAMED) 123279ddbfa5SDavid Howells afs_silly_iput(dentry, inode); 123379ddbfa5SDavid Howells iput(inode); 123479ddbfa5SDavid Howells } 123579ddbfa5SDavid Howells 123679ddbfa5SDavid Howells /* 1237260a9803SDavid Howells * handle dentry release 1238260a9803SDavid Howells */ 123966c7e1d3SDavid Howells void afs_d_release(struct dentry *dentry) 1240260a9803SDavid Howells { 1241a455589fSAl Viro _enter("%pd", dentry); 1242260a9803SDavid Howells } 1243260a9803SDavid Howells 1244728279a5SDavid Howells void afs_check_for_remote_deletion(struct afs_operation *op) 1245728279a5SDavid Howells { 1246728279a5SDavid Howells struct afs_vnode *vnode = op->file[0].vnode; 1247728279a5SDavid Howells 1248728279a5SDavid Howells switch (op->ac.abort_code) { 1249728279a5SDavid Howells case VNOVNODE: 1250728279a5SDavid Howells set_bit(AFS_VNODE_DELETED, &vnode->flags); 1251728279a5SDavid Howells afs_break_callback(vnode, afs_cb_break_for_deleted); 1252728279a5SDavid Howells } 1253728279a5SDavid Howells } 1254728279a5SDavid Howells 1255260a9803SDavid Howells /* 1256d2ddc776SDavid Howells * Create a new inode for create/mkdir/symlink 1257d2ddc776SDavid Howells */ 1258e49c7b2fSDavid Howells static void afs_vnode_new_inode(struct afs_operation *op) 1259d2ddc776SDavid Howells { 1260e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 12615a813276SDavid Howells struct afs_vnode *vnode; 1262d2ddc776SDavid Howells struct inode *inode; 1263d2ddc776SDavid Howells 1264e49c7b2fSDavid Howells _enter(""); 1265d2ddc776SDavid Howells 1266e49c7b2fSDavid Howells ASSERTCMP(op->error, ==, 0); 1267e49c7b2fSDavid Howells 1268e49c7b2fSDavid Howells inode = afs_iget(op, vp); 1269d2ddc776SDavid Howells if (IS_ERR(inode)) { 1270d2ddc776SDavid Howells /* ENOMEM or EINTR at a really inconvenient time - just abandon 1271d2ddc776SDavid Howells * the new directory on the server. 1272d2ddc776SDavid Howells */ 1273e49c7b2fSDavid Howells op->error = PTR_ERR(inode); 1274d2ddc776SDavid Howells return; 1275d2ddc776SDavid Howells } 1276d2ddc776SDavid Howells 12775a813276SDavid Howells vnode = AFS_FS_I(inode); 12785a813276SDavid Howells set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); 1279e49c7b2fSDavid Howells if (!op->error) 1280e49c7b2fSDavid Howells afs_cache_permit(vnode, op->key, vnode->cb_break, &vp->scb); 1281e49c7b2fSDavid Howells d_instantiate(op->dentry, inode); 1282d2ddc776SDavid Howells } 1283d2ddc776SDavid Howells 1284e49c7b2fSDavid Howells static void afs_create_success(struct afs_operation *op) 1285b8359153SDavid Howells { 1286e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1287da8d0755SDavid Howells op->ctime = op->file[0].scb.status.mtime_client; 1288e49c7b2fSDavid Howells afs_vnode_commit_status(op, &op->file[0]); 1289e49c7b2fSDavid Howells afs_update_dentry_version(op, &op->file[0], op->dentry); 1290e49c7b2fSDavid Howells afs_vnode_new_inode(op); 1291b8359153SDavid Howells } 1292b8359153SDavid Howells 1293e49c7b2fSDavid Howells static void afs_create_edit_dir(struct afs_operation *op) 12949dd0b82eSDavid Howells { 1295e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 1296e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 1297e49c7b2fSDavid Howells struct afs_vnode *dvnode = dvp->vnode; 1298e49c7b2fSDavid Howells 1299e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1300e49c7b2fSDavid Howells 1301e49c7b2fSDavid Howells down_write(&dvnode->validate_lock); 1302e49c7b2fSDavid Howells if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) && 1303e49c7b2fSDavid Howells dvnode->status.data_version == dvp->dv_before + dvp->dv_delta) 1304e49c7b2fSDavid Howells afs_edit_dir_add(dvnode, &op->dentry->d_name, &vp->fid, 1305e49c7b2fSDavid Howells op->create.reason); 1306e49c7b2fSDavid Howells up_write(&dvnode->validate_lock); 13079dd0b82eSDavid Howells } 13089dd0b82eSDavid Howells 1309e49c7b2fSDavid Howells static void afs_create_put(struct afs_operation *op) 1310e49c7b2fSDavid Howells { 1311e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1312e49c7b2fSDavid Howells 1313e49c7b2fSDavid Howells if (op->error) 1314e49c7b2fSDavid Howells d_drop(op->dentry); 1315e49c7b2fSDavid Howells } 1316e49c7b2fSDavid Howells 1317e49c7b2fSDavid Howells static const struct afs_operation_ops afs_mkdir_operation = { 1318e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_make_dir, 1319e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_make_dir, 1320e49c7b2fSDavid Howells .success = afs_create_success, 1321728279a5SDavid Howells .aborted = afs_check_for_remote_deletion, 1322e49c7b2fSDavid Howells .edit_dir = afs_create_edit_dir, 1323e49c7b2fSDavid Howells .put = afs_create_put, 1324e49c7b2fSDavid Howells }; 1325e49c7b2fSDavid Howells 13269dd0b82eSDavid Howells /* 1327260a9803SDavid Howells * create a directory on an AFS filesystem 1328260a9803SDavid Howells */ 1329549c7297SChristian Brauner static int afs_mkdir(struct user_namespace *mnt_userns, struct inode *dir, 1330549c7297SChristian Brauner struct dentry *dentry, umode_t mode) 1331260a9803SDavid Howells { 1332e49c7b2fSDavid Howells struct afs_operation *op; 1333d2ddc776SDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir); 1334260a9803SDavid Howells 13353b6492dfSDavid Howells _enter("{%llx:%llu},{%pd},%ho", 1336a455589fSAl Viro dvnode->fid.vid, dvnode->fid.vnode, dentry, mode); 1337260a9803SDavid Howells 1338e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, dvnode->volume); 1339e49c7b2fSDavid Howells if (IS_ERR(op)) { 1340260a9803SDavid Howells d_drop(dentry); 1341e49c7b2fSDavid Howells return PTR_ERR(op); 1342e49c7b2fSDavid Howells } 1343e49c7b2fSDavid Howells 1344e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, dvnode); 1345e49c7b2fSDavid Howells op->file[0].dv_delta = 1; 1346da8d0755SDavid Howells op->file[0].update_ctime = true; 1347e49c7b2fSDavid Howells op->dentry = dentry; 1348e49c7b2fSDavid Howells op->create.mode = S_IFDIR | mode; 1349e49c7b2fSDavid Howells op->create.reason = afs_edit_dir_for_mkdir; 1350e49c7b2fSDavid Howells op->ops = &afs_mkdir_operation; 1351e49c7b2fSDavid Howells return afs_do_sync_operation(op); 1352260a9803SDavid Howells } 1353260a9803SDavid Howells 1354260a9803SDavid Howells /* 1355d2ddc776SDavid Howells * Remove a subdir from a directory. 1356260a9803SDavid Howells */ 1357d2ddc776SDavid Howells static void afs_dir_remove_subdir(struct dentry *dentry) 1358260a9803SDavid Howells { 13592b0143b5SDavid Howells if (d_really_is_positive(dentry)) { 1360d2ddc776SDavid Howells struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); 1361d2ddc776SDavid Howells 1362260a9803SDavid Howells clear_nlink(&vnode->vfs_inode); 1363260a9803SDavid Howells set_bit(AFS_VNODE_DELETED, &vnode->flags); 1364c435ee34SDavid Howells clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); 136563a4681fSDavid Howells clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); 1366260a9803SDavid Howells } 1367260a9803SDavid Howells } 1368260a9803SDavid Howells 1369e49c7b2fSDavid Howells static void afs_rmdir_success(struct afs_operation *op) 1370e49c7b2fSDavid Howells { 1371e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1372da8d0755SDavid Howells op->ctime = op->file[0].scb.status.mtime_client; 1373e49c7b2fSDavid Howells afs_vnode_commit_status(op, &op->file[0]); 1374e49c7b2fSDavid Howells afs_update_dentry_version(op, &op->file[0], op->dentry); 1375e49c7b2fSDavid Howells } 1376e49c7b2fSDavid Howells 1377e49c7b2fSDavid Howells static void afs_rmdir_edit_dir(struct afs_operation *op) 1378e49c7b2fSDavid Howells { 1379e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 1380e49c7b2fSDavid Howells struct afs_vnode *dvnode = dvp->vnode; 1381e49c7b2fSDavid Howells 1382e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1383e49c7b2fSDavid Howells afs_dir_remove_subdir(op->dentry); 1384e49c7b2fSDavid Howells 1385e49c7b2fSDavid Howells down_write(&dvnode->validate_lock); 1386e49c7b2fSDavid Howells if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) && 1387e49c7b2fSDavid Howells dvnode->status.data_version == dvp->dv_before + dvp->dv_delta) 1388e49c7b2fSDavid Howells afs_edit_dir_remove(dvnode, &op->dentry->d_name, 1389e49c7b2fSDavid Howells afs_edit_dir_for_rmdir); 1390e49c7b2fSDavid Howells up_write(&dvnode->validate_lock); 1391e49c7b2fSDavid Howells } 1392e49c7b2fSDavid Howells 1393e49c7b2fSDavid Howells static void afs_rmdir_put(struct afs_operation *op) 1394e49c7b2fSDavid Howells { 1395e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1396e49c7b2fSDavid Howells if (op->file[1].vnode) 1397e49c7b2fSDavid Howells up_write(&op->file[1].vnode->rmdir_lock); 1398e49c7b2fSDavid Howells } 1399e49c7b2fSDavid Howells 1400e49c7b2fSDavid Howells static const struct afs_operation_ops afs_rmdir_operation = { 1401e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_remove_dir, 1402e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_remove_dir, 1403e49c7b2fSDavid Howells .success = afs_rmdir_success, 1404728279a5SDavid Howells .aborted = afs_check_for_remote_deletion, 1405e49c7b2fSDavid Howells .edit_dir = afs_rmdir_edit_dir, 1406e49c7b2fSDavid Howells .put = afs_rmdir_put, 1407e49c7b2fSDavid Howells }; 1408e49c7b2fSDavid Howells 1409260a9803SDavid Howells /* 1410d2ddc776SDavid Howells * remove a directory from an AFS filesystem 1411260a9803SDavid Howells */ 1412d2ddc776SDavid Howells static int afs_rmdir(struct inode *dir, struct dentry *dentry) 1413260a9803SDavid Howells { 1414e49c7b2fSDavid Howells struct afs_operation *op; 1415f58db83fSDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL; 1416260a9803SDavid Howells int ret; 1417260a9803SDavid Howells 14183b6492dfSDavid Howells _enter("{%llx:%llu},{%pd}", 1419a455589fSAl Viro dvnode->fid.vid, dvnode->fid.vnode, dentry); 1420260a9803SDavid Howells 1421e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, dvnode->volume); 1422e49c7b2fSDavid Howells if (IS_ERR(op)) 1423e49c7b2fSDavid Howells return PTR_ERR(op); 1424a58823acSDavid Howells 1425e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, dvnode); 1426e49c7b2fSDavid Howells op->file[0].dv_delta = 1; 1427da8d0755SDavid Howells op->file[0].update_ctime = true; 1428e49c7b2fSDavid Howells 1429e49c7b2fSDavid Howells op->dentry = dentry; 1430e49c7b2fSDavid Howells op->ops = &afs_rmdir_operation; 1431260a9803SDavid Howells 1432f58db83fSDavid Howells /* Try to make sure we have a callback promise on the victim. */ 1433f58db83fSDavid Howells if (d_really_is_positive(dentry)) { 1434f58db83fSDavid Howells vnode = AFS_FS_I(d_inode(dentry)); 1435e49c7b2fSDavid Howells ret = afs_validate(vnode, op->key); 1436f58db83fSDavid Howells if (ret < 0) 1437e49c7b2fSDavid Howells goto error; 1438f58db83fSDavid Howells } 1439f58db83fSDavid Howells 144079ddbfa5SDavid Howells if (vnode) { 144179ddbfa5SDavid Howells ret = down_write_killable(&vnode->rmdir_lock); 144279ddbfa5SDavid Howells if (ret < 0) 1443e49c7b2fSDavid Howells goto error; 1444e49c7b2fSDavid Howells op->file[1].vnode = vnode; 144579ddbfa5SDavid Howells } 144679ddbfa5SDavid Howells 1447e49c7b2fSDavid Howells return afs_do_sync_operation(op); 1448a58823acSDavid Howells 1449d2ddc776SDavid Howells error: 1450e49c7b2fSDavid Howells return afs_put_operation(op); 1451d2ddc776SDavid Howells } 1452260a9803SDavid Howells 1453d2ddc776SDavid Howells /* 1454d2ddc776SDavid Howells * Remove a link to a file or symlink from a directory. 1455d2ddc776SDavid Howells * 1456d2ddc776SDavid Howells * If the file was not deleted due to excess hard links, the fileserver will 1457d2ddc776SDavid Howells * break the callback promise on the file - if it had one - before it returns 1458d2ddc776SDavid Howells * to us, and if it was deleted, it won't 1459d2ddc776SDavid Howells * 1460d2ddc776SDavid Howells * However, if we didn't have a callback promise outstanding, or it was 1461d2ddc776SDavid Howells * outstanding on a different server, then it won't break it either... 1462d2ddc776SDavid Howells */ 1463e49c7b2fSDavid Howells static void afs_dir_remove_link(struct afs_operation *op) 1464d2ddc776SDavid Howells { 1465e49c7b2fSDavid Howells struct afs_vnode *dvnode = op->file[0].vnode; 1466e49c7b2fSDavid Howells struct afs_vnode *vnode = op->file[1].vnode; 1467e49c7b2fSDavid Howells struct dentry *dentry = op->dentry; 1468e49c7b2fSDavid Howells int ret; 1469d2ddc776SDavid Howells 1470e49c7b2fSDavid Howells if (op->error != 0 || 1471e49c7b2fSDavid Howells (op->file[1].scb.have_status && op->file[1].scb.have_error)) 1472e49c7b2fSDavid Howells return; 1473e49c7b2fSDavid Howells if (d_really_is_positive(dentry)) 1474e49c7b2fSDavid Howells return; 1475d2ddc776SDavid Howells 147630062bd1SDavid Howells if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { 147730062bd1SDavid Howells /* Already done */ 1478a38a7558SDavid Howells } else if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { 1479a38a7558SDavid Howells write_seqlock(&vnode->cb_lock); 1480440fbc3aSDavid Howells drop_nlink(&vnode->vfs_inode); 1481440fbc3aSDavid Howells if (vnode->vfs_inode.i_nlink == 0) { 1482440fbc3aSDavid Howells set_bit(AFS_VNODE_DELETED, &vnode->flags); 1483051d2525SDavid Howells __afs_break_callback(vnode, afs_cb_break_for_unlink); 1484440fbc3aSDavid Howells } 1485a38a7558SDavid Howells write_sequnlock(&vnode->cb_lock); 1486440fbc3aSDavid Howells } else { 1487051d2525SDavid Howells afs_break_callback(vnode, afs_cb_break_for_unlink); 1488440fbc3aSDavid Howells 1489d2ddc776SDavid Howells if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) 1490e49c7b2fSDavid Howells _debug("AFS_VNODE_DELETED"); 1491d2ddc776SDavid Howells 1492e49c7b2fSDavid Howells ret = afs_validate(vnode, op->key); 1493e49c7b2fSDavid Howells if (ret != -ESTALE) 1494e49c7b2fSDavid Howells op->error = ret; 1495d2ddc776SDavid Howells } 1496d2ddc776SDavid Howells 1497e49c7b2fSDavid Howells _debug("nlink %d [val %d]", vnode->vfs_inode.i_nlink, op->error); 1498d2ddc776SDavid Howells } 1499d2ddc776SDavid Howells 1500e49c7b2fSDavid Howells static void afs_unlink_success(struct afs_operation *op) 1501e49c7b2fSDavid Howells { 1502e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1503da8d0755SDavid Howells op->ctime = op->file[0].scb.status.mtime_client; 1504b6489a49SDavid Howells afs_check_dir_conflict(op, &op->file[0]); 1505e49c7b2fSDavid Howells afs_vnode_commit_status(op, &op->file[0]); 1506e49c7b2fSDavid Howells afs_vnode_commit_status(op, &op->file[1]); 1507e49c7b2fSDavid Howells afs_update_dentry_version(op, &op->file[0], op->dentry); 1508e49c7b2fSDavid Howells afs_dir_remove_link(op); 1509e49c7b2fSDavid Howells } 1510e49c7b2fSDavid Howells 1511e49c7b2fSDavid Howells static void afs_unlink_edit_dir(struct afs_operation *op) 1512e49c7b2fSDavid Howells { 1513e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 1514e49c7b2fSDavid Howells struct afs_vnode *dvnode = dvp->vnode; 1515e49c7b2fSDavid Howells 1516e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1517e49c7b2fSDavid Howells down_write(&dvnode->validate_lock); 1518e49c7b2fSDavid Howells if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) && 1519e49c7b2fSDavid Howells dvnode->status.data_version == dvp->dv_before + dvp->dv_delta) 1520e49c7b2fSDavid Howells afs_edit_dir_remove(dvnode, &op->dentry->d_name, 1521e49c7b2fSDavid Howells afs_edit_dir_for_unlink); 1522e49c7b2fSDavid Howells up_write(&dvnode->validate_lock); 1523e49c7b2fSDavid Howells } 1524e49c7b2fSDavid Howells 1525e49c7b2fSDavid Howells static void afs_unlink_put(struct afs_operation *op) 1526e49c7b2fSDavid Howells { 1527e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1528e49c7b2fSDavid Howells if (op->unlink.need_rehash && op->error < 0 && op->error != -ENOENT) 1529e49c7b2fSDavid Howells d_rehash(op->dentry); 1530e49c7b2fSDavid Howells } 1531e49c7b2fSDavid Howells 1532e49c7b2fSDavid Howells static const struct afs_operation_ops afs_unlink_operation = { 1533e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_remove_file, 1534e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_remove_file, 1535e49c7b2fSDavid Howells .success = afs_unlink_success, 1536728279a5SDavid Howells .aborted = afs_check_for_remote_deletion, 1537e49c7b2fSDavid Howells .edit_dir = afs_unlink_edit_dir, 1538e49c7b2fSDavid Howells .put = afs_unlink_put, 1539e49c7b2fSDavid Howells }; 1540e49c7b2fSDavid Howells 1541d2ddc776SDavid Howells /* 1542d2ddc776SDavid Howells * Remove a file or symlink from an AFS filesystem. 1543d2ddc776SDavid Howells */ 1544d2ddc776SDavid Howells static int afs_unlink(struct inode *dir, struct dentry *dentry) 1545d2ddc776SDavid Howells { 1546e49c7b2fSDavid Howells struct afs_operation *op; 1547fa59f52fSDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir); 1548fa59f52fSDavid Howells struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); 1549d2ddc776SDavid Howells int ret; 1550d2ddc776SDavid Howells 15513b6492dfSDavid Howells _enter("{%llx:%llu},{%pd}", 1552d2ddc776SDavid Howells dvnode->fid.vid, dvnode->fid.vnode, dentry); 1553d2ddc776SDavid Howells 1554d2ddc776SDavid Howells if (dentry->d_name.len >= AFSNAMEMAX) 1555d2ddc776SDavid Howells return -ENAMETOOLONG; 1556d2ddc776SDavid Howells 1557e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, dvnode->volume); 1558e49c7b2fSDavid Howells if (IS_ERR(op)) 1559e49c7b2fSDavid Howells return PTR_ERR(op); 1560a58823acSDavid Howells 1561e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, dvnode); 1562e49c7b2fSDavid Howells op->file[0].dv_delta = 1; 1563da8d0755SDavid Howells op->file[0].update_ctime = true; 1564d2ddc776SDavid Howells 1565d2ddc776SDavid Howells /* Try to make sure we have a callback promise on the victim. */ 1566e49c7b2fSDavid Howells ret = afs_validate(vnode, op->key); 1567e49c7b2fSDavid Howells if (ret < 0) { 1568e49c7b2fSDavid Howells op->error = ret; 1569e49c7b2fSDavid Howells goto error; 1570e49c7b2fSDavid Howells } 1571d2ddc776SDavid Howells 157279ddbfa5SDavid Howells spin_lock(&dentry->d_lock); 1573fa59f52fSDavid Howells if (d_count(dentry) > 1) { 157479ddbfa5SDavid Howells spin_unlock(&dentry->d_lock); 157579ddbfa5SDavid Howells /* Start asynchronous writeout of the inode */ 157679ddbfa5SDavid Howells write_inode_now(d_inode(dentry), 0); 1577e49c7b2fSDavid Howells op->error = afs_sillyrename(dvnode, vnode, dentry, op->key); 1578e49c7b2fSDavid Howells goto error; 157979ddbfa5SDavid Howells } 158079ddbfa5SDavid Howells if (!d_unhashed(dentry)) { 158179ddbfa5SDavid Howells /* Prevent a race with RCU lookup. */ 158279ddbfa5SDavid Howells __d_drop(dentry); 1583e49c7b2fSDavid Howells op->unlink.need_rehash = true; 158479ddbfa5SDavid Howells } 158579ddbfa5SDavid Howells spin_unlock(&dentry->d_lock); 158679ddbfa5SDavid Howells 1587e49c7b2fSDavid Howells op->file[1].vnode = vnode; 1588da8d0755SDavid Howells op->file[1].update_ctime = true; 1589b6489a49SDavid Howells op->file[1].op_unlinked = true; 1590e49c7b2fSDavid Howells op->dentry = dentry; 1591e49c7b2fSDavid Howells op->ops = &afs_unlink_operation; 1592b6489a49SDavid Howells afs_begin_vnode_operation(op); 1593b6489a49SDavid Howells afs_wait_for_operation(op); 1594b6489a49SDavid Howells 1595b6489a49SDavid Howells /* If there was a conflict with a third party, check the status of the 1596b6489a49SDavid Howells * unlinked vnode. 1597b6489a49SDavid Howells */ 1598b6489a49SDavid Howells if (op->error == 0 && (op->flags & AFS_OPERATION_DIR_CONFLICT)) { 1599b6489a49SDavid Howells op->file[1].update_ctime = false; 1600b6489a49SDavid Howells op->fetch_status.which = 1; 1601b6489a49SDavid Howells op->ops = &afs_fetch_status_operation; 1602b6489a49SDavid Howells afs_begin_vnode_operation(op); 1603b6489a49SDavid Howells afs_wait_for_operation(op); 1604b6489a49SDavid Howells } 1605b6489a49SDavid Howells 1606b6489a49SDavid Howells return afs_put_operation(op); 1607a58823acSDavid Howells 1608260a9803SDavid Howells error: 1609e49c7b2fSDavid Howells return afs_put_operation(op); 1610260a9803SDavid Howells } 1611260a9803SDavid Howells 1612e49c7b2fSDavid Howells static const struct afs_operation_ops afs_create_operation = { 1613e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_create_file, 1614e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_create_file, 1615e49c7b2fSDavid Howells .success = afs_create_success, 1616728279a5SDavid Howells .aborted = afs_check_for_remote_deletion, 1617e49c7b2fSDavid Howells .edit_dir = afs_create_edit_dir, 1618e49c7b2fSDavid Howells .put = afs_create_put, 1619e49c7b2fSDavid Howells }; 1620e49c7b2fSDavid Howells 1621260a9803SDavid Howells /* 1622260a9803SDavid Howells * create a regular file on an AFS filesystem 1623260a9803SDavid Howells */ 1624549c7297SChristian Brauner static int afs_create(struct user_namespace *mnt_userns, struct inode *dir, 1625549c7297SChristian Brauner struct dentry *dentry, umode_t mode, bool excl) 1626260a9803SDavid Howells { 1627e49c7b2fSDavid Howells struct afs_operation *op; 162843dd388bSColin Ian King struct afs_vnode *dvnode = AFS_FS_I(dir); 1629e49c7b2fSDavid Howells int ret = -ENAMETOOLONG; 1630260a9803SDavid Howells 1631e49c7b2fSDavid Howells _enter("{%llx:%llu},{%pd},%ho", 1632a455589fSAl Viro dvnode->fid.vid, dvnode->fid.vnode, dentry, mode); 1633260a9803SDavid Howells 1634d2ddc776SDavid Howells if (dentry->d_name.len >= AFSNAMEMAX) 1635d2ddc776SDavid Howells goto error; 1636d2ddc776SDavid Howells 1637e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, dvnode->volume); 1638e49c7b2fSDavid Howells if (IS_ERR(op)) { 1639e49c7b2fSDavid Howells ret = PTR_ERR(op); 1640260a9803SDavid Howells goto error; 1641260a9803SDavid Howells } 1642260a9803SDavid Howells 1643e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, dvnode); 1644e49c7b2fSDavid Howells op->file[0].dv_delta = 1; 1645da8d0755SDavid Howells op->file[0].update_ctime = true; 1646a58823acSDavid Howells 1647e49c7b2fSDavid Howells op->dentry = dentry; 1648e49c7b2fSDavid Howells op->create.mode = S_IFREG | mode; 1649e49c7b2fSDavid Howells op->create.reason = afs_edit_dir_for_create; 1650e49c7b2fSDavid Howells op->ops = &afs_create_operation; 1651e49c7b2fSDavid Howells return afs_do_sync_operation(op); 1652a58823acSDavid Howells 1653260a9803SDavid Howells error: 1654260a9803SDavid Howells d_drop(dentry); 1655260a9803SDavid Howells _leave(" = %d", ret); 1656260a9803SDavid Howells return ret; 1657260a9803SDavid Howells } 1658260a9803SDavid Howells 1659e49c7b2fSDavid Howells static void afs_link_success(struct afs_operation *op) 1660e49c7b2fSDavid Howells { 1661e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 1662e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 1663e49c7b2fSDavid Howells 1664e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1665da8d0755SDavid Howells op->ctime = dvp->scb.status.mtime_client; 1666e49c7b2fSDavid Howells afs_vnode_commit_status(op, dvp); 1667e49c7b2fSDavid Howells afs_vnode_commit_status(op, vp); 1668e49c7b2fSDavid Howells afs_update_dentry_version(op, dvp, op->dentry); 1669e49c7b2fSDavid Howells if (op->dentry_2->d_parent == op->dentry->d_parent) 1670e49c7b2fSDavid Howells afs_update_dentry_version(op, dvp, op->dentry_2); 1671e49c7b2fSDavid Howells ihold(&vp->vnode->vfs_inode); 1672e49c7b2fSDavid Howells d_instantiate(op->dentry, &vp->vnode->vfs_inode); 1673e49c7b2fSDavid Howells } 1674e49c7b2fSDavid Howells 1675e49c7b2fSDavid Howells static void afs_link_put(struct afs_operation *op) 1676e49c7b2fSDavid Howells { 1677e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1678e49c7b2fSDavid Howells if (op->error) 1679e49c7b2fSDavid Howells d_drop(op->dentry); 1680e49c7b2fSDavid Howells } 1681e49c7b2fSDavid Howells 1682e49c7b2fSDavid Howells static const struct afs_operation_ops afs_link_operation = { 1683e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_link, 1684e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_link, 1685e49c7b2fSDavid Howells .success = afs_link_success, 1686728279a5SDavid Howells .aborted = afs_check_for_remote_deletion, 1687e49c7b2fSDavid Howells .edit_dir = afs_create_edit_dir, 1688e49c7b2fSDavid Howells .put = afs_link_put, 1689e49c7b2fSDavid Howells }; 1690e49c7b2fSDavid Howells 1691260a9803SDavid Howells /* 1692260a9803SDavid Howells * create a hard link between files in an AFS filesystem 1693260a9803SDavid Howells */ 1694260a9803SDavid Howells static int afs_link(struct dentry *from, struct inode *dir, 1695260a9803SDavid Howells struct dentry *dentry) 1696260a9803SDavid Howells { 1697e49c7b2fSDavid Howells struct afs_operation *op; 1698a58823acSDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir); 1699a58823acSDavid Howells struct afs_vnode *vnode = AFS_FS_I(d_inode(from)); 1700e49c7b2fSDavid Howells int ret = -ENAMETOOLONG; 1701260a9803SDavid Howells 17023b6492dfSDavid Howells _enter("{%llx:%llu},{%llx:%llu},{%pd}", 1703260a9803SDavid Howells vnode->fid.vid, vnode->fid.vnode, 1704260a9803SDavid Howells dvnode->fid.vid, dvnode->fid.vnode, 1705a455589fSAl Viro dentry); 1706260a9803SDavid Howells 1707d2ddc776SDavid Howells if (dentry->d_name.len >= AFSNAMEMAX) 1708d2ddc776SDavid Howells goto error; 1709d2ddc776SDavid Howells 1710e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, dvnode->volume); 1711e49c7b2fSDavid Howells if (IS_ERR(op)) { 1712e49c7b2fSDavid Howells ret = PTR_ERR(op); 1713a58823acSDavid Howells goto error; 1714260a9803SDavid Howells } 1715260a9803SDavid Howells 1716e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, dvnode); 1717e49c7b2fSDavid Howells afs_op_set_vnode(op, 1, vnode); 1718e49c7b2fSDavid Howells op->file[0].dv_delta = 1; 1719da8d0755SDavid Howells op->file[0].update_ctime = true; 1720da8d0755SDavid Howells op->file[1].update_ctime = true; 1721a58823acSDavid Howells 1722e49c7b2fSDavid Howells op->dentry = dentry; 1723e49c7b2fSDavid Howells op->dentry_2 = from; 1724e49c7b2fSDavid Howells op->ops = &afs_link_operation; 1725e49c7b2fSDavid Howells op->create.reason = afs_edit_dir_for_link; 1726e49c7b2fSDavid Howells return afs_do_sync_operation(op); 1727260a9803SDavid Howells 1728260a9803SDavid Howells error: 1729260a9803SDavid Howells d_drop(dentry); 1730260a9803SDavid Howells _leave(" = %d", ret); 1731260a9803SDavid Howells return ret; 1732260a9803SDavid Howells } 1733260a9803SDavid Howells 1734e49c7b2fSDavid Howells static const struct afs_operation_ops afs_symlink_operation = { 1735e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_symlink, 1736e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_symlink, 1737e49c7b2fSDavid Howells .success = afs_create_success, 1738728279a5SDavid Howells .aborted = afs_check_for_remote_deletion, 1739e49c7b2fSDavid Howells .edit_dir = afs_create_edit_dir, 1740e49c7b2fSDavid Howells .put = afs_create_put, 1741e49c7b2fSDavid Howells }; 1742e49c7b2fSDavid Howells 1743260a9803SDavid Howells /* 1744260a9803SDavid Howells * create a symlink in an AFS filesystem 1745260a9803SDavid Howells */ 1746549c7297SChristian Brauner static int afs_symlink(struct user_namespace *mnt_userns, struct inode *dir, 1747549c7297SChristian Brauner struct dentry *dentry, const char *content) 1748260a9803SDavid Howells { 1749e49c7b2fSDavid Howells struct afs_operation *op; 1750d2ddc776SDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir); 1751260a9803SDavid Howells int ret; 1752260a9803SDavid Howells 17533b6492dfSDavid Howells _enter("{%llx:%llu},{%pd},%s", 1754a455589fSAl Viro dvnode->fid.vid, dvnode->fid.vnode, dentry, 1755260a9803SDavid Howells content); 1756260a9803SDavid Howells 1757d2ddc776SDavid Howells ret = -ENAMETOOLONG; 1758d2ddc776SDavid Howells if (dentry->d_name.len >= AFSNAMEMAX) 1759d2ddc776SDavid Howells goto error; 1760d2ddc776SDavid Howells 1761260a9803SDavid Howells ret = -EINVAL; 176245222b9eSDavid Howells if (strlen(content) >= AFSPATHMAX) 1763260a9803SDavid Howells goto error; 1764260a9803SDavid Howells 1765e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, dvnode->volume); 1766e49c7b2fSDavid Howells if (IS_ERR(op)) { 1767e49c7b2fSDavid Howells ret = PTR_ERR(op); 1768a58823acSDavid Howells goto error; 1769260a9803SDavid Howells } 1770260a9803SDavid Howells 1771e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, dvnode); 1772e49c7b2fSDavid Howells op->file[0].dv_delta = 1; 1773a58823acSDavid Howells 1774e49c7b2fSDavid Howells op->dentry = dentry; 1775e49c7b2fSDavid Howells op->ops = &afs_symlink_operation; 1776e49c7b2fSDavid Howells op->create.reason = afs_edit_dir_for_symlink; 1777e49c7b2fSDavid Howells op->create.symlink = content; 1778e49c7b2fSDavid Howells return afs_do_sync_operation(op); 1779d2ddc776SDavid Howells 1780260a9803SDavid Howells error: 1781260a9803SDavid Howells d_drop(dentry); 1782260a9803SDavid Howells _leave(" = %d", ret); 1783260a9803SDavid Howells return ret; 1784260a9803SDavid Howells } 1785260a9803SDavid Howells 1786e49c7b2fSDavid Howells static void afs_rename_success(struct afs_operation *op) 1787260a9803SDavid Howells { 1788e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1789e49c7b2fSDavid Howells 1790da8d0755SDavid Howells op->ctime = op->file[0].scb.status.mtime_client; 1791b6489a49SDavid Howells afs_check_dir_conflict(op, &op->file[1]); 1792e49c7b2fSDavid Howells afs_vnode_commit_status(op, &op->file[0]); 1793da8d0755SDavid Howells if (op->file[1].vnode != op->file[0].vnode) { 1794da8d0755SDavid Howells op->ctime = op->file[1].scb.status.mtime_client; 1795e49c7b2fSDavid Howells afs_vnode_commit_status(op, &op->file[1]); 1796e49c7b2fSDavid Howells } 1797da8d0755SDavid Howells } 1798e49c7b2fSDavid Howells 1799e49c7b2fSDavid Howells static void afs_rename_edit_dir(struct afs_operation *op) 1800e49c7b2fSDavid Howells { 1801e49c7b2fSDavid Howells struct afs_vnode_param *orig_dvp = &op->file[0]; 1802e49c7b2fSDavid Howells struct afs_vnode_param *new_dvp = &op->file[1]; 1803e49c7b2fSDavid Howells struct afs_vnode *orig_dvnode = orig_dvp->vnode; 1804e49c7b2fSDavid Howells struct afs_vnode *new_dvnode = new_dvp->vnode; 1805e49c7b2fSDavid Howells struct afs_vnode *vnode = AFS_FS_I(d_inode(op->dentry)); 1806e49c7b2fSDavid Howells struct dentry *old_dentry = op->dentry; 1807e49c7b2fSDavid Howells struct dentry *new_dentry = op->dentry_2; 180879ddbfa5SDavid Howells struct inode *new_inode; 1809260a9803SDavid Howells 1810e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 18111cd66c93SMiklos Szeredi 1812e49c7b2fSDavid Howells if (op->rename.rehash) { 1813e49c7b2fSDavid Howells d_rehash(op->rename.rehash); 1814e49c7b2fSDavid Howells op->rename.rehash = NULL; 1815260a9803SDavid Howells } 1816260a9803SDavid Howells 18172105c282SDavid Howells down_write(&orig_dvnode->validate_lock); 18182105c282SDavid Howells if (test_bit(AFS_VNODE_DIR_VALID, &orig_dvnode->flags) && 1819e49c7b2fSDavid Howells orig_dvnode->status.data_version == orig_dvp->dv_before + orig_dvp->dv_delta) 182063a4681fSDavid Howells afs_edit_dir_remove(orig_dvnode, &old_dentry->d_name, 182179ddbfa5SDavid Howells afs_edit_dir_for_rename_0); 182263a4681fSDavid Howells 1823e49c7b2fSDavid Howells if (new_dvnode != orig_dvnode) { 1824e49c7b2fSDavid Howells up_write(&orig_dvnode->validate_lock); 18252105c282SDavid Howells down_write(&new_dvnode->validate_lock); 18262105c282SDavid Howells } 1827e49c7b2fSDavid Howells 18282105c282SDavid Howells if (test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags) && 1829e49c7b2fSDavid Howells new_dvnode->status.data_version == new_dvp->dv_before + new_dvp->dv_delta) { 1830e49c7b2fSDavid Howells if (!op->rename.new_negative) 183163a4681fSDavid Howells afs_edit_dir_remove(new_dvnode, &new_dentry->d_name, 183279ddbfa5SDavid Howells afs_edit_dir_for_rename_1); 183363a4681fSDavid Howells 183463a4681fSDavid Howells afs_edit_dir_add(new_dvnode, &new_dentry->d_name, 183579ddbfa5SDavid Howells &vnode->fid, afs_edit_dir_for_rename_2); 18362105c282SDavid Howells } 183779ddbfa5SDavid Howells 183879ddbfa5SDavid Howells new_inode = d_inode(new_dentry); 183979ddbfa5SDavid Howells if (new_inode) { 184079ddbfa5SDavid Howells spin_lock(&new_inode->i_lock); 184179ddbfa5SDavid Howells if (new_inode->i_nlink > 0) 184279ddbfa5SDavid Howells drop_nlink(new_inode); 184379ddbfa5SDavid Howells spin_unlock(&new_inode->i_lock); 184479ddbfa5SDavid Howells } 18459dd0b82eSDavid Howells 18469dd0b82eSDavid Howells /* Now we can update d_fsdata on the dentries to reflect their 18479dd0b82eSDavid Howells * new parent's data_version. 18489dd0b82eSDavid Howells * 18499dd0b82eSDavid Howells * Note that if we ever implement RENAME_EXCHANGE, we'll have 18509dd0b82eSDavid Howells * to update both dentries with opposing dir versions. 18519dd0b82eSDavid Howells */ 1852e49c7b2fSDavid Howells afs_update_dentry_version(op, new_dvp, op->dentry); 1853e49c7b2fSDavid Howells afs_update_dentry_version(op, new_dvp, op->dentry_2); 1854e49c7b2fSDavid Howells 185579ddbfa5SDavid Howells d_move(old_dentry, new_dentry); 1856e49c7b2fSDavid Howells 18572105c282SDavid Howells up_write(&new_dvnode->validate_lock); 185863a4681fSDavid Howells } 185963a4681fSDavid Howells 1860e49c7b2fSDavid Howells static void afs_rename_put(struct afs_operation *op) 1861e49c7b2fSDavid Howells { 1862e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1863e49c7b2fSDavid Howells if (op->rename.rehash) 1864e49c7b2fSDavid Howells d_rehash(op->rename.rehash); 1865e49c7b2fSDavid Howells dput(op->rename.tmp); 1866e49c7b2fSDavid Howells if (op->error) 1867e49c7b2fSDavid Howells d_rehash(op->dentry); 1868e49c7b2fSDavid Howells } 1869e49c7b2fSDavid Howells 1870e49c7b2fSDavid Howells static const struct afs_operation_ops afs_rename_operation = { 1871e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_rename, 1872e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_rename, 1873e49c7b2fSDavid Howells .success = afs_rename_success, 1874e49c7b2fSDavid Howells .edit_dir = afs_rename_edit_dir, 1875e49c7b2fSDavid Howells .put = afs_rename_put, 1876e49c7b2fSDavid Howells }; 1877e49c7b2fSDavid Howells 1878e49c7b2fSDavid Howells /* 1879e49c7b2fSDavid Howells * rename a file in an AFS filesystem and/or move it between directories 1880e49c7b2fSDavid Howells */ 1881549c7297SChristian Brauner static int afs_rename(struct user_namespace *mnt_userns, struct inode *old_dir, 1882549c7297SChristian Brauner struct dentry *old_dentry, struct inode *new_dir, 1883549c7297SChristian Brauner struct dentry *new_dentry, unsigned int flags) 1884e49c7b2fSDavid Howells { 1885e49c7b2fSDavid Howells struct afs_operation *op; 1886e49c7b2fSDavid Howells struct afs_vnode *orig_dvnode, *new_dvnode, *vnode; 1887e49c7b2fSDavid Howells int ret; 1888e49c7b2fSDavid Howells 1889e49c7b2fSDavid Howells if (flags) 1890e49c7b2fSDavid Howells return -EINVAL; 1891e49c7b2fSDavid Howells 1892e49c7b2fSDavid Howells /* Don't allow silly-rename files be moved around. */ 1893e49c7b2fSDavid Howells if (old_dentry->d_flags & DCACHE_NFSFS_RENAMED) 1894e49c7b2fSDavid Howells return -EINVAL; 1895e49c7b2fSDavid Howells 1896e49c7b2fSDavid Howells vnode = AFS_FS_I(d_inode(old_dentry)); 1897e49c7b2fSDavid Howells orig_dvnode = AFS_FS_I(old_dir); 1898e49c7b2fSDavid Howells new_dvnode = AFS_FS_I(new_dir); 1899e49c7b2fSDavid Howells 1900e49c7b2fSDavid Howells _enter("{%llx:%llu},{%llx:%llu},{%llx:%llu},{%pd}", 1901e49c7b2fSDavid Howells orig_dvnode->fid.vid, orig_dvnode->fid.vnode, 1902e49c7b2fSDavid Howells vnode->fid.vid, vnode->fid.vnode, 1903e49c7b2fSDavid Howells new_dvnode->fid.vid, new_dvnode->fid.vnode, 1904e49c7b2fSDavid Howells new_dentry); 1905e49c7b2fSDavid Howells 1906e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, orig_dvnode->volume); 1907e49c7b2fSDavid Howells if (IS_ERR(op)) 1908e49c7b2fSDavid Howells return PTR_ERR(op); 1909e49c7b2fSDavid Howells 1910e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, orig_dvnode); 1911e49c7b2fSDavid Howells afs_op_set_vnode(op, 1, new_dvnode); /* May be same as orig_dvnode */ 1912e49c7b2fSDavid Howells op->file[0].dv_delta = 1; 1913e49c7b2fSDavid Howells op->file[1].dv_delta = 1; 1914da8d0755SDavid Howells op->file[0].update_ctime = true; 1915da8d0755SDavid Howells op->file[1].update_ctime = true; 1916e49c7b2fSDavid Howells 1917e49c7b2fSDavid Howells op->dentry = old_dentry; 1918e49c7b2fSDavid Howells op->dentry_2 = new_dentry; 1919e49c7b2fSDavid Howells op->rename.new_negative = d_is_negative(new_dentry); 1920e49c7b2fSDavid Howells op->ops = &afs_rename_operation; 1921e49c7b2fSDavid Howells 1922e49c7b2fSDavid Howells /* For non-directories, check whether the target is busy and if so, 1923e49c7b2fSDavid Howells * make a copy of the dentry and then do a silly-rename. If the 1924e49c7b2fSDavid Howells * silly-rename succeeds, the copied dentry is hashed and becomes the 1925e49c7b2fSDavid Howells * new target. 1926e49c7b2fSDavid Howells */ 1927e49c7b2fSDavid Howells if (d_is_positive(new_dentry) && !d_is_dir(new_dentry)) { 1928e49c7b2fSDavid Howells /* To prevent any new references to the target during the 1929e49c7b2fSDavid Howells * rename, we unhash the dentry in advance. 1930e49c7b2fSDavid Howells */ 1931e49c7b2fSDavid Howells if (!d_unhashed(new_dentry)) { 1932e49c7b2fSDavid Howells d_drop(new_dentry); 1933e49c7b2fSDavid Howells op->rename.rehash = new_dentry; 1934e49c7b2fSDavid Howells } 1935e49c7b2fSDavid Howells 1936e49c7b2fSDavid Howells if (d_count(new_dentry) > 2) { 1937e49c7b2fSDavid Howells /* copy the target dentry's name */ 1938e49c7b2fSDavid Howells ret = -ENOMEM; 1939e49c7b2fSDavid Howells op->rename.tmp = d_alloc(new_dentry->d_parent, 1940e49c7b2fSDavid Howells &new_dentry->d_name); 1941e49c7b2fSDavid Howells if (!op->rename.tmp) 1942e49c7b2fSDavid Howells goto error; 1943e49c7b2fSDavid Howells 1944e49c7b2fSDavid Howells ret = afs_sillyrename(new_dvnode, 1945e49c7b2fSDavid Howells AFS_FS_I(d_inode(new_dentry)), 1946e49c7b2fSDavid Howells new_dentry, op->key); 1947e49c7b2fSDavid Howells if (ret) 1948e49c7b2fSDavid Howells goto error; 1949e49c7b2fSDavid Howells 1950e49c7b2fSDavid Howells op->dentry_2 = op->rename.tmp; 1951e49c7b2fSDavid Howells op->rename.rehash = NULL; 1952e49c7b2fSDavid Howells op->rename.new_negative = true; 1953e49c7b2fSDavid Howells } 1954e49c7b2fSDavid Howells } 1955e49c7b2fSDavid Howells 1956e49c7b2fSDavid Howells /* This bit is potentially nasty as there's a potential race with 1957e49c7b2fSDavid Howells * afs_d_revalidate{,_rcu}(). We have to change d_fsdata on the dentry 1958e49c7b2fSDavid Howells * to reflect it's new parent's new data_version after the op, but 1959e49c7b2fSDavid Howells * d_revalidate may see old_dentry between the op having taken place 1960e49c7b2fSDavid Howells * and the version being updated. 1961e49c7b2fSDavid Howells * 1962e49c7b2fSDavid Howells * So drop the old_dentry for now to make other threads go through 1963e49c7b2fSDavid Howells * lookup instead - which we hold a lock against. 1964e49c7b2fSDavid Howells */ 1965e49c7b2fSDavid Howells d_drop(old_dentry); 1966e49c7b2fSDavid Howells 1967e49c7b2fSDavid Howells return afs_do_sync_operation(op); 1968e49c7b2fSDavid Howells 1969260a9803SDavid Howells error: 1970e49c7b2fSDavid Howells return afs_put_operation(op); 1971260a9803SDavid Howells } 1972f3ddee8dSDavid Howells 1973f3ddee8dSDavid Howells /* 1974f3ddee8dSDavid Howells * Release a directory page and clean up its private state if it's not busy 1975f3ddee8dSDavid Howells * - return true if the page can now be released, false if not 1976f3ddee8dSDavid Howells */ 1977f3ddee8dSDavid Howells static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags) 1978f3ddee8dSDavid Howells { 1979f3ddee8dSDavid Howells struct afs_vnode *dvnode = AFS_FS_I(page->mapping->host); 1980f3ddee8dSDavid Howells 19813b6492dfSDavid Howells _enter("{{%llx:%llu}[%lu]}", dvnode->fid.vid, dvnode->fid.vnode, page->index); 1982f3ddee8dSDavid Howells 1983fa04a40bSDavid Howells detach_page_private(page); 1984f3ddee8dSDavid Howells 1985f3ddee8dSDavid Howells /* The directory will need reloading. */ 1986f3ddee8dSDavid Howells if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) 1987f3ddee8dSDavid Howells afs_stat_v(dvnode, n_relpg); 1988f3ddee8dSDavid Howells return 1; 1989f3ddee8dSDavid Howells } 1990f3ddee8dSDavid Howells 1991f3ddee8dSDavid Howells /* 1992f3ddee8dSDavid Howells * invalidate part or all of a page 1993f3ddee8dSDavid Howells * - release a page and clean up its private data if offset is 0 (indicating 1994f3ddee8dSDavid Howells * the entire page) 1995f3ddee8dSDavid Howells */ 1996f3ddee8dSDavid Howells static void afs_dir_invalidatepage(struct page *page, unsigned int offset, 1997f3ddee8dSDavid Howells unsigned int length) 1998f3ddee8dSDavid Howells { 1999f3ddee8dSDavid Howells struct afs_vnode *dvnode = AFS_FS_I(page->mapping->host); 2000f3ddee8dSDavid Howells 2001f3ddee8dSDavid Howells _enter("{%lu},%u,%u", page->index, offset, length); 2002f3ddee8dSDavid Howells 2003f3ddee8dSDavid Howells BUG_ON(!PageLocked(page)); 2004f3ddee8dSDavid Howells 2005f3ddee8dSDavid Howells /* The directory will need reloading. */ 2006f3ddee8dSDavid Howells if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) 2007f3ddee8dSDavid Howells afs_stat_v(dvnode, n_inval); 2008f3ddee8dSDavid Howells 2009f3ddee8dSDavid Howells /* we clean up only if the entire page is being invalidated */ 2010fa04a40bSDavid Howells if (offset == 0 && length == PAGE_SIZE) 2011fa04a40bSDavid Howells detach_page_private(page); 2012f3ddee8dSDavid Howells } 2013