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); 2725885a35SAl Viro static bool afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen, 285cf9dd55SDavid Howells loff_t fpos, u64 ino, unsigned dtype); 2925885a35SAl Viro static bool afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen, 30afefdbb2SDavid Howells loff_t fpos, u64 ino, unsigned dtype); 316c960e68SChristian Brauner static int afs_create(struct mnt_idmap *idmap, struct inode *dir, 32549c7297SChristian Brauner struct dentry *dentry, umode_t mode, bool excl); 33c54bd91eSChristian Brauner static int afs_mkdir(struct mnt_idmap *idmap, 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); 397a77db95SChristian Brauner static int afs_symlink(struct mnt_idmap *idmap, struct inode *dir, 40549c7297SChristian Brauner struct dentry *dentry, const char *content); 41e18275aeSChristian Brauner static int afs_rename(struct mnt_idmap *idmap, struct inode *old_dir, 42549c7297SChristian Brauner struct dentry *old_dentry, struct inode *new_dir, 43549c7297SChristian Brauner struct dentry *new_dentry, unsigned int flags); 44508cae68SMatthew Wilcox (Oracle) static bool afs_dir_release_folio(struct folio *folio, gfp_t gfp_flags); 45f6bc6fb8SMatthew Wilcox (Oracle) static void afs_dir_invalidate_folio(struct folio *folio, size_t offset, 46f6bc6fb8SMatthew Wilcox (Oracle) size_t length); 47f3ddee8dSDavid Howells 48d7c994b3SMatthew Wilcox (Oracle) static bool afs_dir_dirty_folio(struct address_space *mapping, 49d7c994b3SMatthew Wilcox (Oracle) struct folio *folio) 50f3ddee8dSDavid Howells { 51f3ddee8dSDavid Howells BUG(); /* This should never happen. */ 52f3ddee8dSDavid Howells } 531da177e4SLinus Torvalds 544b6f5d20SArjan van de Ven const struct file_operations afs_dir_file_operations = { 551da177e4SLinus Torvalds .open = afs_dir_open, 5600d3b7a4SDavid Howells .release = afs_release, 5729884effSAl Viro .iterate_shared = afs_readdir, 58e8d6c554SDavid Howells .lock = afs_lock, 593222a3e5SChristoph Hellwig .llseek = generic_file_llseek, 601da177e4SLinus Torvalds }; 611da177e4SLinus Torvalds 62754661f1SArjan van de Ven const struct inode_operations afs_dir_inode_operations = { 63260a9803SDavid Howells .create = afs_create, 64260a9803SDavid Howells .lookup = afs_lookup, 65260a9803SDavid Howells .link = afs_link, 66260a9803SDavid Howells .unlink = afs_unlink, 67260a9803SDavid Howells .symlink = afs_symlink, 68260a9803SDavid Howells .mkdir = afs_mkdir, 69260a9803SDavid Howells .rmdir = afs_rmdir, 702773bf00SMiklos Szeredi .rename = afs_rename, 7100d3b7a4SDavid Howells .permission = afs_permission, 72416351f2SDavid Howells .getattr = afs_getattr, 7331143d5dSDavid Howells .setattr = afs_setattr, 741da177e4SLinus Torvalds }; 751da177e4SLinus Torvalds 76f3ddee8dSDavid Howells const struct address_space_operations afs_dir_aops = { 77d7c994b3SMatthew Wilcox (Oracle) .dirty_folio = afs_dir_dirty_folio, 78508cae68SMatthew Wilcox (Oracle) .release_folio = afs_dir_release_folio, 79f6bc6fb8SMatthew Wilcox (Oracle) .invalidate_folio = afs_dir_invalidate_folio, 80a9eb558aSDavid Howells .migrate_folio = filemap_migrate_folio, 81f3ddee8dSDavid Howells }; 82f3ddee8dSDavid Howells 83d61dcce2SAl Viro const struct dentry_operations afs_fs_dentry_operations = { 841da177e4SLinus Torvalds .d_revalidate = afs_d_revalidate, 851da177e4SLinus Torvalds .d_delete = afs_d_delete, 86260a9803SDavid Howells .d_release = afs_d_release, 87d18610b0SDavid Howells .d_automount = afs_d_automount, 8879ddbfa5SDavid Howells .d_iput = afs_d_iput, 891da177e4SLinus Torvalds }; 901da177e4SLinus Torvalds 915cf9dd55SDavid Howells struct afs_lookup_one_cookie { 925cf9dd55SDavid Howells struct dir_context ctx; 935cf9dd55SDavid Howells struct qstr name; 945cf9dd55SDavid Howells bool found; 955cf9dd55SDavid Howells struct afs_fid fid; 965cf9dd55SDavid Howells }; 975cf9dd55SDavid Howells 98260a9803SDavid Howells struct afs_lookup_cookie { 991bbae9f8SAl Viro struct dir_context ctx; 1001bbae9f8SAl Viro struct qstr name; 1015cf9dd55SDavid Howells bool found; 1025cf9dd55SDavid Howells bool one_only; 1035cf9dd55SDavid Howells unsigned short nr_fids; 1045cf9dd55SDavid Howells struct afs_fid fids[50]; 1051da177e4SLinus Torvalds }; 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds /* 108255ed636SDavid Howells * Drop the refs that we're holding on the folios we were reading into. We've 109c4508464SDavid Howells * got refs on the first nr_pages pages. 110c4508464SDavid Howells */ 111c4508464SDavid Howells static void afs_dir_read_cleanup(struct afs_read *req) 112c4508464SDavid Howells { 113874c8ca1SDavid Howells struct address_space *mapping = req->vnode->netfs.inode.i_mapping; 114255ed636SDavid Howells struct folio *folio; 115c4508464SDavid Howells pgoff_t last = req->nr_pages - 1; 116c4508464SDavid Howells 117c4508464SDavid Howells XA_STATE(xas, &mapping->i_pages, 0); 118c4508464SDavid Howells 119c4508464SDavid Howells if (unlikely(!req->nr_pages)) 120c4508464SDavid Howells return; 121c4508464SDavid Howells 122c4508464SDavid Howells rcu_read_lock(); 123255ed636SDavid Howells xas_for_each(&xas, folio, last) { 124255ed636SDavid Howells if (xas_retry(&xas, folio)) 125c4508464SDavid Howells continue; 126255ed636SDavid Howells BUG_ON(xa_is_value(folio)); 127255ed636SDavid Howells ASSERTCMP(folio_file_mapping(folio), ==, mapping); 128c4508464SDavid Howells 129255ed636SDavid Howells folio_put(folio); 130c4508464SDavid Howells } 131c4508464SDavid Howells 132c4508464SDavid Howells rcu_read_unlock(); 133c4508464SDavid Howells } 134c4508464SDavid Howells 135c4508464SDavid Howells /* 136255ed636SDavid Howells * check that a directory folio is valid 1371da177e4SLinus Torvalds */ 138255ed636SDavid Howells static bool afs_dir_check_folio(struct afs_vnode *dvnode, struct folio *folio, 139f3ddee8dSDavid Howells loff_t i_size) 1401da177e4SLinus Torvalds { 141255ed636SDavid Howells union afs_xdr_dir_block *block; 142255ed636SDavid Howells size_t offset, size; 143255ed636SDavid Howells loff_t pos; 1441da177e4SLinus Torvalds 145255ed636SDavid Howells /* Determine how many magic numbers there should be in this folio, but 146dab17c1aSDavid Howells * we must take care because the directory may change size under us. 147dab17c1aSDavid Howells */ 148255ed636SDavid Howells pos = folio_pos(folio); 149255ed636SDavid Howells if (i_size <= pos) 150dab17c1aSDavid Howells goto checked; 151dab17c1aSDavid Howells 152255ed636SDavid Howells size = min_t(loff_t, folio_size(folio), i_size - pos); 153255ed636SDavid Howells for (offset = 0; offset < size; offset += sizeof(*block)) { 154255ed636SDavid Howells block = kmap_local_folio(folio, offset); 155255ed636SDavid Howells if (block->hdr.magic != AFS_DIR_MAGIC) { 156255ed636SDavid Howells printk("kAFS: %s(%lx): [%llx] bad magic %zx/%zx is %04hx\n", 157874c8ca1SDavid Howells __func__, dvnode->netfs.inode.i_ino, 158255ed636SDavid Howells pos, offset, size, ntohs(block->hdr.magic)); 159255ed636SDavid Howells trace_afs_dir_check_failed(dvnode, pos + offset, i_size); 160255ed636SDavid Howells kunmap_local(block); 161f51375cdSDavid Howells trace_afs_file_error(dvnode, -EIO, afs_file_error_dir_bad_magic); 1621da177e4SLinus Torvalds goto error; 1631da177e4SLinus Torvalds } 16463a4681fSDavid Howells 16563a4681fSDavid Howells /* Make sure each block is NUL terminated so we can reasonably 166255ed636SDavid Howells * use string functions on it. The filenames in the folio 16763a4681fSDavid Howells * *should* be NUL-terminated anyway. 16863a4681fSDavid Howells */ 169255ed636SDavid Howells ((u8 *)block)[AFS_DIR_BLOCK_SIZE - 1] = 0; 170255ed636SDavid Howells 171255ed636SDavid Howells kunmap_local(block); 1721da177e4SLinus Torvalds } 173dab17c1aSDavid Howells checked: 174f3ddee8dSDavid Howells afs_stat_v(dvnode, n_read_dir); 175be5b82dbSAl Viro return true; 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds error: 178be5b82dbSAl Viro return false; 179ec26815aSDavid Howells } 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds /* 182c4508464SDavid Howells * Dump the contents of a directory. 183445b1028SDavid Howells */ 184c4508464SDavid Howells static void afs_dir_dump(struct afs_vnode *dvnode, struct afs_read *req) 185445b1028SDavid Howells { 186255ed636SDavid Howells union afs_xdr_dir_block *block; 187874c8ca1SDavid Howells struct address_space *mapping = dvnode->netfs.inode.i_mapping; 188255ed636SDavid Howells struct folio *folio; 189c4508464SDavid Howells pgoff_t last = req->nr_pages - 1; 190255ed636SDavid Howells size_t offset, size; 191445b1028SDavid Howells 192c4508464SDavid Howells XA_STATE(xas, &mapping->i_pages, 0); 193445b1028SDavid Howells 194c4508464SDavid Howells pr_warn("DIR %llx:%llx f=%llx l=%llx al=%llx\n", 195445b1028SDavid Howells dvnode->fid.vid, dvnode->fid.vnode, 196c4508464SDavid Howells req->file_size, req->len, req->actual_len); 197c4508464SDavid Howells pr_warn("DIR %llx %x %zx %zx\n", 198c4508464SDavid Howells req->pos, req->nr_pages, 199c4508464SDavid Howells req->iter->iov_offset, iov_iter_count(req->iter)); 200445b1028SDavid Howells 201255ed636SDavid Howells xas_for_each(&xas, folio, last) { 202255ed636SDavid Howells if (xas_retry(&xas, folio)) 203c4508464SDavid Howells continue; 204445b1028SDavid Howells 205255ed636SDavid Howells BUG_ON(folio_file_mapping(folio) != mapping); 206c4508464SDavid Howells 207255ed636SDavid Howells size = min_t(loff_t, folio_size(folio), req->actual_len - folio_pos(folio)); 208255ed636SDavid Howells for (offset = 0; offset < size; offset += sizeof(*block)) { 209255ed636SDavid Howells block = kmap_local_folio(folio, offset); 210255ed636SDavid Howells pr_warn("[%02lx] %32phN\n", folio_index(folio) + offset, block); 211255ed636SDavid Howells kunmap_local(block); 212445b1028SDavid Howells } 213445b1028SDavid Howells } 214c4508464SDavid Howells } 215c4508464SDavid Howells 216c4508464SDavid Howells /* 217255ed636SDavid Howells * Check all the blocks in a directory. All the folios are held pinned. 218c4508464SDavid Howells */ 219c4508464SDavid Howells static int afs_dir_check(struct afs_vnode *dvnode, struct afs_read *req) 220c4508464SDavid Howells { 221874c8ca1SDavid Howells struct address_space *mapping = dvnode->netfs.inode.i_mapping; 222255ed636SDavid Howells struct folio *folio; 223c4508464SDavid Howells pgoff_t last = req->nr_pages - 1; 224c4508464SDavid Howells int ret = 0; 225c4508464SDavid Howells 226c4508464SDavid Howells XA_STATE(xas, &mapping->i_pages, 0); 227c4508464SDavid Howells 228c4508464SDavid Howells if (unlikely(!req->nr_pages)) 229c4508464SDavid Howells return 0; 230c4508464SDavid Howells 231c4508464SDavid Howells rcu_read_lock(); 232255ed636SDavid Howells xas_for_each(&xas, folio, last) { 233255ed636SDavid Howells if (xas_retry(&xas, folio)) 234c4508464SDavid Howells continue; 235c4508464SDavid Howells 236255ed636SDavid Howells BUG_ON(folio_file_mapping(folio) != mapping); 237c4508464SDavid Howells 238255ed636SDavid Howells if (!afs_dir_check_folio(dvnode, folio, req->actual_len)) { 239c4508464SDavid Howells afs_dir_dump(dvnode, req); 240c4508464SDavid Howells ret = -EIO; 241c4508464SDavid Howells break; 242c4508464SDavid Howells } 243c4508464SDavid Howells } 244c4508464SDavid Howells 245c4508464SDavid Howells rcu_read_unlock(); 246c4508464SDavid Howells return ret; 247445b1028SDavid Howells } 248445b1028SDavid Howells 249445b1028SDavid Howells /* 2501da177e4SLinus Torvalds * open an AFS directory file 2511da177e4SLinus Torvalds */ 2521da177e4SLinus Torvalds static int afs_dir_open(struct inode *inode, struct file *file) 2531da177e4SLinus Torvalds { 2541da177e4SLinus Torvalds _enter("{%lu}", inode->i_ino); 2551da177e4SLinus Torvalds 25600317636SDavid Howells BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); 25700317636SDavid Howells BUILD_BUG_ON(sizeof(union afs_xdr_dirent) != 32); 2581da177e4SLinus Torvalds 25908e0e7c8SDavid Howells if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags)) 2601da177e4SLinus Torvalds return -ENOENT; 2611da177e4SLinus Torvalds 26200d3b7a4SDavid Howells return afs_open(inode, file); 263ec26815aSDavid Howells } 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds /* 266f3ddee8dSDavid Howells * Read the directory into the pagecache in one go, scrubbing the previous 267255ed636SDavid Howells * contents. The list of folios is returned, pinning them so that they don't 268f3ddee8dSDavid Howells * get reclaimed during the iteration. 269f3ddee8dSDavid Howells */ 270f3ddee8dSDavid Howells static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) 271b61f7dcfSDavid Howells __acquires(&dvnode->validate_lock) 272f3ddee8dSDavid Howells { 273874c8ca1SDavid Howells struct address_space *mapping = dvnode->netfs.inode.i_mapping; 274f3ddee8dSDavid Howells struct afs_read *req; 275f3ddee8dSDavid Howells loff_t i_size; 276255ed636SDavid Howells int nr_pages, i; 277c4508464SDavid Howells int ret; 278*9ea4eff4SMarc Dionne loff_t remote_size = 0; 279f3ddee8dSDavid Howells 280c4508464SDavid Howells _enter(""); 281f3ddee8dSDavid Howells 282c4508464SDavid Howells req = kzalloc(sizeof(*req), GFP_KERNEL); 283f3ddee8dSDavid Howells if (!req) 284f3ddee8dSDavid Howells return ERR_PTR(-ENOMEM); 285f3ddee8dSDavid Howells 286f3ddee8dSDavid Howells refcount_set(&req->usage, 1); 287c4508464SDavid Howells req->vnode = dvnode; 288c69bf479SDavid Howells req->key = key_get(key); 289c4508464SDavid Howells req->cleanup = afs_dir_read_cleanup; 290c4508464SDavid Howells 291c4508464SDavid Howells expand: 292874c8ca1SDavid Howells i_size = i_size_read(&dvnode->netfs.inode); 293*9ea4eff4SMarc Dionne if (i_size < remote_size) 294*9ea4eff4SMarc Dionne i_size = remote_size; 295c4508464SDavid Howells if (i_size < 2048) { 296c4508464SDavid Howells ret = afs_bad(dvnode, afs_file_error_dir_small); 297c4508464SDavid Howells goto error; 298c4508464SDavid Howells } 299c4508464SDavid Howells if (i_size > 2048 * 1024) { 300c4508464SDavid Howells trace_afs_file_error(dvnode, -EFBIG, afs_file_error_dir_big); 301c4508464SDavid Howells ret = -EFBIG; 302f3ddee8dSDavid Howells goto error; 303f3ddee8dSDavid Howells } 304f3ddee8dSDavid Howells 305c4508464SDavid Howells _enter("%llu", i_size); 306c4508464SDavid Howells 307c4508464SDavid Howells nr_pages = (i_size + PAGE_SIZE - 1) / PAGE_SIZE; 308c4508464SDavid Howells 309c4508464SDavid Howells req->actual_len = i_size; /* May change */ 310c4508464SDavid Howells req->len = nr_pages * PAGE_SIZE; /* We can ask for more than there is */ 311c4508464SDavid Howells req->data_version = dvnode->status.data_version; /* May change */ 312de4eda9dSAl Viro iov_iter_xarray(&req->def_iter, ITER_DEST, &dvnode->netfs.inode.i_mapping->i_pages, 313c4508464SDavid Howells 0, i_size); 314c4508464SDavid Howells req->iter = &req->def_iter; 315c4508464SDavid Howells 316c4508464SDavid Howells /* Fill in any gaps that we might find where the memory reclaimer has 317255ed636SDavid Howells * been at work and pin all the folios. If there are any gaps, we will 318f3ddee8dSDavid Howells * need to reread the entire directory contents. 319f3ddee8dSDavid Howells */ 320c4508464SDavid Howells i = req->nr_pages; 321c4508464SDavid Howells while (i < nr_pages) { 322255ed636SDavid Howells struct folio *folio; 323c4508464SDavid Howells 324255ed636SDavid Howells folio = filemap_get_folio(mapping, i); 32566dabbb6SChristoph Hellwig if (IS_ERR(folio)) { 326f3ddee8dSDavid Howells if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) 327f3ddee8dSDavid Howells afs_stat_v(dvnode, n_inval); 328255ed636SDavid Howells folio = __filemap_get_folio(mapping, 329255ed636SDavid Howells i, FGP_LOCK | FGP_CREAT, 330255ed636SDavid Howells mapping->gfp_mask); 33166dabbb6SChristoph Hellwig if (IS_ERR(folio)) { 33266dabbb6SChristoph Hellwig ret = PTR_ERR(folio); 333f3ddee8dSDavid Howells goto error; 33466dabbb6SChristoph Hellwig } 335255ed636SDavid Howells folio_attach_private(folio, (void *)1); 336255ed636SDavid Howells folio_unlock(folio); 337f3ddee8dSDavid Howells } 338255ed636SDavid Howells 339255ed636SDavid Howells req->nr_pages += folio_nr_pages(folio); 340255ed636SDavid Howells i += folio_nr_pages(folio); 341c4508464SDavid Howells } 342f3ddee8dSDavid Howells 343f3ddee8dSDavid Howells /* If we're going to reload, we need to lock all the pages to prevent 344f3ddee8dSDavid Howells * races. 345f3ddee8dSDavid Howells */ 346f3ddee8dSDavid Howells ret = -ERESTARTSYS; 347b61f7dcfSDavid Howells if (down_read_killable(&dvnode->validate_lock) < 0) 348b61f7dcfSDavid Howells goto error; 349f3ddee8dSDavid Howells 350f3ddee8dSDavid Howells if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) 351f3ddee8dSDavid Howells goto success; 352f3ddee8dSDavid Howells 353b61f7dcfSDavid Howells up_read(&dvnode->validate_lock); 354b61f7dcfSDavid Howells if (down_write_killable(&dvnode->validate_lock) < 0) 355b61f7dcfSDavid Howells goto error; 356b61f7dcfSDavid Howells 357b61f7dcfSDavid Howells if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { 35899987c56SDavid Howells trace_afs_reload_dir(dvnode); 359c69bf479SDavid Howells ret = afs_fetch_data(dvnode, req); 360f3ddee8dSDavid Howells if (ret < 0) 361b61f7dcfSDavid Howells goto error_unlock; 362f3ddee8dSDavid Howells 363f3ddee8dSDavid Howells task_io_account_read(PAGE_SIZE * req->nr_pages); 364f3ddee8dSDavid Howells 365c4508464SDavid Howells if (req->len < req->file_size) { 366c4508464SDavid Howells /* The content has grown, so we need to expand the 367c4508464SDavid Howells * buffer. 368c4508464SDavid Howells */ 369c4508464SDavid Howells up_write(&dvnode->validate_lock); 370*9ea4eff4SMarc Dionne remote_size = req->file_size; 371c4508464SDavid Howells goto expand; 372c4508464SDavid Howells } 373f3ddee8dSDavid Howells 374f3ddee8dSDavid Howells /* Validate the data we just read. */ 375c4508464SDavid Howells ret = afs_dir_check(dvnode, req); 376c4508464SDavid Howells if (ret < 0) 377b61f7dcfSDavid Howells goto error_unlock; 378f3ddee8dSDavid Howells 379f3ddee8dSDavid Howells // TODO: Trim excess pages 380f3ddee8dSDavid Howells 381f3ddee8dSDavid Howells set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags); 382f3ddee8dSDavid Howells } 383f3ddee8dSDavid Howells 384b61f7dcfSDavid Howells downgrade_write(&dvnode->validate_lock); 385f3ddee8dSDavid Howells success: 386f3ddee8dSDavid Howells return req; 387f3ddee8dSDavid Howells 388f3ddee8dSDavid Howells error_unlock: 389b61f7dcfSDavid Howells up_write(&dvnode->validate_lock); 390f3ddee8dSDavid Howells error: 391f3ddee8dSDavid Howells afs_put_read(req); 392f3ddee8dSDavid Howells _leave(" = %d", ret); 393f3ddee8dSDavid Howells return ERR_PTR(ret); 394f3ddee8dSDavid Howells } 395f3ddee8dSDavid Howells 396f3ddee8dSDavid Howells /* 3971da177e4SLinus Torvalds * deal with one block in an AFS directory 3981da177e4SLinus Torvalds */ 399f51375cdSDavid Howells static int afs_dir_iterate_block(struct afs_vnode *dvnode, 400f51375cdSDavid Howells struct dir_context *ctx, 40100317636SDavid Howells union afs_xdr_dir_block *block, 4021bbae9f8SAl Viro unsigned blkoff) 4031da177e4SLinus Torvalds { 40400317636SDavid Howells union afs_xdr_dirent *dire; 405366911cdSDavid Howells unsigned offset, next, curr, nr_slots; 4061da177e4SLinus Torvalds size_t nlen; 4071bbae9f8SAl Viro int tmp; 4081da177e4SLinus Torvalds 409255ed636SDavid Howells _enter("%llx,%x", ctx->pos, blkoff); 4101da177e4SLinus Torvalds 41100317636SDavid Howells curr = (ctx->pos - blkoff) / sizeof(union afs_xdr_dirent); 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds /* walk through the block, an entry at a time */ 4144ea219a8SDavid Howells for (offset = (blkoff == 0 ? AFS_DIR_RESV_BLOCKS0 : AFS_DIR_RESV_BLOCKS); 4154ea219a8SDavid Howells offset < AFS_DIR_SLOTS_PER_BLOCK; 4161da177e4SLinus Torvalds offset = next 4171da177e4SLinus Torvalds ) { 4181da177e4SLinus Torvalds /* skip entries marked unused in the bitmap */ 41900317636SDavid Howells if (!(block->hdr.bitmap[offset / 8] & 4201da177e4SLinus Torvalds (1 << (offset % 8)))) { 4215b5e0928SAlexey Dobriyan _debug("ENT[%zu.%u]: unused", 42200317636SDavid Howells blkoff / sizeof(union afs_xdr_dir_block), offset); 423366911cdSDavid Howells next = offset + 1; 4241da177e4SLinus Torvalds if (offset >= curr) 4251bbae9f8SAl Viro ctx->pos = blkoff + 42600317636SDavid Howells next * sizeof(union afs_xdr_dirent); 4271da177e4SLinus Torvalds continue; 4281da177e4SLinus Torvalds } 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds /* got a valid entry */ 4311da177e4SLinus Torvalds dire = &block->dirents[offset]; 4321da177e4SLinus Torvalds nlen = strnlen(dire->u.name, 4331da177e4SLinus Torvalds sizeof(*block) - 43400317636SDavid Howells offset * sizeof(union afs_xdr_dirent)); 435366911cdSDavid Howells if (nlen > AFSNAMEMAX - 1) { 436366911cdSDavid Howells _debug("ENT[%zu]: name too long (len %u/%zu)", 437366911cdSDavid Howells blkoff / sizeof(union afs_xdr_dir_block), 438366911cdSDavid Howells offset, nlen); 439366911cdSDavid Howells return afs_bad(dvnode, afs_file_error_dir_name_too_long); 440366911cdSDavid Howells } 4411da177e4SLinus Torvalds 4425b5e0928SAlexey Dobriyan _debug("ENT[%zu.%u]: %s %zu \"%s\"", 44300317636SDavid Howells blkoff / sizeof(union afs_xdr_dir_block), offset, 4441da177e4SLinus Torvalds (offset < curr ? "skip" : "fill"), 4451da177e4SLinus Torvalds nlen, dire->u.name); 4461da177e4SLinus Torvalds 447366911cdSDavid Howells nr_slots = afs_dir_calc_slots(nlen); 448366911cdSDavid Howells next = offset + nr_slots; 449366911cdSDavid Howells if (next > AFS_DIR_SLOTS_PER_BLOCK) { 4505b5e0928SAlexey Dobriyan _debug("ENT[%zu.%u]:" 451366911cdSDavid Howells " %u extends beyond end dir block" 452366911cdSDavid Howells " (len %zu)", 45300317636SDavid Howells blkoff / sizeof(union afs_xdr_dir_block), 454366911cdSDavid Howells offset, next, nlen); 455f51375cdSDavid Howells return afs_bad(dvnode, afs_file_error_dir_over_end); 4561da177e4SLinus Torvalds } 457366911cdSDavid Howells 458366911cdSDavid Howells /* Check that the name-extension dirents are all allocated */ 459366911cdSDavid Howells for (tmp = 1; tmp < nr_slots; tmp++) { 460366911cdSDavid Howells unsigned int ix = offset + tmp; 461366911cdSDavid Howells if (!(block->hdr.bitmap[ix / 8] & (1 << (ix % 8)))) { 462366911cdSDavid Howells _debug("ENT[%zu.u]:" 463366911cdSDavid Howells " %u unmarked extension (%u/%u)", 46400317636SDavid Howells blkoff / sizeof(union afs_xdr_dir_block), 465366911cdSDavid Howells offset, tmp, nr_slots); 466f51375cdSDavid Howells return afs_bad(dvnode, afs_file_error_dir_unmarked_ext); 4671da177e4SLinus Torvalds } 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds /* skip if starts before the current position */ 47117eabd42SDavid Howells if (offset < curr) { 47217eabd42SDavid Howells if (next > curr) 47317eabd42SDavid Howells ctx->pos = blkoff + next * sizeof(union afs_xdr_dirent); 4741da177e4SLinus Torvalds continue; 47517eabd42SDavid Howells } 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds /* found the next entry */ 4781bbae9f8SAl Viro if (!dir_emit(ctx, dire->u.name, nlen, 4791da177e4SLinus Torvalds ntohl(dire->u.vnode), 4805cf9dd55SDavid Howells (ctx->actor == afs_lookup_filldir || 4815cf9dd55SDavid Howells ctx->actor == afs_lookup_one_filldir)? 4821bbae9f8SAl Viro ntohl(dire->u.unique) : DT_UNKNOWN)) { 4831da177e4SLinus Torvalds _leave(" = 0 [full]"); 4841da177e4SLinus Torvalds return 0; 4851da177e4SLinus Torvalds } 4861da177e4SLinus Torvalds 48700317636SDavid Howells ctx->pos = blkoff + next * sizeof(union afs_xdr_dirent); 4881da177e4SLinus Torvalds } 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds _leave(" = 1 [more]"); 4911da177e4SLinus Torvalds return 1; 492ec26815aSDavid Howells } 4931da177e4SLinus Torvalds 4941da177e4SLinus Torvalds /* 49508e0e7c8SDavid Howells * iterate through the data blob that lists the contents of an AFS directory 4961da177e4SLinus Torvalds */ 4971bbae9f8SAl Viro static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, 4989dd0b82eSDavid Howells struct key *key, afs_dataversion_t *_dir_version) 4991da177e4SLinus Torvalds { 500f3ddee8dSDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir); 50100317636SDavid Howells union afs_xdr_dir_block *dblock; 502f3ddee8dSDavid Howells struct afs_read *req; 503255ed636SDavid Howells struct folio *folio; 504255ed636SDavid Howells unsigned offset, size; 5051da177e4SLinus Torvalds int ret; 5061da177e4SLinus Torvalds 5071bbae9f8SAl Viro _enter("{%lu},%u,,", dir->i_ino, (unsigned)ctx->pos); 5081da177e4SLinus Torvalds 50908e0e7c8SDavid Howells if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) { 5101da177e4SLinus Torvalds _leave(" = -ESTALE"); 5111da177e4SLinus Torvalds return -ESTALE; 5121da177e4SLinus Torvalds } 5131da177e4SLinus Torvalds 514f3ddee8dSDavid Howells req = afs_read_dir(dvnode, key); 515f3ddee8dSDavid Howells if (IS_ERR(req)) 516f3ddee8dSDavid Howells return PTR_ERR(req); 5179dd0b82eSDavid Howells *_dir_version = req->data_version; 518f3ddee8dSDavid Howells 5191da177e4SLinus Torvalds /* round the file position up to the next entry boundary */ 52000317636SDavid Howells ctx->pos += sizeof(union afs_xdr_dirent) - 1; 52100317636SDavid Howells ctx->pos &= ~(sizeof(union afs_xdr_dirent) - 1); 5221da177e4SLinus Torvalds 5231da177e4SLinus Torvalds /* walk through the blocks in sequence */ 5241da177e4SLinus Torvalds ret = 0; 525f3ddee8dSDavid Howells while (ctx->pos < req->actual_len) { 526255ed636SDavid Howells /* Fetch the appropriate folio from the directory and re-add it 527c4508464SDavid Howells * to the LRU. We have all the pages pinned with an extra ref. 528f3ddee8dSDavid Howells */ 529255ed636SDavid Howells folio = __filemap_get_folio(dir->i_mapping, ctx->pos / PAGE_SIZE, 530255ed636SDavid Howells FGP_ACCESSED, 0); 53166dabbb6SChristoph Hellwig if (IS_ERR(folio)) { 532f51375cdSDavid Howells ret = afs_bad(dvnode, afs_file_error_dir_missing_page); 5331da177e4SLinus Torvalds break; 5341da177e4SLinus Torvalds } 5351da177e4SLinus Torvalds 536255ed636SDavid Howells offset = round_down(ctx->pos, sizeof(*dblock)) - folio_file_pos(folio); 537255ed636SDavid Howells size = min_t(loff_t, folio_size(folio), 538255ed636SDavid Howells req->actual_len - folio_file_pos(folio)); 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds do { 541255ed636SDavid Howells dblock = kmap_local_folio(folio, offset); 542255ed636SDavid Howells ret = afs_dir_iterate_block(dvnode, ctx, dblock, 543255ed636SDavid Howells folio_file_pos(folio) + offset); 544255ed636SDavid Howells kunmap_local(dblock); 545255ed636SDavid Howells if (ret != 1) 5461da177e4SLinus Torvalds goto out; 5471da177e4SLinus Torvalds 548255ed636SDavid Howells } while (offset += sizeof(*dblock), offset < size); 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds ret = 0; 5511da177e4SLinus Torvalds } 5521da177e4SLinus Torvalds 5531da177e4SLinus Torvalds out: 554b61f7dcfSDavid Howells up_read(&dvnode->validate_lock); 555f3ddee8dSDavid Howells afs_put_read(req); 5561da177e4SLinus Torvalds _leave(" = %d", ret); 5571da177e4SLinus Torvalds return ret; 558ec26815aSDavid Howells } 5591da177e4SLinus Torvalds 5601da177e4SLinus Torvalds /* 5611da177e4SLinus Torvalds * read an AFS directory 5621da177e4SLinus Torvalds */ 5631bbae9f8SAl Viro static int afs_readdir(struct file *file, struct dir_context *ctx) 5641da177e4SLinus Torvalds { 5659dd0b82eSDavid Howells afs_dataversion_t dir_version; 5669dd0b82eSDavid Howells 5679dd0b82eSDavid Howells return afs_dir_iterate(file_inode(file), ctx, afs_file_key(file), 5689dd0b82eSDavid Howells &dir_version); 569ec26815aSDavid Howells } 5701da177e4SLinus Torvalds 5711da177e4SLinus Torvalds /* 5725cf9dd55SDavid Howells * Search the directory for a single name 5731da177e4SLinus Torvalds * - if afs_dir_iterate_block() spots this function, it'll pass the FID 5741da177e4SLinus Torvalds * uniquifier through dtype 5751da177e4SLinus Torvalds */ 57625885a35SAl Viro static bool afs_lookup_one_filldir(struct dir_context *ctx, const char *name, 577ac7576f4SMiklos Szeredi int nlen, loff_t fpos, u64 ino, unsigned dtype) 5781da177e4SLinus Torvalds { 5795cf9dd55SDavid Howells struct afs_lookup_one_cookie *cookie = 5805cf9dd55SDavid Howells container_of(ctx, struct afs_lookup_one_cookie, ctx); 5811da177e4SLinus Torvalds 5821bbae9f8SAl Viro _enter("{%s,%u},%s,%u,,%llu,%u", 5831bbae9f8SAl Viro cookie->name.name, cookie->name.len, name, nlen, 584ba3e0e1aSDavid S. Miller (unsigned long long) ino, dtype); 5851da177e4SLinus Torvalds 58608e0e7c8SDavid Howells /* insanity checks first */ 58700317636SDavid Howells BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); 58800317636SDavid Howells BUILD_BUG_ON(sizeof(union afs_xdr_dirent) != 32); 58908e0e7c8SDavid Howells 5901bbae9f8SAl Viro if (cookie->name.len != nlen || 5911bbae9f8SAl Viro memcmp(cookie->name.name, name, nlen) != 0) { 59225885a35SAl Viro _leave(" = true [keep looking]"); 59325885a35SAl Viro return true; 5941da177e4SLinus Torvalds } 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds cookie->fid.vnode = ino; 5971da177e4SLinus Torvalds cookie->fid.unique = dtype; 5981da177e4SLinus Torvalds cookie->found = 1; 5991da177e4SLinus Torvalds 60025885a35SAl Viro _leave(" = false [found]"); 60125885a35SAl Viro return false; 602ec26815aSDavid Howells } 6031da177e4SLinus Torvalds 6041da177e4SLinus Torvalds /* 6055cf9dd55SDavid Howells * Do a lookup of a single name in a directory 606260a9803SDavid Howells * - just returns the FID the dentry name maps to if found 6071da177e4SLinus Torvalds */ 6085cf9dd55SDavid Howells static int afs_do_lookup_one(struct inode *dir, struct dentry *dentry, 6099dd0b82eSDavid Howells struct afs_fid *fid, struct key *key, 6109dd0b82eSDavid Howells afs_dataversion_t *_dir_version) 6111da177e4SLinus Torvalds { 6121bbae9f8SAl Viro struct afs_super_info *as = dir->i_sb->s_fs_info; 6135cf9dd55SDavid Howells struct afs_lookup_one_cookie cookie = { 6145cf9dd55SDavid Howells .ctx.actor = afs_lookup_one_filldir, 6151bbae9f8SAl Viro .name = dentry->d_name, 6161bbae9f8SAl Viro .fid.vid = as->volume->vid 6171bbae9f8SAl Viro }; 6181da177e4SLinus Torvalds int ret; 6191da177e4SLinus Torvalds 620a455589fSAl Viro _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry); 6211da177e4SLinus Torvalds 6221da177e4SLinus Torvalds /* search the directory */ 6239dd0b82eSDavid Howells ret = afs_dir_iterate(dir, &cookie.ctx, key, _dir_version); 6241da177e4SLinus Torvalds if (ret < 0) { 62508e0e7c8SDavid Howells _leave(" = %d [iter]", ret); 62608e0e7c8SDavid Howells return ret; 6271da177e4SLinus Torvalds } 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds if (!cookie.found) { 63008e0e7c8SDavid Howells _leave(" = -ENOENT [not found]"); 63108e0e7c8SDavid Howells return -ENOENT; 63208e0e7c8SDavid Howells } 63308e0e7c8SDavid Howells 63408e0e7c8SDavid Howells *fid = cookie.fid; 6353b6492dfSDavid Howells _leave(" = 0 { vn=%llu u=%u }", fid->vnode, fid->unique); 63608e0e7c8SDavid Howells return 0; 63708e0e7c8SDavid Howells } 63808e0e7c8SDavid Howells 63908e0e7c8SDavid Howells /* 6405cf9dd55SDavid Howells * search the directory for a name 6415cf9dd55SDavid Howells * - if afs_dir_iterate_block() spots this function, it'll pass the FID 6425cf9dd55SDavid Howells * uniquifier through dtype 6435cf9dd55SDavid Howells */ 64425885a35SAl Viro static bool afs_lookup_filldir(struct dir_context *ctx, const char *name, 6455cf9dd55SDavid Howells int nlen, loff_t fpos, u64 ino, unsigned dtype) 6465cf9dd55SDavid Howells { 6475cf9dd55SDavid Howells struct afs_lookup_cookie *cookie = 6485cf9dd55SDavid Howells container_of(ctx, struct afs_lookup_cookie, ctx); 6495cf9dd55SDavid Howells 6505cf9dd55SDavid Howells _enter("{%s,%u},%s,%u,,%llu,%u", 6515cf9dd55SDavid Howells cookie->name.name, cookie->name.len, name, nlen, 6525cf9dd55SDavid Howells (unsigned long long) ino, dtype); 6535cf9dd55SDavid Howells 6545cf9dd55SDavid Howells /* insanity checks first */ 65500317636SDavid Howells BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); 65600317636SDavid Howells BUILD_BUG_ON(sizeof(union afs_xdr_dirent) != 32); 6575cf9dd55SDavid Howells 6585cf9dd55SDavid Howells if (cookie->found) { 6595cf9dd55SDavid Howells if (cookie->nr_fids < 50) { 6605cf9dd55SDavid Howells cookie->fids[cookie->nr_fids].vnode = ino; 6615cf9dd55SDavid Howells cookie->fids[cookie->nr_fids].unique = dtype; 6625cf9dd55SDavid Howells cookie->nr_fids++; 6635cf9dd55SDavid Howells } 6645cf9dd55SDavid Howells } else if (cookie->name.len == nlen && 6655cf9dd55SDavid Howells memcmp(cookie->name.name, name, nlen) == 0) { 666e49c7b2fSDavid Howells cookie->fids[1].vnode = ino; 667e49c7b2fSDavid Howells cookie->fids[1].unique = dtype; 6685cf9dd55SDavid Howells cookie->found = 1; 6695cf9dd55SDavid Howells if (cookie->one_only) 67025885a35SAl Viro return false; 6715cf9dd55SDavid Howells } 6725cf9dd55SDavid Howells 67325885a35SAl Viro return cookie->nr_fids < 50; 6745cf9dd55SDavid Howells } 6755cf9dd55SDavid Howells 6765cf9dd55SDavid Howells /* 677e49c7b2fSDavid Howells * Deal with the result of a successful lookup operation. Turn all the files 678e49c7b2fSDavid Howells * into inodes and save the first one - which is the one we actually want. 679e49c7b2fSDavid Howells */ 680e49c7b2fSDavid Howells static void afs_do_lookup_success(struct afs_operation *op) 681e49c7b2fSDavid Howells { 682e49c7b2fSDavid Howells struct afs_vnode_param *vp; 683e49c7b2fSDavid Howells struct afs_vnode *vnode; 684e49c7b2fSDavid Howells struct inode *inode; 685e49c7b2fSDavid Howells u32 abort_code; 686e49c7b2fSDavid Howells int i; 687e49c7b2fSDavid Howells 688e49c7b2fSDavid Howells _enter(""); 689e49c7b2fSDavid Howells 690e49c7b2fSDavid Howells for (i = 0; i < op->nr_files; i++) { 691e49c7b2fSDavid Howells switch (i) { 692e49c7b2fSDavid Howells case 0: 693e49c7b2fSDavid Howells vp = &op->file[0]; 694e49c7b2fSDavid Howells abort_code = vp->scb.status.abort_code; 695e49c7b2fSDavid Howells if (abort_code != 0) { 69644767c35SDavid Howells op->ac.abort_code = abort_code; 697e49c7b2fSDavid Howells op->error = afs_abort_to_error(abort_code); 698e49c7b2fSDavid Howells } 699e49c7b2fSDavid Howells break; 700e49c7b2fSDavid Howells 701e49c7b2fSDavid Howells case 1: 702e49c7b2fSDavid Howells vp = &op->file[1]; 703e49c7b2fSDavid Howells break; 704e49c7b2fSDavid Howells 705e49c7b2fSDavid Howells default: 706e49c7b2fSDavid Howells vp = &op->more_files[i - 2]; 707e49c7b2fSDavid Howells break; 708e49c7b2fSDavid Howells } 709e49c7b2fSDavid Howells 710e49c7b2fSDavid Howells if (!vp->scb.have_status && !vp->scb.have_error) 711e49c7b2fSDavid Howells continue; 712e49c7b2fSDavid Howells 713e49c7b2fSDavid Howells _debug("do [%u]", i); 714e49c7b2fSDavid Howells if (vp->vnode) { 715e49c7b2fSDavid Howells if (!test_bit(AFS_VNODE_UNSET, &vp->vnode->flags)) 716e49c7b2fSDavid Howells afs_vnode_commit_status(op, vp); 717e49c7b2fSDavid Howells } else if (vp->scb.status.abort_code == 0) { 718e49c7b2fSDavid Howells inode = afs_iget(op, vp); 719e49c7b2fSDavid Howells if (!IS_ERR(inode)) { 720e49c7b2fSDavid Howells vnode = AFS_FS_I(inode); 721e49c7b2fSDavid Howells afs_cache_permit(vnode, op->key, 722e49c7b2fSDavid Howells 0 /* Assume vnode->cb_break is 0 */ + 723e49c7b2fSDavid Howells op->cb_v_break, 724e49c7b2fSDavid Howells &vp->scb); 725e49c7b2fSDavid Howells vp->vnode = vnode; 726e49c7b2fSDavid Howells vp->put_vnode = true; 727e49c7b2fSDavid Howells } 728e49c7b2fSDavid Howells } else { 729e49c7b2fSDavid Howells _debug("- abort %d %llx:%llx.%x", 730e49c7b2fSDavid Howells vp->scb.status.abort_code, 731e49c7b2fSDavid Howells vp->fid.vid, vp->fid.vnode, vp->fid.unique); 732e49c7b2fSDavid Howells } 733e49c7b2fSDavid Howells } 734e49c7b2fSDavid Howells 735e49c7b2fSDavid Howells _leave(""); 736e49c7b2fSDavid Howells } 737e49c7b2fSDavid Howells 738e49c7b2fSDavid Howells static const struct afs_operation_ops afs_inline_bulk_status_operation = { 739e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_inline_bulk_status, 740e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_inline_bulk_status, 741e49c7b2fSDavid Howells .success = afs_do_lookup_success, 742e49c7b2fSDavid Howells }; 743e49c7b2fSDavid Howells 744b6489a49SDavid Howells static const struct afs_operation_ops afs_lookup_fetch_status_operation = { 745e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_fetch_status, 746e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_fetch_status, 747e49c7b2fSDavid Howells .success = afs_do_lookup_success, 748728279a5SDavid Howells .aborted = afs_check_for_remote_deletion, 749e49c7b2fSDavid Howells }; 750e49c7b2fSDavid Howells 751e49c7b2fSDavid Howells /* 75220325960SDavid Howells * See if we know that the server we expect to use doesn't support 75320325960SDavid Howells * FS.InlineBulkStatus. 75420325960SDavid Howells */ 75520325960SDavid Howells static bool afs_server_supports_ibulk(struct afs_vnode *dvnode) 75620325960SDavid Howells { 75720325960SDavid Howells struct afs_server_list *slist; 75820325960SDavid Howells struct afs_volume *volume = dvnode->volume; 75920325960SDavid Howells struct afs_server *server; 76020325960SDavid Howells bool ret = true; 76120325960SDavid Howells int i; 76220325960SDavid Howells 76320325960SDavid Howells if (!test_bit(AFS_VOLUME_MAYBE_NO_IBULK, &volume->flags)) 76420325960SDavid Howells return true; 76520325960SDavid Howells 76620325960SDavid Howells rcu_read_lock(); 76720325960SDavid Howells slist = rcu_dereference(volume->servers); 76820325960SDavid Howells 76920325960SDavid Howells for (i = 0; i < slist->nr_servers; i++) { 77020325960SDavid Howells server = slist->servers[i].server; 77120325960SDavid Howells if (server == dvnode->cb_server) { 77220325960SDavid Howells if (test_bit(AFS_SERVER_FL_NO_IBULK, &server->flags)) 77320325960SDavid Howells ret = false; 77420325960SDavid Howells break; 77520325960SDavid Howells } 77620325960SDavid Howells } 77720325960SDavid Howells 77820325960SDavid Howells rcu_read_unlock(); 77920325960SDavid Howells return ret; 78020325960SDavid Howells } 78120325960SDavid Howells 78220325960SDavid Howells /* 7835cf9dd55SDavid Howells * Do a lookup in a directory. We make use of bulk lookup to query a slew of 7845cf9dd55SDavid Howells * files in one go and create inodes for them. The inode of the file we were 7855cf9dd55SDavid Howells * asked for is returned. 7865cf9dd55SDavid Howells */ 7875cf9dd55SDavid Howells static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, 7885cf9dd55SDavid Howells struct key *key) 7895cf9dd55SDavid Howells { 7905cf9dd55SDavid Howells struct afs_lookup_cookie *cookie; 791e49c7b2fSDavid Howells struct afs_vnode_param *vp; 792e49c7b2fSDavid Howells struct afs_operation *op; 79339db9815SDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode; 79439db9815SDavid Howells struct inode *inode = NULL, *ti; 7959dd0b82eSDavid Howells afs_dataversion_t data_version = READ_ONCE(dvnode->status.data_version); 796e49c7b2fSDavid Howells long ret; 797e49c7b2fSDavid Howells int i; 7985cf9dd55SDavid Howells 7995cf9dd55SDavid Howells _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry); 8005cf9dd55SDavid Howells 8015cf9dd55SDavid Howells cookie = kzalloc(sizeof(struct afs_lookup_cookie), GFP_KERNEL); 8025cf9dd55SDavid Howells if (!cookie) 8035cf9dd55SDavid Howells return ERR_PTR(-ENOMEM); 8045cf9dd55SDavid Howells 805e49c7b2fSDavid Howells for (i = 0; i < ARRAY_SIZE(cookie->fids); i++) 806e49c7b2fSDavid Howells cookie->fids[i].vid = dvnode->fid.vid; 8075cf9dd55SDavid Howells cookie->ctx.actor = afs_lookup_filldir; 8085cf9dd55SDavid Howells cookie->name = dentry->d_name; 80913fcc635SDavid Howells cookie->nr_fids = 2; /* slot 0 is saved for the fid we actually want 81013fcc635SDavid Howells * and slot 1 for the directory */ 8115cf9dd55SDavid Howells 81220325960SDavid Howells if (!afs_server_supports_ibulk(dvnode)) 8135cf9dd55SDavid Howells cookie->one_only = true; 8145cf9dd55SDavid Howells 8155cf9dd55SDavid Howells /* search the directory */ 8169dd0b82eSDavid Howells ret = afs_dir_iterate(dir, &cookie->ctx, key, &data_version); 817e49c7b2fSDavid Howells if (ret < 0) 8185cf9dd55SDavid Howells goto out; 8195cf9dd55SDavid Howells 8209dd0b82eSDavid Howells dentry->d_fsdata = (void *)(unsigned long)data_version; 8219dd0b82eSDavid Howells 822e49c7b2fSDavid Howells ret = -ENOENT; 8235cf9dd55SDavid Howells if (!cookie->found) 8245cf9dd55SDavid Howells goto out; 8255cf9dd55SDavid Howells 8265cf9dd55SDavid Howells /* Check to see if we already have an inode for the primary fid. */ 827e49c7b2fSDavid Howells inode = ilookup5(dir->i_sb, cookie->fids[1].vnode, 828e49c7b2fSDavid Howells afs_ilookup5_test_by_fid, &cookie->fids[1]); 8295cf9dd55SDavid Howells if (inode) 830e49c7b2fSDavid Howells goto out; /* We do */ 831e49c7b2fSDavid Howells 832e49c7b2fSDavid Howells /* Okay, we didn't find it. We need to query the server - and whilst 833e49c7b2fSDavid Howells * we're doing that, we're going to attempt to look up a bunch of other 834e49c7b2fSDavid Howells * vnodes also. 835e49c7b2fSDavid Howells */ 836e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, dvnode->volume); 837e49c7b2fSDavid Howells if (IS_ERR(op)) { 838e49c7b2fSDavid Howells ret = PTR_ERR(op); 8395cf9dd55SDavid Howells goto out; 840e49c7b2fSDavid Howells } 841e49c7b2fSDavid Howells 842e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, dvnode); 843e49c7b2fSDavid Howells afs_op_set_fid(op, 1, &cookie->fids[1]); 844e49c7b2fSDavid Howells 845e49c7b2fSDavid Howells op->nr_files = cookie->nr_fids; 846e49c7b2fSDavid Howells _debug("nr_files %u", op->nr_files); 8475cf9dd55SDavid Howells 8485cf9dd55SDavid Howells /* Need space for examining all the selected files */ 849e49c7b2fSDavid Howells op->error = -ENOMEM; 850e49c7b2fSDavid Howells if (op->nr_files > 2) { 851e49c7b2fSDavid Howells op->more_files = kvcalloc(op->nr_files - 2, 852e49c7b2fSDavid Howells sizeof(struct afs_vnode_param), 8535cf9dd55SDavid Howells GFP_KERNEL); 854e49c7b2fSDavid Howells if (!op->more_files) 855e49c7b2fSDavid Howells goto out_op; 8565cf9dd55SDavid Howells 857e49c7b2fSDavid Howells for (i = 2; i < op->nr_files; i++) { 858e49c7b2fSDavid Howells vp = &op->more_files[i - 2]; 859e49c7b2fSDavid Howells vp->fid = cookie->fids[i]; 86039db9815SDavid Howells 86139db9815SDavid Howells /* Find any inodes that already exist and get their 86239db9815SDavid Howells * callback counters. 86339db9815SDavid Howells */ 864e49c7b2fSDavid Howells ti = ilookup5_nowait(dir->i_sb, vp->fid.vnode, 865e49c7b2fSDavid Howells afs_ilookup5_test_by_fid, &vp->fid); 86639db9815SDavid Howells if (!IS_ERR_OR_NULL(ti)) { 86739db9815SDavid Howells vnode = AFS_FS_I(ti); 868e49c7b2fSDavid Howells vp->dv_before = vnode->status.data_version; 869e49c7b2fSDavid Howells vp->cb_break_before = afs_calc_vnode_cb_break(vnode); 870e49c7b2fSDavid Howells vp->vnode = vnode; 871e49c7b2fSDavid Howells vp->put_vnode = true; 872a9e5c87cSDavid Howells vp->speculative = true; /* vnode not locked */ 873e49c7b2fSDavid Howells } 87439db9815SDavid Howells } 87539db9815SDavid Howells } 87639db9815SDavid Howells 8775cf9dd55SDavid Howells /* Try FS.InlineBulkStatus first. Abort codes for the individual 8785cf9dd55SDavid Howells * lookups contained therein are stored in the reply without aborting 8795cf9dd55SDavid Howells * the whole operation. 8805cf9dd55SDavid Howells */ 881e49c7b2fSDavid Howells op->error = -ENOTSUPP; 882e49c7b2fSDavid Howells if (!cookie->one_only) { 883e49c7b2fSDavid Howells op->ops = &afs_inline_bulk_status_operation; 884e49c7b2fSDavid Howells afs_begin_vnode_operation(op); 885e49c7b2fSDavid Howells afs_wait_for_operation(op); 8865cf9dd55SDavid Howells } 8875cf9dd55SDavid Howells 888e49c7b2fSDavid Howells if (op->error == -ENOTSUPP) { 889e49c7b2fSDavid Howells /* We could try FS.BulkStatus next, but this aborts the entire 890e49c7b2fSDavid Howells * op if any of the lookups fails - so, for the moment, revert 891e49c7b2fSDavid Howells * to FS.FetchStatus for op->file[1]. 8925cf9dd55SDavid Howells */ 893e49c7b2fSDavid Howells op->fetch_status.which = 1; 894f8ea5c7bSDavid Howells op->ops = &afs_lookup_fetch_status_operation; 895e49c7b2fSDavid Howells afs_begin_vnode_operation(op); 896e49c7b2fSDavid Howells afs_wait_for_operation(op); 897e49c7b2fSDavid Howells } 898e49c7b2fSDavid Howells inode = ERR_PTR(op->error); 899e49c7b2fSDavid Howells 900e49c7b2fSDavid Howells out_op: 901e49c7b2fSDavid Howells if (op->error == 0) { 902874c8ca1SDavid Howells inode = &op->file[1].vnode->netfs.inode; 903e49c7b2fSDavid Howells op->file[1].vnode = NULL; 9045cf9dd55SDavid Howells } 9055cf9dd55SDavid Howells 906e49c7b2fSDavid Howells if (op->file[0].scb.have_status) 907e49c7b2fSDavid Howells dentry->d_fsdata = (void *)(unsigned long)op->file[0].scb.status.data_version; 908e49c7b2fSDavid Howells else 909e49c7b2fSDavid Howells dentry->d_fsdata = (void *)(unsigned long)op->file[0].dv_before; 910e49c7b2fSDavid Howells ret = afs_put_operation(op); 9115cf9dd55SDavid Howells out: 9125cf9dd55SDavid Howells kfree(cookie); 913e49c7b2fSDavid Howells _leave(""); 914e49c7b2fSDavid Howells return inode ?: ERR_PTR(ret); 9155cf9dd55SDavid Howells } 9165cf9dd55SDavid Howells 9175cf9dd55SDavid Howells /* 9186f8880d8SDavid Howells * Look up an entry in a directory with @sys substitution. 9196f8880d8SDavid Howells */ 9206f8880d8SDavid Howells static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry, 9216f8880d8SDavid Howells struct key *key) 9226f8880d8SDavid Howells { 9236f8880d8SDavid Howells struct afs_sysnames *subs; 9246f8880d8SDavid Howells struct afs_net *net = afs_i2net(dir); 9256f8880d8SDavid Howells struct dentry *ret; 9266f8880d8SDavid Howells char *buf, *p, *name; 9276f8880d8SDavid Howells int len, i; 9286f8880d8SDavid Howells 9296f8880d8SDavid Howells _enter(""); 9306f8880d8SDavid Howells 9316f8880d8SDavid Howells ret = ERR_PTR(-ENOMEM); 9326f8880d8SDavid Howells p = buf = kmalloc(AFSNAMEMAX, GFP_KERNEL); 9336f8880d8SDavid Howells if (!buf) 9346f8880d8SDavid Howells goto out_p; 9356f8880d8SDavid Howells if (dentry->d_name.len > 4) { 9366f8880d8SDavid Howells memcpy(p, dentry->d_name.name, dentry->d_name.len - 4); 9376f8880d8SDavid Howells p += dentry->d_name.len - 4; 9386f8880d8SDavid Howells } 9396f8880d8SDavid Howells 9406f8880d8SDavid Howells /* There is an ordered list of substitutes that we have to try. */ 9416f8880d8SDavid Howells read_lock(&net->sysnames_lock); 9426f8880d8SDavid Howells subs = net->sysnames; 9436f8880d8SDavid Howells refcount_inc(&subs->usage); 9446f8880d8SDavid Howells read_unlock(&net->sysnames_lock); 9456f8880d8SDavid Howells 9466f8880d8SDavid Howells for (i = 0; i < subs->nr; i++) { 9476f8880d8SDavid Howells name = subs->subs[i]; 9486f8880d8SDavid Howells len = dentry->d_name.len - 4 + strlen(name); 9496f8880d8SDavid Howells if (len >= AFSNAMEMAX) { 9506f8880d8SDavid Howells ret = ERR_PTR(-ENAMETOOLONG); 9516f8880d8SDavid Howells goto out_s; 9526f8880d8SDavid Howells } 9536f8880d8SDavid Howells 9546f8880d8SDavid Howells strcpy(p, name); 9556f8880d8SDavid Howells ret = lookup_one_len(buf, dentry->d_parent, len); 9566f8880d8SDavid Howells if (IS_ERR(ret) || d_is_positive(ret)) 9576f8880d8SDavid Howells goto out_s; 9586f8880d8SDavid Howells dput(ret); 9596f8880d8SDavid Howells } 9606f8880d8SDavid Howells 9616f8880d8SDavid Howells /* We don't want to d_add() the @sys dentry here as we don't want to 9626f8880d8SDavid Howells * the cached dentry to hide changes to the sysnames list. 9636f8880d8SDavid Howells */ 9646f8880d8SDavid Howells ret = NULL; 9656f8880d8SDavid Howells out_s: 9666f8880d8SDavid Howells afs_put_sysnames(subs); 9676f8880d8SDavid Howells kfree(buf); 9686f8880d8SDavid Howells out_p: 9696f8880d8SDavid Howells key_put(key); 9706f8880d8SDavid Howells return ret; 9716f8880d8SDavid Howells } 9726f8880d8SDavid Howells 9736f8880d8SDavid Howells /* 97408e0e7c8SDavid Howells * look up an entry in a directory 97508e0e7c8SDavid Howells */ 976260a9803SDavid Howells static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, 97700cd8dd3SAl Viro unsigned int flags) 97808e0e7c8SDavid Howells { 9795cf9dd55SDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir); 98040a708bdSDavid Howells struct afs_fid fid = {}; 98108e0e7c8SDavid Howells struct inode *inode; 98234b2a88fSAl Viro struct dentry *d; 98300d3b7a4SDavid Howells struct key *key; 98408e0e7c8SDavid Howells int ret; 98508e0e7c8SDavid Howells 9863b6492dfSDavid Howells _enter("{%llx:%llu},%p{%pd},", 9875cf9dd55SDavid Howells dvnode->fid.vid, dvnode->fid.vnode, dentry, dentry); 988260a9803SDavid Howells 9892b0143b5SDavid Howells ASSERTCMP(d_inode(dentry), ==, NULL); 99008e0e7c8SDavid Howells 99145222b9eSDavid Howells if (dentry->d_name.len >= AFSNAMEMAX) { 99208e0e7c8SDavid Howells _leave(" = -ENAMETOOLONG"); 99308e0e7c8SDavid Howells return ERR_PTR(-ENAMETOOLONG); 99408e0e7c8SDavid Howells } 99508e0e7c8SDavid Howells 9965cf9dd55SDavid Howells if (test_bit(AFS_VNODE_DELETED, &dvnode->flags)) { 99708e0e7c8SDavid Howells _leave(" = -ESTALE"); 99808e0e7c8SDavid Howells return ERR_PTR(-ESTALE); 99908e0e7c8SDavid Howells } 100008e0e7c8SDavid Howells 10015cf9dd55SDavid Howells key = afs_request_key(dvnode->volume->cell); 100200d3b7a4SDavid Howells if (IS_ERR(key)) { 100300d3b7a4SDavid Howells _leave(" = %ld [key]", PTR_ERR(key)); 1004e231c2eeSDavid Howells return ERR_CAST(key); 100500d3b7a4SDavid Howells } 100600d3b7a4SDavid Howells 10075cf9dd55SDavid Howells ret = afs_validate(dvnode, key); 100808e0e7c8SDavid Howells if (ret < 0) { 100900d3b7a4SDavid Howells key_put(key); 1010260a9803SDavid Howells _leave(" = %d [val]", ret); 10111da177e4SLinus Torvalds return ERR_PTR(ret); 10121da177e4SLinus Torvalds } 10131da177e4SLinus Torvalds 10146f8880d8SDavid Howells if (dentry->d_name.len >= 4 && 10156f8880d8SDavid Howells dentry->d_name.name[dentry->d_name.len - 4] == '@' && 10166f8880d8SDavid Howells dentry->d_name.name[dentry->d_name.len - 3] == 's' && 10176f8880d8SDavid Howells dentry->d_name.name[dentry->d_name.len - 2] == 'y' && 10186f8880d8SDavid Howells dentry->d_name.name[dentry->d_name.len - 1] == 's') 10196f8880d8SDavid Howells return afs_lookup_atsys(dir, dentry, key); 10206f8880d8SDavid Howells 1021d55b4da4SDavid Howells afs_stat_v(dvnode, n_lookup); 10225cf9dd55SDavid Howells inode = afs_do_lookup(dir, dentry, key); 102334b2a88fSAl Viro key_put(key); 1024f52b83b0SDavid Howells if (inode == ERR_PTR(-ENOENT)) 10255cf9dd55SDavid Howells inode = afs_try_auto_mntpt(dentry, dir); 102640a708bdSDavid Howells 102740a708bdSDavid Howells if (!IS_ERR_OR_NULL(inode)) 102840a708bdSDavid Howells fid = AFS_FS_I(inode)->fid; 102940a708bdSDavid Howells 1030fed79fd7SDavid Howells _debug("splice %p", dentry->d_inode); 103134b2a88fSAl Viro d = d_splice_alias(inode, dentry); 103280548b03SDavid Howells if (!IS_ERR_OR_NULL(d)) { 103334b2a88fSAl Viro d->d_fsdata = dentry->d_fsdata; 103440a708bdSDavid Howells trace_afs_lookup(dvnode, &d->d_name, &fid); 103580548b03SDavid Howells } else { 103640a708bdSDavid Howells trace_afs_lookup(dvnode, &dentry->d_name, &fid); 103780548b03SDavid Howells } 1038e49c7b2fSDavid Howells _leave(""); 103934b2a88fSAl Viro return d; 1040ec26815aSDavid Howells } 10411da177e4SLinus Torvalds 10421da177e4SLinus Torvalds /* 1043a0753c29SDavid Howells * Check the validity of a dentry under RCU conditions. 1044a0753c29SDavid Howells */ 1045a0753c29SDavid Howells static int afs_d_revalidate_rcu(struct dentry *dentry) 1046a0753c29SDavid Howells { 104763d49d84SDavid Howells struct afs_vnode *dvnode; 1048a0753c29SDavid Howells struct dentry *parent; 104963d49d84SDavid Howells struct inode *dir; 1050a0753c29SDavid Howells long dir_version, de_version; 1051a0753c29SDavid Howells 1052a0753c29SDavid Howells _enter("%p", dentry); 1053a0753c29SDavid Howells 1054a0753c29SDavid Howells /* Check the parent directory is still valid first. */ 1055a0753c29SDavid Howells parent = READ_ONCE(dentry->d_parent); 1056a0753c29SDavid Howells dir = d_inode_rcu(parent); 1057a0753c29SDavid Howells if (!dir) 1058a0753c29SDavid Howells return -ECHILD; 1059a0753c29SDavid Howells dvnode = AFS_FS_I(dir); 1060a0753c29SDavid Howells if (test_bit(AFS_VNODE_DELETED, &dvnode->flags)) 1061a0753c29SDavid Howells return -ECHILD; 1062a0753c29SDavid Howells 1063a0753c29SDavid Howells if (!afs_check_validity(dvnode)) 1064a0753c29SDavid Howells return -ECHILD; 1065a0753c29SDavid Howells 1066a0753c29SDavid Howells /* We only need to invalidate a dentry if the server's copy changed 1067a0753c29SDavid Howells * behind our back. If we made the change, it's no problem. Note that 1068a0753c29SDavid Howells * on a 32-bit system, we only have 32 bits in the dentry to store the 1069a0753c29SDavid Howells * version. 1070a0753c29SDavid Howells */ 1071a0753c29SDavid Howells dir_version = (long)READ_ONCE(dvnode->status.data_version); 1072a0753c29SDavid Howells de_version = (long)READ_ONCE(dentry->d_fsdata); 1073a0753c29SDavid Howells if (de_version != dir_version) { 1074a0753c29SDavid Howells dir_version = (long)READ_ONCE(dvnode->invalid_before); 1075a0753c29SDavid Howells if (de_version - dir_version < 0) 1076a0753c29SDavid Howells return -ECHILD; 1077a0753c29SDavid Howells } 1078a0753c29SDavid Howells 1079a0753c29SDavid Howells return 1; /* Still valid */ 1080a0753c29SDavid Howells } 1081a0753c29SDavid Howells 1082a0753c29SDavid Howells /* 10831da177e4SLinus Torvalds * check that a dentry lookup hit has found a valid entry 10841da177e4SLinus Torvalds * - NOTE! the hit can be a negative hit too, so we can't assume we have an 10851da177e4SLinus Torvalds * inode 10861da177e4SLinus Torvalds */ 10870b728e19SAl Viro static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) 10881da177e4SLinus Torvalds { 1089260a9803SDavid Howells struct afs_vnode *vnode, *dir; 10903f649ab7SKees Cook struct afs_fid fid; 10911da177e4SLinus Torvalds struct dentry *parent; 1092c435ee34SDavid Howells struct inode *inode; 109300d3b7a4SDavid Howells struct key *key; 109440fc8102SDavid Howells afs_dataversion_t dir_version, invalid_before; 10959dd0b82eSDavid Howells long de_version; 10961da177e4SLinus Torvalds int ret; 10971da177e4SLinus Torvalds 10980b728e19SAl Viro if (flags & LOOKUP_RCU) 1099a0753c29SDavid Howells return afs_d_revalidate_rcu(dentry); 110034286d66SNick Piggin 1101c435ee34SDavid Howells if (d_really_is_positive(dentry)) { 11022b0143b5SDavid Howells vnode = AFS_FS_I(d_inode(dentry)); 11033b6492dfSDavid Howells _enter("{v={%llx:%llu} n=%pd fl=%lx},", 1104a455589fSAl Viro vnode->fid.vid, vnode->fid.vnode, dentry, 1105260a9803SDavid Howells vnode->flags); 1106c435ee34SDavid Howells } else { 1107a455589fSAl Viro _enter("{neg n=%pd}", dentry); 1108c435ee34SDavid Howells } 11091da177e4SLinus Torvalds 1110260a9803SDavid Howells key = afs_request_key(AFS_FS_S(dentry->d_sb)->volume->cell); 111100d3b7a4SDavid Howells if (IS_ERR(key)) 111200d3b7a4SDavid Howells key = NULL; 111300d3b7a4SDavid Howells 111463d49d84SDavid Howells /* Hold the parent dentry so we can peer at it */ 111508e0e7c8SDavid Howells parent = dget_parent(dentry); 11162b0143b5SDavid Howells dir = AFS_FS_I(d_inode(parent)); 11171da177e4SLinus Torvalds 1118260a9803SDavid Howells /* validate the parent directory */ 1119260a9803SDavid Howells afs_validate(dir, key); 1120260a9803SDavid Howells 1121260a9803SDavid Howells if (test_bit(AFS_VNODE_DELETED, &dir->flags)) { 1122a455589fSAl Viro _debug("%pd: parent dir deleted", dentry); 112363d49d84SDavid Howells goto not_found; 11241da177e4SLinus Torvalds } 11251da177e4SLinus Torvalds 1126a4ff7401SDavid Howells /* We only need to invalidate a dentry if the server's copy changed 1127a4ff7401SDavid Howells * behind our back. If we made the change, it's no problem. Note that 1128a4ff7401SDavid Howells * on a 32-bit system, we only have 32 bits in the dentry to store the 1129a4ff7401SDavid Howells * version. 1130a4ff7401SDavid Howells */ 11319dd0b82eSDavid Howells dir_version = dir->status.data_version; 1132a4ff7401SDavid Howells de_version = (long)dentry->d_fsdata; 11339dd0b82eSDavid Howells if (de_version == (long)dir_version) 11345dc84855SDavid Howells goto out_valid_noupdate; 1135a4ff7401SDavid Howells 113640fc8102SDavid Howells invalid_before = dir->invalid_before; 113740fc8102SDavid Howells if (de_version - (long)invalid_before >= 0) 1138a4ff7401SDavid Howells goto out_valid; 1139260a9803SDavid Howells 114008e0e7c8SDavid Howells _debug("dir modified"); 1141d55b4da4SDavid Howells afs_stat_v(dir, n_reval); 11421da177e4SLinus Torvalds 11431da177e4SLinus Torvalds /* search the directory for this vnode */ 1144874c8ca1SDavid Howells ret = afs_do_lookup_one(&dir->netfs.inode, dentry, &fid, key, &dir_version); 1145260a9803SDavid Howells switch (ret) { 1146260a9803SDavid Howells case 0: 1147260a9803SDavid Howells /* the filename maps to something */ 11482b0143b5SDavid Howells if (d_really_is_negative(dentry)) 114963d49d84SDavid Howells goto not_found; 1150c435ee34SDavid Howells inode = d_inode(dentry); 1151c435ee34SDavid Howells if (is_bad_inode(inode)) { 1152a455589fSAl Viro printk("kAFS: afs_d_revalidate: %pd2 has bad inode\n", 1153a455589fSAl Viro dentry); 115463d49d84SDavid Howells goto not_found; 11551da177e4SLinus Torvalds } 11561da177e4SLinus Torvalds 1157c435ee34SDavid Howells vnode = AFS_FS_I(inode); 1158c435ee34SDavid Howells 11591da177e4SLinus Torvalds /* if the vnode ID has changed, then the dirent points to a 11601da177e4SLinus Torvalds * different file */ 116108e0e7c8SDavid Howells if (fid.vnode != vnode->fid.vnode) { 11623b6492dfSDavid Howells _debug("%pd: dirent changed [%llu != %llu]", 1163a455589fSAl Viro dentry, fid.vnode, 116408e0e7c8SDavid Howells vnode->fid.vnode); 11651da177e4SLinus Torvalds goto not_found; 11661da177e4SLinus Torvalds } 11671da177e4SLinus Torvalds 11681da177e4SLinus Torvalds /* if the vnode ID uniqifier has changed, then the file has 1169260a9803SDavid Howells * been deleted and replaced, and the original vnode ID has 1170260a9803SDavid Howells * been reused */ 117108e0e7c8SDavid Howells if (fid.unique != vnode->fid.unique) { 1172a455589fSAl Viro _debug("%pd: file deleted (uq %u -> %u I:%u)", 1173a455589fSAl Viro dentry, fid.unique, 11747a224228SJean Noel Cordenner vnode->fid.unique, 1175874c8ca1SDavid Howells vnode->netfs.inode.i_generation); 1176260a9803SDavid Howells goto not_found; 1177260a9803SDavid Howells } 1178260a9803SDavid Howells goto out_valid; 1179260a9803SDavid Howells 1180260a9803SDavid Howells case -ENOENT: 1181260a9803SDavid Howells /* the filename is unknown */ 1182a455589fSAl Viro _debug("%pd: dirent not found", dentry); 11832b0143b5SDavid Howells if (d_really_is_positive(dentry)) 1184260a9803SDavid Howells goto not_found; 1185260a9803SDavid Howells goto out_valid; 1186260a9803SDavid Howells 1187260a9803SDavid Howells default: 1188a455589fSAl Viro _debug("failed to iterate dir %pd: %d", 1189a455589fSAl Viro parent, ret); 119063d49d84SDavid Howells goto not_found; 11911da177e4SLinus Torvalds } 119208e0e7c8SDavid Howells 11931da177e4SLinus Torvalds out_valid: 11949dd0b82eSDavid Howells dentry->d_fsdata = (void *)(unsigned long)dir_version; 11955dc84855SDavid Howells out_valid_noupdate: 11961da177e4SLinus Torvalds dput(parent); 119700d3b7a4SDavid Howells key_put(key); 11981da177e4SLinus Torvalds _leave(" = 1 [valid]"); 11991da177e4SLinus Torvalds return 1; 12001da177e4SLinus Torvalds 12011da177e4SLinus Torvalds not_found: 1202a455589fSAl Viro _debug("dropping dentry %pd2", dentry); 12031da177e4SLinus Torvalds dput(parent); 120400d3b7a4SDavid Howells key_put(key); 12051da177e4SLinus Torvalds 12061da177e4SLinus Torvalds _leave(" = 0 [bad]"); 12071da177e4SLinus Torvalds return 0; 1208ec26815aSDavid Howells } 12091da177e4SLinus Torvalds 12101da177e4SLinus Torvalds /* 12111da177e4SLinus Torvalds * allow the VFS to enquire as to whether a dentry should be unhashed (mustn't 12121da177e4SLinus Torvalds * sleep) 12131da177e4SLinus Torvalds * - called from dput() when d_count is going to 0. 12141da177e4SLinus Torvalds * - return 1 to request dentry be unhashed, 0 otherwise 12151da177e4SLinus Torvalds */ 1216fe15ce44SNick Piggin static int afs_d_delete(const struct dentry *dentry) 12171da177e4SLinus Torvalds { 1218a455589fSAl Viro _enter("%pd", dentry); 12191da177e4SLinus Torvalds 12201da177e4SLinus Torvalds if (dentry->d_flags & DCACHE_NFSFS_RENAMED) 12211da177e4SLinus Torvalds goto zap; 12221da177e4SLinus Torvalds 12232b0143b5SDavid Howells if (d_really_is_positive(dentry) && 12242b0143b5SDavid Howells (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(d_inode(dentry))->flags) || 12252b0143b5SDavid Howells test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(d_inode(dentry))->flags))) 12261da177e4SLinus Torvalds goto zap; 12271da177e4SLinus Torvalds 12281da177e4SLinus Torvalds _leave(" = 0 [keep]"); 12291da177e4SLinus Torvalds return 0; 12301da177e4SLinus Torvalds 12311da177e4SLinus Torvalds zap: 12321da177e4SLinus Torvalds _leave(" = 1 [zap]"); 12331da177e4SLinus Torvalds return 1; 1234ec26815aSDavid Howells } 1235260a9803SDavid Howells 1236260a9803SDavid Howells /* 123779ddbfa5SDavid Howells * Clean up sillyrename files on dentry removal. 123879ddbfa5SDavid Howells */ 123979ddbfa5SDavid Howells static void afs_d_iput(struct dentry *dentry, struct inode *inode) 124079ddbfa5SDavid Howells { 124179ddbfa5SDavid Howells if (dentry->d_flags & DCACHE_NFSFS_RENAMED) 124279ddbfa5SDavid Howells afs_silly_iput(dentry, inode); 124379ddbfa5SDavid Howells iput(inode); 124479ddbfa5SDavid Howells } 124579ddbfa5SDavid Howells 124679ddbfa5SDavid Howells /* 1247260a9803SDavid Howells * handle dentry release 1248260a9803SDavid Howells */ 124966c7e1d3SDavid Howells void afs_d_release(struct dentry *dentry) 1250260a9803SDavid Howells { 1251a455589fSAl Viro _enter("%pd", dentry); 1252260a9803SDavid Howells } 1253260a9803SDavid Howells 1254728279a5SDavid Howells void afs_check_for_remote_deletion(struct afs_operation *op) 1255728279a5SDavid Howells { 1256728279a5SDavid Howells struct afs_vnode *vnode = op->file[0].vnode; 1257728279a5SDavid Howells 1258728279a5SDavid Howells switch (op->ac.abort_code) { 1259728279a5SDavid Howells case VNOVNODE: 1260728279a5SDavid Howells set_bit(AFS_VNODE_DELETED, &vnode->flags); 1261728279a5SDavid Howells afs_break_callback(vnode, afs_cb_break_for_deleted); 1262728279a5SDavid Howells } 1263728279a5SDavid Howells } 1264728279a5SDavid Howells 1265260a9803SDavid Howells /* 1266d2ddc776SDavid Howells * Create a new inode for create/mkdir/symlink 1267d2ddc776SDavid Howells */ 1268e49c7b2fSDavid Howells static void afs_vnode_new_inode(struct afs_operation *op) 1269d2ddc776SDavid Howells { 1270e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 12715a813276SDavid Howells struct afs_vnode *vnode; 1272d2ddc776SDavid Howells struct inode *inode; 1273d2ddc776SDavid Howells 1274e49c7b2fSDavid Howells _enter(""); 1275d2ddc776SDavid Howells 1276e49c7b2fSDavid Howells ASSERTCMP(op->error, ==, 0); 1277e49c7b2fSDavid Howells 1278e49c7b2fSDavid Howells inode = afs_iget(op, vp); 1279d2ddc776SDavid Howells if (IS_ERR(inode)) { 1280d2ddc776SDavid Howells /* ENOMEM or EINTR at a really inconvenient time - just abandon 1281d2ddc776SDavid Howells * the new directory on the server. 1282d2ddc776SDavid Howells */ 1283e49c7b2fSDavid Howells op->error = PTR_ERR(inode); 1284d2ddc776SDavid Howells return; 1285d2ddc776SDavid Howells } 1286d2ddc776SDavid Howells 12875a813276SDavid Howells vnode = AFS_FS_I(inode); 12885a813276SDavid Howells set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); 1289e49c7b2fSDavid Howells if (!op->error) 1290e49c7b2fSDavid Howells afs_cache_permit(vnode, op->key, vnode->cb_break, &vp->scb); 1291e49c7b2fSDavid Howells d_instantiate(op->dentry, inode); 1292d2ddc776SDavid Howells } 1293d2ddc776SDavid Howells 1294e49c7b2fSDavid Howells static void afs_create_success(struct afs_operation *op) 1295b8359153SDavid Howells { 1296e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1297da8d0755SDavid Howells op->ctime = op->file[0].scb.status.mtime_client; 1298e49c7b2fSDavid Howells afs_vnode_commit_status(op, &op->file[0]); 1299e49c7b2fSDavid Howells afs_update_dentry_version(op, &op->file[0], op->dentry); 1300e49c7b2fSDavid Howells afs_vnode_new_inode(op); 1301b8359153SDavid Howells } 1302b8359153SDavid Howells 1303e49c7b2fSDavid Howells static void afs_create_edit_dir(struct afs_operation *op) 13049dd0b82eSDavid Howells { 1305e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 1306e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 1307e49c7b2fSDavid Howells struct afs_vnode *dvnode = dvp->vnode; 1308e49c7b2fSDavid Howells 1309e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1310e49c7b2fSDavid Howells 1311e49c7b2fSDavid Howells down_write(&dvnode->validate_lock); 1312e49c7b2fSDavid Howells if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) && 1313e49c7b2fSDavid Howells dvnode->status.data_version == dvp->dv_before + dvp->dv_delta) 1314e49c7b2fSDavid Howells afs_edit_dir_add(dvnode, &op->dentry->d_name, &vp->fid, 1315e49c7b2fSDavid Howells op->create.reason); 1316e49c7b2fSDavid Howells up_write(&dvnode->validate_lock); 13179dd0b82eSDavid Howells } 13189dd0b82eSDavid Howells 1319e49c7b2fSDavid Howells static void afs_create_put(struct afs_operation *op) 1320e49c7b2fSDavid Howells { 1321e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1322e49c7b2fSDavid Howells 1323e49c7b2fSDavid Howells if (op->error) 1324e49c7b2fSDavid Howells d_drop(op->dentry); 1325e49c7b2fSDavid Howells } 1326e49c7b2fSDavid Howells 1327e49c7b2fSDavid Howells static const struct afs_operation_ops afs_mkdir_operation = { 1328e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_make_dir, 1329e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_make_dir, 1330e49c7b2fSDavid Howells .success = afs_create_success, 1331728279a5SDavid Howells .aborted = afs_check_for_remote_deletion, 1332e49c7b2fSDavid Howells .edit_dir = afs_create_edit_dir, 1333e49c7b2fSDavid Howells .put = afs_create_put, 1334e49c7b2fSDavid Howells }; 1335e49c7b2fSDavid Howells 13369dd0b82eSDavid Howells /* 1337260a9803SDavid Howells * create a directory on an AFS filesystem 1338260a9803SDavid Howells */ 1339c54bd91eSChristian Brauner static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, 1340549c7297SChristian Brauner struct dentry *dentry, umode_t mode) 1341260a9803SDavid Howells { 1342e49c7b2fSDavid Howells struct afs_operation *op; 1343d2ddc776SDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir); 1344260a9803SDavid Howells 13453b6492dfSDavid Howells _enter("{%llx:%llu},{%pd},%ho", 1346a455589fSAl Viro dvnode->fid.vid, dvnode->fid.vnode, dentry, mode); 1347260a9803SDavid Howells 1348e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, dvnode->volume); 1349e49c7b2fSDavid Howells if (IS_ERR(op)) { 1350260a9803SDavid Howells d_drop(dentry); 1351e49c7b2fSDavid Howells return PTR_ERR(op); 1352e49c7b2fSDavid Howells } 1353e49c7b2fSDavid Howells 1354e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, dvnode); 1355e49c7b2fSDavid Howells op->file[0].dv_delta = 1; 135622650f14SDavid Howells op->file[0].modification = true; 1357da8d0755SDavid Howells op->file[0].update_ctime = true; 1358e49c7b2fSDavid Howells op->dentry = dentry; 1359e49c7b2fSDavid Howells op->create.mode = S_IFDIR | mode; 1360e49c7b2fSDavid Howells op->create.reason = afs_edit_dir_for_mkdir; 1361e49c7b2fSDavid Howells op->ops = &afs_mkdir_operation; 1362e49c7b2fSDavid Howells return afs_do_sync_operation(op); 1363260a9803SDavid Howells } 1364260a9803SDavid Howells 1365260a9803SDavid Howells /* 1366d2ddc776SDavid Howells * Remove a subdir from a directory. 1367260a9803SDavid Howells */ 1368d2ddc776SDavid Howells static void afs_dir_remove_subdir(struct dentry *dentry) 1369260a9803SDavid Howells { 13702b0143b5SDavid Howells if (d_really_is_positive(dentry)) { 1371d2ddc776SDavid Howells struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); 1372d2ddc776SDavid Howells 1373874c8ca1SDavid Howells clear_nlink(&vnode->netfs.inode); 1374260a9803SDavid Howells set_bit(AFS_VNODE_DELETED, &vnode->flags); 1375c435ee34SDavid Howells clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); 137663a4681fSDavid Howells clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); 1377260a9803SDavid Howells } 1378260a9803SDavid Howells } 1379260a9803SDavid Howells 1380e49c7b2fSDavid Howells static void afs_rmdir_success(struct afs_operation *op) 1381e49c7b2fSDavid Howells { 1382e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1383da8d0755SDavid Howells op->ctime = op->file[0].scb.status.mtime_client; 1384e49c7b2fSDavid Howells afs_vnode_commit_status(op, &op->file[0]); 1385e49c7b2fSDavid Howells afs_update_dentry_version(op, &op->file[0], op->dentry); 1386e49c7b2fSDavid Howells } 1387e49c7b2fSDavid Howells 1388e49c7b2fSDavid Howells static void afs_rmdir_edit_dir(struct afs_operation *op) 1389e49c7b2fSDavid Howells { 1390e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 1391e49c7b2fSDavid Howells struct afs_vnode *dvnode = dvp->vnode; 1392e49c7b2fSDavid Howells 1393e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1394e49c7b2fSDavid Howells afs_dir_remove_subdir(op->dentry); 1395e49c7b2fSDavid Howells 1396e49c7b2fSDavid Howells down_write(&dvnode->validate_lock); 1397e49c7b2fSDavid Howells if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) && 1398e49c7b2fSDavid Howells dvnode->status.data_version == dvp->dv_before + dvp->dv_delta) 1399e49c7b2fSDavid Howells afs_edit_dir_remove(dvnode, &op->dentry->d_name, 1400e49c7b2fSDavid Howells afs_edit_dir_for_rmdir); 1401e49c7b2fSDavid Howells up_write(&dvnode->validate_lock); 1402e49c7b2fSDavid Howells } 1403e49c7b2fSDavid Howells 1404e49c7b2fSDavid Howells static void afs_rmdir_put(struct afs_operation *op) 1405e49c7b2fSDavid Howells { 1406e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1407e49c7b2fSDavid Howells if (op->file[1].vnode) 1408e49c7b2fSDavid Howells up_write(&op->file[1].vnode->rmdir_lock); 1409e49c7b2fSDavid Howells } 1410e49c7b2fSDavid Howells 1411e49c7b2fSDavid Howells static const struct afs_operation_ops afs_rmdir_operation = { 1412e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_remove_dir, 1413e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_remove_dir, 1414e49c7b2fSDavid Howells .success = afs_rmdir_success, 1415728279a5SDavid Howells .aborted = afs_check_for_remote_deletion, 1416e49c7b2fSDavid Howells .edit_dir = afs_rmdir_edit_dir, 1417e49c7b2fSDavid Howells .put = afs_rmdir_put, 1418e49c7b2fSDavid Howells }; 1419e49c7b2fSDavid Howells 1420260a9803SDavid Howells /* 1421d2ddc776SDavid Howells * remove a directory from an AFS filesystem 1422260a9803SDavid Howells */ 1423d2ddc776SDavid Howells static int afs_rmdir(struct inode *dir, struct dentry *dentry) 1424260a9803SDavid Howells { 1425e49c7b2fSDavid Howells struct afs_operation *op; 1426f58db83fSDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL; 1427260a9803SDavid Howells int ret; 1428260a9803SDavid Howells 14293b6492dfSDavid Howells _enter("{%llx:%llu},{%pd}", 1430a455589fSAl Viro dvnode->fid.vid, dvnode->fid.vnode, dentry); 1431260a9803SDavid Howells 1432e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, dvnode->volume); 1433e49c7b2fSDavid Howells if (IS_ERR(op)) 1434e49c7b2fSDavid Howells return PTR_ERR(op); 1435a58823acSDavid Howells 1436e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, dvnode); 1437e49c7b2fSDavid Howells op->file[0].dv_delta = 1; 143822650f14SDavid Howells op->file[0].modification = true; 1439da8d0755SDavid Howells op->file[0].update_ctime = true; 1440e49c7b2fSDavid Howells 1441e49c7b2fSDavid Howells op->dentry = dentry; 1442e49c7b2fSDavid Howells op->ops = &afs_rmdir_operation; 1443260a9803SDavid Howells 1444f58db83fSDavid Howells /* Try to make sure we have a callback promise on the victim. */ 1445f58db83fSDavid Howells if (d_really_is_positive(dentry)) { 1446f58db83fSDavid Howells vnode = AFS_FS_I(d_inode(dentry)); 1447e49c7b2fSDavid Howells ret = afs_validate(vnode, op->key); 1448f58db83fSDavid Howells if (ret < 0) 1449e49c7b2fSDavid Howells goto error; 1450f58db83fSDavid Howells } 1451f58db83fSDavid Howells 145279ddbfa5SDavid Howells if (vnode) { 145379ddbfa5SDavid Howells ret = down_write_killable(&vnode->rmdir_lock); 145479ddbfa5SDavid Howells if (ret < 0) 1455e49c7b2fSDavid Howells goto error; 1456e49c7b2fSDavid Howells op->file[1].vnode = vnode; 145779ddbfa5SDavid Howells } 145879ddbfa5SDavid Howells 1459e49c7b2fSDavid Howells return afs_do_sync_operation(op); 1460a58823acSDavid Howells 1461d2ddc776SDavid Howells error: 1462e49c7b2fSDavid Howells return afs_put_operation(op); 1463d2ddc776SDavid Howells } 1464260a9803SDavid Howells 1465d2ddc776SDavid Howells /* 1466d2ddc776SDavid Howells * Remove a link to a file or symlink from a directory. 1467d2ddc776SDavid Howells * 1468d2ddc776SDavid Howells * If the file was not deleted due to excess hard links, the fileserver will 1469d2ddc776SDavid Howells * break the callback promise on the file - if it had one - before it returns 1470d2ddc776SDavid Howells * to us, and if it was deleted, it won't 1471d2ddc776SDavid Howells * 1472d2ddc776SDavid Howells * However, if we didn't have a callback promise outstanding, or it was 1473d2ddc776SDavid Howells * outstanding on a different server, then it won't break it either... 1474d2ddc776SDavid Howells */ 1475e49c7b2fSDavid Howells static void afs_dir_remove_link(struct afs_operation *op) 1476d2ddc776SDavid Howells { 1477e49c7b2fSDavid Howells struct afs_vnode *dvnode = op->file[0].vnode; 1478e49c7b2fSDavid Howells struct afs_vnode *vnode = op->file[1].vnode; 1479e49c7b2fSDavid Howells struct dentry *dentry = op->dentry; 1480e49c7b2fSDavid Howells int ret; 1481d2ddc776SDavid Howells 1482e49c7b2fSDavid Howells if (op->error != 0 || 1483e49c7b2fSDavid Howells (op->file[1].scb.have_status && op->file[1].scb.have_error)) 1484e49c7b2fSDavid Howells return; 1485e49c7b2fSDavid Howells if (d_really_is_positive(dentry)) 1486e49c7b2fSDavid Howells return; 1487d2ddc776SDavid Howells 148830062bd1SDavid Howells if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { 148930062bd1SDavid Howells /* Already done */ 1490a38a7558SDavid Howells } else if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { 1491a38a7558SDavid Howells write_seqlock(&vnode->cb_lock); 1492874c8ca1SDavid Howells drop_nlink(&vnode->netfs.inode); 1493874c8ca1SDavid Howells if (vnode->netfs.inode.i_nlink == 0) { 1494440fbc3aSDavid Howells set_bit(AFS_VNODE_DELETED, &vnode->flags); 1495051d2525SDavid Howells __afs_break_callback(vnode, afs_cb_break_for_unlink); 1496440fbc3aSDavid Howells } 1497a38a7558SDavid Howells write_sequnlock(&vnode->cb_lock); 1498440fbc3aSDavid Howells } else { 1499051d2525SDavid Howells afs_break_callback(vnode, afs_cb_break_for_unlink); 1500440fbc3aSDavid Howells 1501d2ddc776SDavid Howells if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) 1502e49c7b2fSDavid Howells _debug("AFS_VNODE_DELETED"); 1503d2ddc776SDavid Howells 1504e49c7b2fSDavid Howells ret = afs_validate(vnode, op->key); 1505e49c7b2fSDavid Howells if (ret != -ESTALE) 1506e49c7b2fSDavid Howells op->error = ret; 1507d2ddc776SDavid Howells } 1508d2ddc776SDavid Howells 1509874c8ca1SDavid Howells _debug("nlink %d [val %d]", vnode->netfs.inode.i_nlink, op->error); 1510d2ddc776SDavid Howells } 1511d2ddc776SDavid Howells 1512e49c7b2fSDavid Howells static void afs_unlink_success(struct afs_operation *op) 1513e49c7b2fSDavid Howells { 1514e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1515da8d0755SDavid Howells op->ctime = op->file[0].scb.status.mtime_client; 1516b6489a49SDavid Howells afs_check_dir_conflict(op, &op->file[0]); 1517e49c7b2fSDavid Howells afs_vnode_commit_status(op, &op->file[0]); 1518e49c7b2fSDavid Howells afs_vnode_commit_status(op, &op->file[1]); 1519e49c7b2fSDavid Howells afs_update_dentry_version(op, &op->file[0], op->dentry); 1520e49c7b2fSDavid Howells afs_dir_remove_link(op); 1521e49c7b2fSDavid Howells } 1522e49c7b2fSDavid Howells 1523e49c7b2fSDavid Howells static void afs_unlink_edit_dir(struct afs_operation *op) 1524e49c7b2fSDavid Howells { 1525e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 1526e49c7b2fSDavid Howells struct afs_vnode *dvnode = dvp->vnode; 1527e49c7b2fSDavid Howells 1528e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1529e49c7b2fSDavid Howells down_write(&dvnode->validate_lock); 1530e49c7b2fSDavid Howells if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) && 1531e49c7b2fSDavid Howells dvnode->status.data_version == dvp->dv_before + dvp->dv_delta) 1532e49c7b2fSDavid Howells afs_edit_dir_remove(dvnode, &op->dentry->d_name, 1533e49c7b2fSDavid Howells afs_edit_dir_for_unlink); 1534e49c7b2fSDavid Howells up_write(&dvnode->validate_lock); 1535e49c7b2fSDavid Howells } 1536e49c7b2fSDavid Howells 1537e49c7b2fSDavid Howells static void afs_unlink_put(struct afs_operation *op) 1538e49c7b2fSDavid Howells { 1539e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1540e49c7b2fSDavid Howells if (op->unlink.need_rehash && op->error < 0 && op->error != -ENOENT) 1541e49c7b2fSDavid Howells d_rehash(op->dentry); 1542e49c7b2fSDavid Howells } 1543e49c7b2fSDavid Howells 1544e49c7b2fSDavid Howells static const struct afs_operation_ops afs_unlink_operation = { 1545e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_remove_file, 1546e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_remove_file, 1547e49c7b2fSDavid Howells .success = afs_unlink_success, 1548728279a5SDavid Howells .aborted = afs_check_for_remote_deletion, 1549e49c7b2fSDavid Howells .edit_dir = afs_unlink_edit_dir, 1550e49c7b2fSDavid Howells .put = afs_unlink_put, 1551e49c7b2fSDavid Howells }; 1552e49c7b2fSDavid Howells 1553d2ddc776SDavid Howells /* 1554d2ddc776SDavid Howells * Remove a file or symlink from an AFS filesystem. 1555d2ddc776SDavid Howells */ 1556d2ddc776SDavid Howells static int afs_unlink(struct inode *dir, struct dentry *dentry) 1557d2ddc776SDavid Howells { 1558e49c7b2fSDavid Howells struct afs_operation *op; 1559fa59f52fSDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir); 1560fa59f52fSDavid Howells struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); 1561d2ddc776SDavid Howells int ret; 1562d2ddc776SDavid Howells 15633b6492dfSDavid Howells _enter("{%llx:%llu},{%pd}", 1564d2ddc776SDavid Howells dvnode->fid.vid, dvnode->fid.vnode, dentry); 1565d2ddc776SDavid Howells 1566d2ddc776SDavid Howells if (dentry->d_name.len >= AFSNAMEMAX) 1567d2ddc776SDavid Howells return -ENAMETOOLONG; 1568d2ddc776SDavid Howells 1569e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, dvnode->volume); 1570e49c7b2fSDavid Howells if (IS_ERR(op)) 1571e49c7b2fSDavid Howells return PTR_ERR(op); 1572a58823acSDavid Howells 1573e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, dvnode); 1574e49c7b2fSDavid Howells op->file[0].dv_delta = 1; 157522650f14SDavid Howells op->file[0].modification = true; 1576da8d0755SDavid Howells op->file[0].update_ctime = true; 1577d2ddc776SDavid Howells 1578d2ddc776SDavid Howells /* Try to make sure we have a callback promise on the victim. */ 1579e49c7b2fSDavid Howells ret = afs_validate(vnode, op->key); 1580e49c7b2fSDavid Howells if (ret < 0) { 1581e49c7b2fSDavid Howells op->error = ret; 1582e49c7b2fSDavid Howells goto error; 1583e49c7b2fSDavid Howells } 1584d2ddc776SDavid Howells 158579ddbfa5SDavid Howells spin_lock(&dentry->d_lock); 1586fa59f52fSDavid Howells if (d_count(dentry) > 1) { 158779ddbfa5SDavid Howells spin_unlock(&dentry->d_lock); 158879ddbfa5SDavid Howells /* Start asynchronous writeout of the inode */ 158979ddbfa5SDavid Howells write_inode_now(d_inode(dentry), 0); 1590e49c7b2fSDavid Howells op->error = afs_sillyrename(dvnode, vnode, dentry, op->key); 1591e49c7b2fSDavid Howells goto error; 159279ddbfa5SDavid Howells } 159379ddbfa5SDavid Howells if (!d_unhashed(dentry)) { 159479ddbfa5SDavid Howells /* Prevent a race with RCU lookup. */ 159579ddbfa5SDavid Howells __d_drop(dentry); 1596e49c7b2fSDavid Howells op->unlink.need_rehash = true; 159779ddbfa5SDavid Howells } 159879ddbfa5SDavid Howells spin_unlock(&dentry->d_lock); 159979ddbfa5SDavid Howells 1600e49c7b2fSDavid Howells op->file[1].vnode = vnode; 1601da8d0755SDavid Howells op->file[1].update_ctime = true; 1602b6489a49SDavid Howells op->file[1].op_unlinked = true; 1603e49c7b2fSDavid Howells op->dentry = dentry; 1604e49c7b2fSDavid Howells op->ops = &afs_unlink_operation; 1605b6489a49SDavid Howells afs_begin_vnode_operation(op); 1606b6489a49SDavid Howells afs_wait_for_operation(op); 1607b6489a49SDavid Howells 1608b6489a49SDavid Howells /* If there was a conflict with a third party, check the status of the 1609b6489a49SDavid Howells * unlinked vnode. 1610b6489a49SDavid Howells */ 1611b6489a49SDavid Howells if (op->error == 0 && (op->flags & AFS_OPERATION_DIR_CONFLICT)) { 1612b6489a49SDavid Howells op->file[1].update_ctime = false; 1613b6489a49SDavid Howells op->fetch_status.which = 1; 1614b6489a49SDavid Howells op->ops = &afs_fetch_status_operation; 1615b6489a49SDavid Howells afs_begin_vnode_operation(op); 1616b6489a49SDavid Howells afs_wait_for_operation(op); 1617b6489a49SDavid Howells } 1618b6489a49SDavid Howells 1619b6489a49SDavid Howells return afs_put_operation(op); 1620a58823acSDavid Howells 1621260a9803SDavid Howells error: 1622e49c7b2fSDavid Howells return afs_put_operation(op); 1623260a9803SDavid Howells } 1624260a9803SDavid Howells 1625e49c7b2fSDavid Howells static const struct afs_operation_ops afs_create_operation = { 1626e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_create_file, 1627e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_create_file, 1628e49c7b2fSDavid Howells .success = afs_create_success, 1629728279a5SDavid Howells .aborted = afs_check_for_remote_deletion, 1630e49c7b2fSDavid Howells .edit_dir = afs_create_edit_dir, 1631e49c7b2fSDavid Howells .put = afs_create_put, 1632e49c7b2fSDavid Howells }; 1633e49c7b2fSDavid Howells 1634260a9803SDavid Howells /* 1635260a9803SDavid Howells * create a regular file on an AFS filesystem 1636260a9803SDavid Howells */ 16376c960e68SChristian Brauner static int afs_create(struct mnt_idmap *idmap, struct inode *dir, 1638549c7297SChristian Brauner struct dentry *dentry, umode_t mode, bool excl) 1639260a9803SDavid Howells { 1640e49c7b2fSDavid Howells struct afs_operation *op; 164143dd388bSColin Ian King struct afs_vnode *dvnode = AFS_FS_I(dir); 1642e49c7b2fSDavid Howells int ret = -ENAMETOOLONG; 1643260a9803SDavid Howells 1644e49c7b2fSDavid Howells _enter("{%llx:%llu},{%pd},%ho", 1645a455589fSAl Viro dvnode->fid.vid, dvnode->fid.vnode, dentry, mode); 1646260a9803SDavid Howells 1647d2ddc776SDavid Howells if (dentry->d_name.len >= AFSNAMEMAX) 1648d2ddc776SDavid Howells goto error; 1649d2ddc776SDavid Howells 1650e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, dvnode->volume); 1651e49c7b2fSDavid Howells if (IS_ERR(op)) { 1652e49c7b2fSDavid Howells ret = PTR_ERR(op); 1653260a9803SDavid Howells goto error; 1654260a9803SDavid Howells } 1655260a9803SDavid Howells 1656e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, dvnode); 1657e49c7b2fSDavid Howells op->file[0].dv_delta = 1; 165822650f14SDavid Howells op->file[0].modification = true; 1659da8d0755SDavid Howells op->file[0].update_ctime = true; 1660a58823acSDavid Howells 1661e49c7b2fSDavid Howells op->dentry = dentry; 1662e49c7b2fSDavid Howells op->create.mode = S_IFREG | mode; 1663e49c7b2fSDavid Howells op->create.reason = afs_edit_dir_for_create; 1664e49c7b2fSDavid Howells op->ops = &afs_create_operation; 1665e49c7b2fSDavid Howells return afs_do_sync_operation(op); 1666a58823acSDavid Howells 1667260a9803SDavid Howells error: 1668260a9803SDavid Howells d_drop(dentry); 1669260a9803SDavid Howells _leave(" = %d", ret); 1670260a9803SDavid Howells return ret; 1671260a9803SDavid Howells } 1672260a9803SDavid Howells 1673e49c7b2fSDavid Howells static void afs_link_success(struct afs_operation *op) 1674e49c7b2fSDavid Howells { 1675e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 1676e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 1677e49c7b2fSDavid Howells 1678e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1679da8d0755SDavid Howells op->ctime = dvp->scb.status.mtime_client; 1680e49c7b2fSDavid Howells afs_vnode_commit_status(op, dvp); 1681e49c7b2fSDavid Howells afs_vnode_commit_status(op, vp); 1682e49c7b2fSDavid Howells afs_update_dentry_version(op, dvp, op->dentry); 1683e49c7b2fSDavid Howells if (op->dentry_2->d_parent == op->dentry->d_parent) 1684e49c7b2fSDavid Howells afs_update_dentry_version(op, dvp, op->dentry_2); 1685874c8ca1SDavid Howells ihold(&vp->vnode->netfs.inode); 1686874c8ca1SDavid Howells d_instantiate(op->dentry, &vp->vnode->netfs.inode); 1687e49c7b2fSDavid Howells } 1688e49c7b2fSDavid Howells 1689e49c7b2fSDavid Howells static void afs_link_put(struct afs_operation *op) 1690e49c7b2fSDavid Howells { 1691e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1692e49c7b2fSDavid Howells if (op->error) 1693e49c7b2fSDavid Howells d_drop(op->dentry); 1694e49c7b2fSDavid Howells } 1695e49c7b2fSDavid Howells 1696e49c7b2fSDavid Howells static const struct afs_operation_ops afs_link_operation = { 1697e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_link, 1698e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_link, 1699e49c7b2fSDavid Howells .success = afs_link_success, 1700728279a5SDavid Howells .aborted = afs_check_for_remote_deletion, 1701e49c7b2fSDavid Howells .edit_dir = afs_create_edit_dir, 1702e49c7b2fSDavid Howells .put = afs_link_put, 1703e49c7b2fSDavid Howells }; 1704e49c7b2fSDavid Howells 1705260a9803SDavid Howells /* 1706260a9803SDavid Howells * create a hard link between files in an AFS filesystem 1707260a9803SDavid Howells */ 1708260a9803SDavid Howells static int afs_link(struct dentry *from, struct inode *dir, 1709260a9803SDavid Howells struct dentry *dentry) 1710260a9803SDavid Howells { 1711e49c7b2fSDavid Howells struct afs_operation *op; 1712a58823acSDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir); 1713a58823acSDavid Howells struct afs_vnode *vnode = AFS_FS_I(d_inode(from)); 1714e49c7b2fSDavid Howells int ret = -ENAMETOOLONG; 1715260a9803SDavid Howells 17163b6492dfSDavid Howells _enter("{%llx:%llu},{%llx:%llu},{%pd}", 1717260a9803SDavid Howells vnode->fid.vid, vnode->fid.vnode, 1718260a9803SDavid Howells dvnode->fid.vid, dvnode->fid.vnode, 1719a455589fSAl Viro dentry); 1720260a9803SDavid Howells 1721d2ddc776SDavid Howells if (dentry->d_name.len >= AFSNAMEMAX) 1722d2ddc776SDavid Howells goto error; 1723d2ddc776SDavid Howells 1724e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, dvnode->volume); 1725e49c7b2fSDavid Howells if (IS_ERR(op)) { 1726e49c7b2fSDavid Howells ret = PTR_ERR(op); 1727a58823acSDavid Howells goto error; 1728260a9803SDavid Howells } 1729260a9803SDavid Howells 17303978d816SDavid Howells ret = afs_validate(vnode, op->key); 17313978d816SDavid Howells if (ret < 0) 17323978d816SDavid Howells goto error_op; 17333978d816SDavid Howells 1734e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, dvnode); 1735e49c7b2fSDavid Howells afs_op_set_vnode(op, 1, vnode); 1736e49c7b2fSDavid Howells op->file[0].dv_delta = 1; 173722650f14SDavid Howells op->file[0].modification = true; 1738da8d0755SDavid Howells op->file[0].update_ctime = true; 1739da8d0755SDavid Howells op->file[1].update_ctime = true; 1740a58823acSDavid Howells 1741e49c7b2fSDavid Howells op->dentry = dentry; 1742e49c7b2fSDavid Howells op->dentry_2 = from; 1743e49c7b2fSDavid Howells op->ops = &afs_link_operation; 1744e49c7b2fSDavid Howells op->create.reason = afs_edit_dir_for_link; 1745e49c7b2fSDavid Howells return afs_do_sync_operation(op); 1746260a9803SDavid Howells 17473978d816SDavid Howells error_op: 17483978d816SDavid Howells afs_put_operation(op); 1749260a9803SDavid Howells error: 1750260a9803SDavid Howells d_drop(dentry); 1751260a9803SDavid Howells _leave(" = %d", ret); 1752260a9803SDavid Howells return ret; 1753260a9803SDavid Howells } 1754260a9803SDavid Howells 1755e49c7b2fSDavid Howells static const struct afs_operation_ops afs_symlink_operation = { 1756e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_symlink, 1757e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_symlink, 1758e49c7b2fSDavid Howells .success = afs_create_success, 1759728279a5SDavid Howells .aborted = afs_check_for_remote_deletion, 1760e49c7b2fSDavid Howells .edit_dir = afs_create_edit_dir, 1761e49c7b2fSDavid Howells .put = afs_create_put, 1762e49c7b2fSDavid Howells }; 1763e49c7b2fSDavid Howells 1764260a9803SDavid Howells /* 1765260a9803SDavid Howells * create a symlink in an AFS filesystem 1766260a9803SDavid Howells */ 17677a77db95SChristian Brauner static int afs_symlink(struct mnt_idmap *idmap, struct inode *dir, 1768549c7297SChristian Brauner struct dentry *dentry, const char *content) 1769260a9803SDavid Howells { 1770e49c7b2fSDavid Howells struct afs_operation *op; 1771d2ddc776SDavid Howells struct afs_vnode *dvnode = AFS_FS_I(dir); 1772260a9803SDavid Howells int ret; 1773260a9803SDavid Howells 17743b6492dfSDavid Howells _enter("{%llx:%llu},{%pd},%s", 1775a455589fSAl Viro dvnode->fid.vid, dvnode->fid.vnode, dentry, 1776260a9803SDavid Howells content); 1777260a9803SDavid Howells 1778d2ddc776SDavid Howells ret = -ENAMETOOLONG; 1779d2ddc776SDavid Howells if (dentry->d_name.len >= AFSNAMEMAX) 1780d2ddc776SDavid Howells goto error; 1781d2ddc776SDavid Howells 1782260a9803SDavid Howells ret = -EINVAL; 178345222b9eSDavid Howells if (strlen(content) >= AFSPATHMAX) 1784260a9803SDavid Howells goto error; 1785260a9803SDavid Howells 1786e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, dvnode->volume); 1787e49c7b2fSDavid Howells if (IS_ERR(op)) { 1788e49c7b2fSDavid Howells ret = PTR_ERR(op); 1789a58823acSDavid Howells goto error; 1790260a9803SDavid Howells } 1791260a9803SDavid Howells 1792e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, dvnode); 1793e49c7b2fSDavid Howells op->file[0].dv_delta = 1; 1794a58823acSDavid Howells 1795e49c7b2fSDavid Howells op->dentry = dentry; 1796e49c7b2fSDavid Howells op->ops = &afs_symlink_operation; 1797e49c7b2fSDavid Howells op->create.reason = afs_edit_dir_for_symlink; 1798e49c7b2fSDavid Howells op->create.symlink = content; 1799e49c7b2fSDavid Howells return afs_do_sync_operation(op); 1800d2ddc776SDavid Howells 1801260a9803SDavid Howells error: 1802260a9803SDavid Howells d_drop(dentry); 1803260a9803SDavid Howells _leave(" = %d", ret); 1804260a9803SDavid Howells return ret; 1805260a9803SDavid Howells } 1806260a9803SDavid Howells 1807e49c7b2fSDavid Howells static void afs_rename_success(struct afs_operation *op) 1808260a9803SDavid Howells { 1809e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1810e49c7b2fSDavid Howells 1811da8d0755SDavid Howells op->ctime = op->file[0].scb.status.mtime_client; 1812b6489a49SDavid Howells afs_check_dir_conflict(op, &op->file[1]); 1813e49c7b2fSDavid Howells afs_vnode_commit_status(op, &op->file[0]); 1814da8d0755SDavid Howells if (op->file[1].vnode != op->file[0].vnode) { 1815da8d0755SDavid Howells op->ctime = op->file[1].scb.status.mtime_client; 1816e49c7b2fSDavid Howells afs_vnode_commit_status(op, &op->file[1]); 1817e49c7b2fSDavid Howells } 1818da8d0755SDavid Howells } 1819e49c7b2fSDavid Howells 1820e49c7b2fSDavid Howells static void afs_rename_edit_dir(struct afs_operation *op) 1821e49c7b2fSDavid Howells { 1822e49c7b2fSDavid Howells struct afs_vnode_param *orig_dvp = &op->file[0]; 1823e49c7b2fSDavid Howells struct afs_vnode_param *new_dvp = &op->file[1]; 1824e49c7b2fSDavid Howells struct afs_vnode *orig_dvnode = orig_dvp->vnode; 1825e49c7b2fSDavid Howells struct afs_vnode *new_dvnode = new_dvp->vnode; 1826e49c7b2fSDavid Howells struct afs_vnode *vnode = AFS_FS_I(d_inode(op->dentry)); 1827e49c7b2fSDavid Howells struct dentry *old_dentry = op->dentry; 1828e49c7b2fSDavid Howells struct dentry *new_dentry = op->dentry_2; 182979ddbfa5SDavid Howells struct inode *new_inode; 1830260a9803SDavid Howells 1831e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 18321cd66c93SMiklos Szeredi 1833e49c7b2fSDavid Howells if (op->rename.rehash) { 1834e49c7b2fSDavid Howells d_rehash(op->rename.rehash); 1835e49c7b2fSDavid Howells op->rename.rehash = NULL; 1836260a9803SDavid Howells } 1837260a9803SDavid Howells 18382105c282SDavid Howells down_write(&orig_dvnode->validate_lock); 18392105c282SDavid Howells if (test_bit(AFS_VNODE_DIR_VALID, &orig_dvnode->flags) && 1840e49c7b2fSDavid Howells orig_dvnode->status.data_version == orig_dvp->dv_before + orig_dvp->dv_delta) 184163a4681fSDavid Howells afs_edit_dir_remove(orig_dvnode, &old_dentry->d_name, 184279ddbfa5SDavid Howells afs_edit_dir_for_rename_0); 184363a4681fSDavid Howells 1844e49c7b2fSDavid Howells if (new_dvnode != orig_dvnode) { 1845e49c7b2fSDavid Howells up_write(&orig_dvnode->validate_lock); 18462105c282SDavid Howells down_write(&new_dvnode->validate_lock); 18472105c282SDavid Howells } 1848e49c7b2fSDavid Howells 18492105c282SDavid Howells if (test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags) && 1850e49c7b2fSDavid Howells new_dvnode->status.data_version == new_dvp->dv_before + new_dvp->dv_delta) { 1851e49c7b2fSDavid Howells if (!op->rename.new_negative) 185263a4681fSDavid Howells afs_edit_dir_remove(new_dvnode, &new_dentry->d_name, 185379ddbfa5SDavid Howells afs_edit_dir_for_rename_1); 185463a4681fSDavid Howells 185563a4681fSDavid Howells afs_edit_dir_add(new_dvnode, &new_dentry->d_name, 185679ddbfa5SDavid Howells &vnode->fid, afs_edit_dir_for_rename_2); 18572105c282SDavid Howells } 185879ddbfa5SDavid Howells 185979ddbfa5SDavid Howells new_inode = d_inode(new_dentry); 186079ddbfa5SDavid Howells if (new_inode) { 186179ddbfa5SDavid Howells spin_lock(&new_inode->i_lock); 1862f610a5a2SDavid Howells if (S_ISDIR(new_inode->i_mode)) 1863f610a5a2SDavid Howells clear_nlink(new_inode); 1864f610a5a2SDavid Howells else if (new_inode->i_nlink > 0) 186579ddbfa5SDavid Howells drop_nlink(new_inode); 186679ddbfa5SDavid Howells spin_unlock(&new_inode->i_lock); 186779ddbfa5SDavid Howells } 18689dd0b82eSDavid Howells 18699dd0b82eSDavid Howells /* Now we can update d_fsdata on the dentries to reflect their 18709dd0b82eSDavid Howells * new parent's data_version. 18719dd0b82eSDavid Howells * 18729dd0b82eSDavid Howells * Note that if we ever implement RENAME_EXCHANGE, we'll have 18739dd0b82eSDavid Howells * to update both dentries with opposing dir versions. 18749dd0b82eSDavid Howells */ 1875e49c7b2fSDavid Howells afs_update_dentry_version(op, new_dvp, op->dentry); 1876e49c7b2fSDavid Howells afs_update_dentry_version(op, new_dvp, op->dentry_2); 1877e49c7b2fSDavid Howells 187879ddbfa5SDavid Howells d_move(old_dentry, new_dentry); 1879e49c7b2fSDavid Howells 18802105c282SDavid Howells up_write(&new_dvnode->validate_lock); 188163a4681fSDavid Howells } 188263a4681fSDavid Howells 1883e49c7b2fSDavid Howells static void afs_rename_put(struct afs_operation *op) 1884e49c7b2fSDavid Howells { 1885e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 1886e49c7b2fSDavid Howells if (op->rename.rehash) 1887e49c7b2fSDavid Howells d_rehash(op->rename.rehash); 1888e49c7b2fSDavid Howells dput(op->rename.tmp); 1889e49c7b2fSDavid Howells if (op->error) 1890e49c7b2fSDavid Howells d_rehash(op->dentry); 1891e49c7b2fSDavid Howells } 1892e49c7b2fSDavid Howells 1893e49c7b2fSDavid Howells static const struct afs_operation_ops afs_rename_operation = { 1894e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_rename, 1895e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_rename, 1896e49c7b2fSDavid Howells .success = afs_rename_success, 1897e49c7b2fSDavid Howells .edit_dir = afs_rename_edit_dir, 1898e49c7b2fSDavid Howells .put = afs_rename_put, 1899e49c7b2fSDavid Howells }; 1900e49c7b2fSDavid Howells 1901e49c7b2fSDavid Howells /* 1902e49c7b2fSDavid Howells * rename a file in an AFS filesystem and/or move it between directories 1903e49c7b2fSDavid Howells */ 1904e18275aeSChristian Brauner static int afs_rename(struct mnt_idmap *idmap, struct inode *old_dir, 1905549c7297SChristian Brauner struct dentry *old_dentry, struct inode *new_dir, 1906549c7297SChristian Brauner struct dentry *new_dentry, unsigned int flags) 1907e49c7b2fSDavid Howells { 1908e49c7b2fSDavid Howells struct afs_operation *op; 1909e49c7b2fSDavid Howells struct afs_vnode *orig_dvnode, *new_dvnode, *vnode; 1910e49c7b2fSDavid Howells int ret; 1911e49c7b2fSDavid Howells 1912e49c7b2fSDavid Howells if (flags) 1913e49c7b2fSDavid Howells return -EINVAL; 1914e49c7b2fSDavid Howells 1915e49c7b2fSDavid Howells /* Don't allow silly-rename files be moved around. */ 1916e49c7b2fSDavid Howells if (old_dentry->d_flags & DCACHE_NFSFS_RENAMED) 1917e49c7b2fSDavid Howells return -EINVAL; 1918e49c7b2fSDavid Howells 1919e49c7b2fSDavid Howells vnode = AFS_FS_I(d_inode(old_dentry)); 1920e49c7b2fSDavid Howells orig_dvnode = AFS_FS_I(old_dir); 1921e49c7b2fSDavid Howells new_dvnode = AFS_FS_I(new_dir); 1922e49c7b2fSDavid Howells 1923e49c7b2fSDavid Howells _enter("{%llx:%llu},{%llx:%llu},{%llx:%llu},{%pd}", 1924e49c7b2fSDavid Howells orig_dvnode->fid.vid, orig_dvnode->fid.vnode, 1925e49c7b2fSDavid Howells vnode->fid.vid, vnode->fid.vnode, 1926e49c7b2fSDavid Howells new_dvnode->fid.vid, new_dvnode->fid.vnode, 1927e49c7b2fSDavid Howells new_dentry); 1928e49c7b2fSDavid Howells 1929e49c7b2fSDavid Howells op = afs_alloc_operation(NULL, orig_dvnode->volume); 1930e49c7b2fSDavid Howells if (IS_ERR(op)) 1931e49c7b2fSDavid Howells return PTR_ERR(op); 1932e49c7b2fSDavid Howells 19333978d816SDavid Howells ret = afs_validate(vnode, op->key); 19343978d816SDavid Howells op->error = ret; 19353978d816SDavid Howells if (ret < 0) 19363978d816SDavid Howells goto error; 19373978d816SDavid Howells 1938e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, orig_dvnode); 1939e49c7b2fSDavid Howells afs_op_set_vnode(op, 1, new_dvnode); /* May be same as orig_dvnode */ 1940e49c7b2fSDavid Howells op->file[0].dv_delta = 1; 1941e49c7b2fSDavid Howells op->file[1].dv_delta = 1; 194222650f14SDavid Howells op->file[0].modification = true; 194322650f14SDavid Howells op->file[1].modification = true; 1944da8d0755SDavid Howells op->file[0].update_ctime = true; 1945da8d0755SDavid Howells op->file[1].update_ctime = true; 1946e49c7b2fSDavid Howells 1947e49c7b2fSDavid Howells op->dentry = old_dentry; 1948e49c7b2fSDavid Howells op->dentry_2 = new_dentry; 1949e49c7b2fSDavid Howells op->rename.new_negative = d_is_negative(new_dentry); 1950e49c7b2fSDavid Howells op->ops = &afs_rename_operation; 1951e49c7b2fSDavid Howells 1952e49c7b2fSDavid Howells /* For non-directories, check whether the target is busy and if so, 1953e49c7b2fSDavid Howells * make a copy of the dentry and then do a silly-rename. If the 1954e49c7b2fSDavid Howells * silly-rename succeeds, the copied dentry is hashed and becomes the 1955e49c7b2fSDavid Howells * new target. 1956e49c7b2fSDavid Howells */ 1957e49c7b2fSDavid Howells if (d_is_positive(new_dentry) && !d_is_dir(new_dentry)) { 1958e49c7b2fSDavid Howells /* To prevent any new references to the target during the 1959e49c7b2fSDavid Howells * rename, we unhash the dentry in advance. 1960e49c7b2fSDavid Howells */ 1961e49c7b2fSDavid Howells if (!d_unhashed(new_dentry)) { 1962e49c7b2fSDavid Howells d_drop(new_dentry); 1963e49c7b2fSDavid Howells op->rename.rehash = new_dentry; 1964e49c7b2fSDavid Howells } 1965e49c7b2fSDavid Howells 1966e49c7b2fSDavid Howells if (d_count(new_dentry) > 2) { 1967e49c7b2fSDavid Howells /* copy the target dentry's name */ 1968e49c7b2fSDavid Howells op->rename.tmp = d_alloc(new_dentry->d_parent, 1969e49c7b2fSDavid Howells &new_dentry->d_name); 1970b4280812SJiapeng Chong if (!op->rename.tmp) { 1971b4280812SJiapeng Chong op->error = -ENOMEM; 1972e49c7b2fSDavid Howells goto error; 1973b4280812SJiapeng Chong } 1974e49c7b2fSDavid Howells 1975e49c7b2fSDavid Howells ret = afs_sillyrename(new_dvnode, 1976e49c7b2fSDavid Howells AFS_FS_I(d_inode(new_dentry)), 1977e49c7b2fSDavid Howells new_dentry, op->key); 1978b4280812SJiapeng Chong if (ret) { 1979b4280812SJiapeng Chong op->error = ret; 1980e49c7b2fSDavid Howells goto error; 1981b4280812SJiapeng Chong } 1982e49c7b2fSDavid Howells 1983e49c7b2fSDavid Howells op->dentry_2 = op->rename.tmp; 1984e49c7b2fSDavid Howells op->rename.rehash = NULL; 1985e49c7b2fSDavid Howells op->rename.new_negative = true; 1986e49c7b2fSDavid Howells } 1987e49c7b2fSDavid Howells } 1988e49c7b2fSDavid Howells 1989e49c7b2fSDavid Howells /* This bit is potentially nasty as there's a potential race with 1990e49c7b2fSDavid Howells * afs_d_revalidate{,_rcu}(). We have to change d_fsdata on the dentry 1991e49c7b2fSDavid Howells * to reflect it's new parent's new data_version after the op, but 1992e49c7b2fSDavid Howells * d_revalidate may see old_dentry between the op having taken place 1993e49c7b2fSDavid Howells * and the version being updated. 1994e49c7b2fSDavid Howells * 1995e49c7b2fSDavid Howells * So drop the old_dentry for now to make other threads go through 1996e49c7b2fSDavid Howells * lookup instead - which we hold a lock against. 1997e49c7b2fSDavid Howells */ 1998e49c7b2fSDavid Howells d_drop(old_dentry); 1999e49c7b2fSDavid Howells 2000e49c7b2fSDavid Howells return afs_do_sync_operation(op); 2001e49c7b2fSDavid Howells 2002260a9803SDavid Howells error: 2003e49c7b2fSDavid Howells return afs_put_operation(op); 2004260a9803SDavid Howells } 2005f3ddee8dSDavid Howells 2006f3ddee8dSDavid Howells /* 2007255ed636SDavid Howells * Release a directory folio and clean up its private state if it's not busy 2008255ed636SDavid Howells * - return true if the folio can now be released, false if not 2009f3ddee8dSDavid Howells */ 2010508cae68SMatthew Wilcox (Oracle) static bool afs_dir_release_folio(struct folio *folio, gfp_t gfp_flags) 2011f3ddee8dSDavid Howells { 2012255ed636SDavid Howells struct afs_vnode *dvnode = AFS_FS_I(folio_inode(folio)); 2013f3ddee8dSDavid Howells 2014255ed636SDavid Howells _enter("{{%llx:%llu}[%lu]}", dvnode->fid.vid, dvnode->fid.vnode, folio_index(folio)); 2015f3ddee8dSDavid Howells 2016255ed636SDavid Howells folio_detach_private(folio); 2017f3ddee8dSDavid Howells 2018f3ddee8dSDavid Howells /* The directory will need reloading. */ 2019f3ddee8dSDavid Howells if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) 2020f3ddee8dSDavid Howells afs_stat_v(dvnode, n_relpg); 2021255ed636SDavid Howells return true; 2022f3ddee8dSDavid Howells } 2023f3ddee8dSDavid Howells 2024f3ddee8dSDavid Howells /* 2025255ed636SDavid Howells * Invalidate part or all of a folio. 2026f3ddee8dSDavid Howells */ 2027f6bc6fb8SMatthew Wilcox (Oracle) static void afs_dir_invalidate_folio(struct folio *folio, size_t offset, 2028f6bc6fb8SMatthew Wilcox (Oracle) size_t length) 2029f3ddee8dSDavid Howells { 2030255ed636SDavid Howells struct afs_vnode *dvnode = AFS_FS_I(folio_inode(folio)); 2031f3ddee8dSDavid Howells 2032f6bc6fb8SMatthew Wilcox (Oracle) _enter("{%lu},%zu,%zu", folio->index, offset, length); 2033f3ddee8dSDavid Howells 2034255ed636SDavid Howells BUG_ON(!folio_test_locked(folio)); 2035f3ddee8dSDavid Howells 2036f3ddee8dSDavid Howells /* The directory will need reloading. */ 2037f3ddee8dSDavid Howells if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) 2038f3ddee8dSDavid Howells afs_stat_v(dvnode, n_inval); 2039f3ddee8dSDavid Howells 2040255ed636SDavid Howells /* we clean up only if the entire folio is being invalidated */ 2041255ed636SDavid Howells if (offset == 0 && length == folio_size(folio)) 2042255ed636SDavid Howells folio_detach_private(folio); 2043f3ddee8dSDavid Howells } 2044