11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (c) 2002 Red Hat, Inc. All rights reserved. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * This software may be freely redistributed under the terms of the 51da177e4SLinus Torvalds * GNU General Public License. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 81da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 91da177e4SLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 101da177e4SLinus Torvalds * 1144d1b980SDavid Woodhouse * Authors: David Woodhouse <dwmw2@infradead.org> 121da177e4SLinus Torvalds * David Howells <dhowells@redhat.com> 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds */ 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds #include <linux/kernel.h> 171da177e4SLinus Torvalds #include <linux/module.h> 181da177e4SLinus Torvalds #include <linux/init.h> 191da177e4SLinus Torvalds #include <linux/fs.h> 201da177e4SLinus Torvalds #include <linux/pagemap.h> 21e8edc6e0SAlexey Dobriyan #include <linux/sched.h> 22bec5eb61Swanglei #include <linux/mount.h> 23bec5eb61Swanglei #include <linux/namei.h> 24a01179e6SJeff Layton #include <linux/iversion.h> 251da177e4SLinus Torvalds #include "internal.h" 261da177e4SLinus Torvalds 27d3e3b7eaSDavid Howells static const struct inode_operations afs_symlink_inode_operations = { 28d3e3b7eaSDavid Howells .get_link = page_get_link, 29d3e3b7eaSDavid Howells .listxattr = afs_listxattr, 30d3e3b7eaSDavid Howells }; 31d3e3b7eaSDavid Howells 32*b134d687SDavid Howells static noinline void dump_vnode(struct afs_vnode *vnode, struct afs_vnode *parent_vnode) 33*b134d687SDavid Howells { 34*b134d687SDavid Howells static unsigned long once_only; 35*b134d687SDavid Howells 36*b134d687SDavid Howells pr_warn("kAFS: AFS vnode with undefined type %u\n", 37*b134d687SDavid Howells vnode->status.type); 38*b134d687SDavid Howells pr_warn("kAFS: A=%d m=%o s=%llx v=%llx\n", 39*b134d687SDavid Howells vnode->status.abort_code, 40*b134d687SDavid Howells vnode->status.mode, 41*b134d687SDavid Howells vnode->status.size, 42*b134d687SDavid Howells vnode->status.data_version); 43*b134d687SDavid Howells pr_warn("kAFS: vnode %llx:%llx:%x\n", 44*b134d687SDavid Howells vnode->fid.vid, 45*b134d687SDavid Howells vnode->fid.vnode, 46*b134d687SDavid Howells vnode->fid.unique); 47*b134d687SDavid Howells if (parent_vnode) 48*b134d687SDavid Howells pr_warn("kAFS: dir %llx:%llx:%x\n", 49*b134d687SDavid Howells parent_vnode->fid.vid, 50*b134d687SDavid Howells parent_vnode->fid.vnode, 51*b134d687SDavid Howells parent_vnode->fid.unique); 52*b134d687SDavid Howells 53*b134d687SDavid Howells if (!test_and_set_bit(0, &once_only)) 54*b134d687SDavid Howells dump_stack(); 55*b134d687SDavid Howells } 56*b134d687SDavid Howells 571da177e4SLinus Torvalds /* 58dd9fbcb8SDavid Howells * Initialise an inode from the vnode status. 591da177e4SLinus Torvalds */ 60*b134d687SDavid Howells static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key, 61*b134d687SDavid Howells struct afs_vnode *parent_vnode) 621da177e4SLinus Torvalds { 631da177e4SLinus Torvalds struct inode *inode = AFS_VNODE_TO_I(vnode); 641da177e4SLinus Torvalds 65260a9803SDavid Howells _debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu", 661da177e4SLinus Torvalds vnode->status.type, 671da177e4SLinus Torvalds vnode->status.nlink, 68ba3e0e1aSDavid S. Miller (unsigned long long) vnode->status.size, 6908e0e7c8SDavid Howells vnode->status.data_version, 701da177e4SLinus Torvalds vnode->status.mode); 711da177e4SLinus Torvalds 72c435ee34SDavid Howells read_seqlock_excl(&vnode->cb_lock); 73c435ee34SDavid Howells 74dd9fbcb8SDavid Howells afs_update_inode_from_status(vnode, &vnode->status, NULL, 75dd9fbcb8SDavid Howells AFS_VNODE_NOT_YET_SET); 76dd9fbcb8SDavid Howells 771da177e4SLinus Torvalds switch (vnode->status.type) { 781da177e4SLinus Torvalds case AFS_FTYPE_FILE: 791da177e4SLinus Torvalds inode->i_mode = S_IFREG | vnode->status.mode; 801da177e4SLinus Torvalds inode->i_op = &afs_file_inode_operations; 8100d3b7a4SDavid Howells inode->i_fop = &afs_file_operations; 82f3ddee8dSDavid Howells inode->i_mapping->a_ops = &afs_fs_aops; 831da177e4SLinus Torvalds break; 841da177e4SLinus Torvalds case AFS_FTYPE_DIR: 851da177e4SLinus Torvalds inode->i_mode = S_IFDIR | vnode->status.mode; 861da177e4SLinus Torvalds inode->i_op = &afs_dir_inode_operations; 871da177e4SLinus Torvalds inode->i_fop = &afs_dir_file_operations; 88f3ddee8dSDavid Howells inode->i_mapping->a_ops = &afs_dir_aops; 891da177e4SLinus Torvalds break; 901da177e4SLinus Torvalds case AFS_FTYPE_SYMLINK: 91944c74f4SDavid Howells /* Symlinks with a mode of 0644 are actually mountpoints. */ 92944c74f4SDavid Howells if ((vnode->status.mode & 0777) == 0644) { 93944c74f4SDavid Howells inode->i_flags |= S_AUTOMOUNT; 94944c74f4SDavid Howells 95944c74f4SDavid Howells set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); 96944c74f4SDavid Howells 97944c74f4SDavid Howells inode->i_mode = S_IFDIR | 0555; 98944c74f4SDavid Howells inode->i_op = &afs_mntpt_inode_operations; 99944c74f4SDavid Howells inode->i_fop = &afs_mntpt_file_operations; 100f3ddee8dSDavid Howells inode->i_mapping->a_ops = &afs_fs_aops; 101944c74f4SDavid Howells } else { 1021da177e4SLinus Torvalds inode->i_mode = S_IFLNK | vnode->status.mode; 103d3e3b7eaSDavid Howells inode->i_op = &afs_symlink_inode_operations; 104f3ddee8dSDavid Howells inode->i_mapping->a_ops = &afs_fs_aops; 105944c74f4SDavid Howells } 10621fc61c7SAl Viro inode_nohighmem(inode); 1071da177e4SLinus Torvalds break; 1081da177e4SLinus Torvalds default: 109*b134d687SDavid Howells dump_vnode(vnode, parent_vnode); 110c435ee34SDavid Howells read_sequnlock_excl(&vnode->cb_lock); 111160cb957SDavid Howells return afs_protocol_error(NULL, -EBADMSG, afs_eproto_file_type); 1121da177e4SLinus Torvalds } 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds inode->i_blocks = 0; 115a4ff7401SDavid Howells vnode->invalid_before = vnode->status.data_version; 116c435ee34SDavid Howells 117c435ee34SDavid Howells read_sequnlock_excl(&vnode->cb_lock); 1181da177e4SLinus Torvalds return 0; 119ec26815aSDavid Howells } 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds /* 122d2ddc776SDavid Howells * Fetch file status from the volume. 123d2ddc776SDavid Howells */ 1240c3a5ac2SDavid Howells int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode) 125d2ddc776SDavid Howells { 126d2ddc776SDavid Howells struct afs_fs_cursor fc; 127d2ddc776SDavid Howells int ret; 128d2ddc776SDavid Howells 1293b6492dfSDavid Howells _enter("%s,{%llx:%llu.%u,S=%lx}", 130d2ddc776SDavid Howells vnode->volume->name, 131d2ddc776SDavid Howells vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique, 132d2ddc776SDavid Howells vnode->flags); 133d2ddc776SDavid Howells 134d2ddc776SDavid Howells ret = -ERESTARTSYS; 135d2ddc776SDavid Howells if (afs_begin_vnode_operation(&fc, vnode, key)) { 136d2ddc776SDavid Howells while (afs_select_fileserver(&fc)) { 13768251f0aSDavid Howells fc.cb_break = afs_calc_vnode_cb_break(vnode); 1380c3a5ac2SDavid Howells afs_fs_fetch_file_status(&fc, NULL, new_inode); 139d2ddc776SDavid Howells } 140d2ddc776SDavid Howells 141d2ddc776SDavid Howells afs_check_for_remote_deletion(&fc, fc.vnode); 142d2ddc776SDavid Howells afs_vnode_commit_status(&fc, vnode, fc.cb_break); 143d2ddc776SDavid Howells ret = afs_end_vnode_operation(&fc); 144d2ddc776SDavid Howells } 145d2ddc776SDavid Howells 146d2ddc776SDavid Howells _leave(" = %d", ret); 147d2ddc776SDavid Howells return ret; 148d2ddc776SDavid Howells } 149d2ddc776SDavid Howells 150d2ddc776SDavid Howells /* 1511da177e4SLinus Torvalds * iget5() comparator 1521da177e4SLinus Torvalds */ 153c435ee34SDavid Howells int afs_iget5_test(struct inode *inode, void *opaque) 1541da177e4SLinus Torvalds { 1551da177e4SLinus Torvalds struct afs_iget_data *data = opaque; 1563b6492dfSDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 1571da177e4SLinus Torvalds 1583b6492dfSDavid Howells return memcmp(&vnode->fid, &data->fid, sizeof(data->fid)) == 0; 159ec26815aSDavid Howells } 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds /* 162bec5eb61Swanglei * iget5() comparator for inode created by autocell operations 163bec5eb61Swanglei * 164bec5eb61Swanglei * These pseudo inodes don't match anything. 165bec5eb61Swanglei */ 1664d673da1SDavid Howells static int afs_iget5_pseudo_dir_test(struct inode *inode, void *opaque) 167bec5eb61Swanglei { 168bec5eb61Swanglei return 0; 169bec5eb61Swanglei } 170bec5eb61Swanglei 171bec5eb61Swanglei /* 1721da177e4SLinus Torvalds * iget5() inode initialiser 1731da177e4SLinus Torvalds */ 1741da177e4SLinus Torvalds static int afs_iget5_set(struct inode *inode, void *opaque) 1751da177e4SLinus Torvalds { 1761da177e4SLinus Torvalds struct afs_iget_data *data = opaque; 1771da177e4SLinus Torvalds struct afs_vnode *vnode = AFS_FS_I(inode); 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds vnode->fid = data->fid; 1801da177e4SLinus Torvalds vnode->volume = data->volume; 1811da177e4SLinus Torvalds 1823b6492dfSDavid Howells /* YFS supports 96-bit vnode IDs, but Linux only supports 1833b6492dfSDavid Howells * 64-bit inode numbers. 1843b6492dfSDavid Howells */ 1853b6492dfSDavid Howells inode->i_ino = data->fid.vnode; 1863b6492dfSDavid Howells inode->i_generation = data->fid.unique; 1871da177e4SLinus Torvalds return 0; 188ec26815aSDavid Howells } 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds /* 1914d673da1SDavid Howells * Create an inode for a dynamic root directory or an autocell dynamic 1924d673da1SDavid Howells * automount dir. 193bec5eb61Swanglei */ 1944d673da1SDavid Howells struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root) 195bec5eb61Swanglei { 196bec5eb61Swanglei struct afs_iget_data data; 197bec5eb61Swanglei struct afs_super_info *as; 198bec5eb61Swanglei struct afs_vnode *vnode; 199bec5eb61Swanglei struct inode *inode; 200bec5eb61Swanglei static atomic_t afs_autocell_ino; 201bec5eb61Swanglei 2024d673da1SDavid Howells _enter(""); 203bec5eb61Swanglei 204bec5eb61Swanglei as = sb->s_fs_info; 2054d673da1SDavid Howells if (as->volume) { 206bec5eb61Swanglei data.volume = as->volume; 207bec5eb61Swanglei data.fid.vid = as->volume->vid; 2084d673da1SDavid Howells } 2094d673da1SDavid Howells if (root) { 2104d673da1SDavid Howells data.fid.vnode = 1; 2114d673da1SDavid Howells data.fid.unique = 1; 2124d673da1SDavid Howells } else { 2134d673da1SDavid Howells data.fid.vnode = atomic_inc_return(&afs_autocell_ino); 214bec5eb61Swanglei data.fid.unique = 0; 2154d673da1SDavid Howells } 216bec5eb61Swanglei 2174d673da1SDavid Howells inode = iget5_locked(sb, data.fid.vnode, 2184d673da1SDavid Howells afs_iget5_pseudo_dir_test, afs_iget5_set, 219bec5eb61Swanglei &data); 220bec5eb61Swanglei if (!inode) { 221bec5eb61Swanglei _leave(" = -ENOMEM"); 222bec5eb61Swanglei return ERR_PTR(-ENOMEM); 223bec5eb61Swanglei } 224bec5eb61Swanglei 2253b6492dfSDavid Howells _debug("GOT INODE %p { ino=%lu, vl=%llx, vn=%llx, u=%x }", 226bec5eb61Swanglei inode, inode->i_ino, data.fid.vid, data.fid.vnode, 227bec5eb61Swanglei data.fid.unique); 228bec5eb61Swanglei 229bec5eb61Swanglei vnode = AFS_FS_I(inode); 230bec5eb61Swanglei 231bec5eb61Swanglei /* there shouldn't be an existing inode */ 232bec5eb61Swanglei BUG_ON(!(inode->i_state & I_NEW)); 233bec5eb61Swanglei 234bec5eb61Swanglei inode->i_size = 0; 235bec5eb61Swanglei inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 2364d673da1SDavid Howells if (root) { 2374d673da1SDavid Howells inode->i_op = &afs_dynroot_inode_operations; 2384d673da1SDavid Howells inode->i_fop = &afs_dynroot_file_operations; 2394d673da1SDavid Howells } else { 240bec5eb61Swanglei inode->i_op = &afs_autocell_inode_operations; 2414d673da1SDavid Howells } 242bfe86848SMiklos Szeredi set_nlink(inode, 2); 243a0a5386aSEric W. Biederman inode->i_uid = GLOBAL_ROOT_UID; 244a0a5386aSEric W. Biederman inode->i_gid = GLOBAL_ROOT_GID; 245ba25b81eSArnd Bergmann inode->i_ctime = inode->i_atime = inode->i_mtime = current_time(inode); 246bec5eb61Swanglei inode->i_blocks = 0; 247a01179e6SJeff Layton inode_set_iversion_raw(inode, 0); 248bec5eb61Swanglei inode->i_generation = 0; 249bec5eb61Swanglei 250bec5eb61Swanglei set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags); 2514d673da1SDavid Howells if (!root) { 252d18610b0SDavid Howells set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); 2534d673da1SDavid Howells inode->i_flags |= S_AUTOMOUNT; 2544d673da1SDavid Howells } 2554d673da1SDavid Howells 2564d673da1SDavid Howells inode->i_flags |= S_NOATIME; 257bec5eb61Swanglei unlock_new_inode(inode); 258bec5eb61Swanglei _leave(" = %p", inode); 259bec5eb61Swanglei return inode; 260bec5eb61Swanglei } 261bec5eb61Swanglei 262bec5eb61Swanglei /* 263402cb8ddSDavid Howells * Get a cache cookie for an inode. 264402cb8ddSDavid Howells */ 265402cb8ddSDavid Howells static void afs_get_inode_cache(struct afs_vnode *vnode) 266402cb8ddSDavid Howells { 267402cb8ddSDavid Howells #ifdef CONFIG_AFS_FSCACHE 268402cb8ddSDavid Howells struct { 269402cb8ddSDavid Howells u32 vnode_id; 270402cb8ddSDavid Howells u32 unique; 271402cb8ddSDavid Howells u32 vnode_id_ext[2]; /* Allow for a 96-bit key */ 272402cb8ddSDavid Howells } __packed key; 273402cb8ddSDavid Howells struct afs_vnode_cache_aux aux; 274402cb8ddSDavid Howells 275f3ddee8dSDavid Howells if (vnode->status.type == AFS_FTYPE_DIR) { 276f3ddee8dSDavid Howells vnode->cache = NULL; 277f3ddee8dSDavid Howells return; 278f3ddee8dSDavid Howells } 279f3ddee8dSDavid Howells 280402cb8ddSDavid Howells key.vnode_id = vnode->fid.vnode; 281402cb8ddSDavid Howells key.unique = vnode->fid.unique; 2823b6492dfSDavid Howells key.vnode_id_ext[0] = vnode->fid.vnode >> 32; 2833b6492dfSDavid Howells key.vnode_id_ext[1] = vnode->fid.vnode_hi; 284402cb8ddSDavid Howells aux.data_version = vnode->status.data_version; 285402cb8ddSDavid Howells 286402cb8ddSDavid Howells vnode->cache = fscache_acquire_cookie(vnode->volume->cache, 287402cb8ddSDavid Howells &afs_vnode_cache_index_def, 288402cb8ddSDavid Howells &key, sizeof(key), 289402cb8ddSDavid Howells &aux, sizeof(aux), 290ee1235a9SDavid Howells vnode, vnode->status.size, true); 291402cb8ddSDavid Howells #endif 292402cb8ddSDavid Howells } 293402cb8ddSDavid Howells 294402cb8ddSDavid Howells /* 2951da177e4SLinus Torvalds * inode retrieval 2961da177e4SLinus Torvalds */ 297260a9803SDavid Howells struct inode *afs_iget(struct super_block *sb, struct key *key, 298260a9803SDavid Howells struct afs_fid *fid, struct afs_file_status *status, 299*b134d687SDavid Howells struct afs_callback *cb, struct afs_cb_interest *cbi, 300*b134d687SDavid Howells struct afs_vnode *parent_vnode) 3011da177e4SLinus Torvalds { 3021da177e4SLinus Torvalds struct afs_iget_data data = { .fid = *fid }; 3031da177e4SLinus Torvalds struct afs_super_info *as; 3041da177e4SLinus Torvalds struct afs_vnode *vnode; 3051da177e4SLinus Torvalds struct inode *inode; 3061da177e4SLinus Torvalds int ret; 3071da177e4SLinus Torvalds 3083b6492dfSDavid Howells _enter(",{%llx:%llu.%u},,", fid->vid, fid->vnode, fid->unique); 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds as = sb->s_fs_info; 3111da177e4SLinus Torvalds data.volume = as->volume; 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds inode = iget5_locked(sb, fid->vnode, afs_iget5_test, afs_iget5_set, 3141da177e4SLinus Torvalds &data); 3151da177e4SLinus Torvalds if (!inode) { 3161da177e4SLinus Torvalds _leave(" = -ENOMEM"); 31708e0e7c8SDavid Howells return ERR_PTR(-ENOMEM); 3181da177e4SLinus Torvalds } 3191da177e4SLinus Torvalds 3203b6492dfSDavid Howells _debug("GOT INODE %p { vl=%llx vn=%llx, u=%x }", 32108e0e7c8SDavid Howells inode, fid->vid, fid->vnode, fid->unique); 32208e0e7c8SDavid Howells 3231da177e4SLinus Torvalds vnode = AFS_FS_I(inode); 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds /* deal with an existing inode */ 3261da177e4SLinus Torvalds if (!(inode->i_state & I_NEW)) { 32708e0e7c8SDavid Howells _leave(" = %p", inode); 32808e0e7c8SDavid Howells return inode; 3291da177e4SLinus Torvalds } 3301da177e4SLinus Torvalds 331260a9803SDavid Howells if (!status) { 332260a9803SDavid Howells /* it's a remotely extant inode */ 3330c3a5ac2SDavid Howells ret = afs_fetch_status(vnode, key, true); 33408e0e7c8SDavid Howells if (ret < 0) 33508e0e7c8SDavid Howells goto bad_inode; 336260a9803SDavid Howells } else { 337260a9803SDavid Howells /* it's an inode we just created */ 338260a9803SDavid Howells memcpy(&vnode->status, status, sizeof(vnode->status)); 339260a9803SDavid Howells 340260a9803SDavid Howells if (!cb) { 341260a9803SDavid Howells /* it's a symlink we just created (the fileserver 342260a9803SDavid Howells * didn't give us a callback) */ 343260a9803SDavid Howells vnode->cb_version = 0; 344260a9803SDavid Howells vnode->cb_type = 0; 34512d8e95aSDavid Howells vnode->cb_expires_at = ktime_get(); 346260a9803SDavid Howells } else { 347260a9803SDavid Howells vnode->cb_version = cb->version; 348260a9803SDavid Howells vnode->cb_type = cb->type; 34912d8e95aSDavid Howells vnode->cb_expires_at = cb->expires_at; 350d2ddc776SDavid Howells vnode->cb_interest = afs_get_cb_interest(cbi); 351c435ee34SDavid Howells set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); 352260a9803SDavid Howells } 353c435ee34SDavid Howells 354c435ee34SDavid Howells vnode->cb_expires_at += ktime_get_real_seconds(); 355260a9803SDavid Howells } 356260a9803SDavid Howells 357*b134d687SDavid Howells ret = afs_inode_init_from_status(vnode, key, parent_vnode); 3581da177e4SLinus Torvalds if (ret < 0) 3591da177e4SLinus Torvalds goto bad_inode; 3601da177e4SLinus Torvalds 3615800db81SDavid Howells afs_get_inode_cache(vnode); 3625800db81SDavid Howells 3631da177e4SLinus Torvalds /* success */ 364260a9803SDavid Howells clear_bit(AFS_VNODE_UNSET, &vnode->flags); 36508e0e7c8SDavid Howells inode->i_flags |= S_NOATIME; 3661da177e4SLinus Torvalds unlock_new_inode(inode); 36708e0e7c8SDavid Howells _leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type); 36808e0e7c8SDavid Howells return inode; 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds /* failure */ 3711da177e4SLinus Torvalds bad_inode: 372aa7fa240SDavid Howells iget_failed(inode); 3731da177e4SLinus Torvalds _leave(" = %d [bad]", ret); 37408e0e7c8SDavid Howells return ERR_PTR(ret); 375ec26815aSDavid Howells } 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds /* 378416351f2SDavid Howells * mark the data attached to an inode as obsolete due to a write on the server 379416351f2SDavid Howells * - might also want to ditch all the outstanding writes and dirty pages 380416351f2SDavid Howells */ 381416351f2SDavid Howells void afs_zap_data(struct afs_vnode *vnode) 382416351f2SDavid Howells { 3833b6492dfSDavid Howells _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode); 384416351f2SDavid Howells 385c1515999SDavid Howells #ifdef CONFIG_AFS_FSCACHE 386c1515999SDavid Howells fscache_invalidate(vnode->cache); 387c1515999SDavid Howells #endif 388c1515999SDavid Howells 389416351f2SDavid Howells /* nuke all the non-dirty pages that aren't locked, mapped or being 3900f300ca9SDavid Howells * written back in a regular file and completely discard the pages in a 3910f300ca9SDavid Howells * directory or symlink */ 3920f300ca9SDavid Howells if (S_ISREG(vnode->vfs_inode.i_mode)) 393416351f2SDavid Howells invalidate_remote_inode(&vnode->vfs_inode); 3940f300ca9SDavid Howells else 3950f300ca9SDavid Howells invalidate_inode_pages2(vnode->vfs_inode.i_mapping); 396416351f2SDavid Howells } 397416351f2SDavid Howells 398416351f2SDavid Howells /* 399260a9803SDavid Howells * validate a vnode/inode 400260a9803SDavid Howells * - there are several things we need to check 401260a9803SDavid Howells * - parent dir data changes (rm, rmdir, rename, mkdir, create, link, 402260a9803SDavid Howells * symlink) 403260a9803SDavid Howells * - parent dir metadata changed (security changes) 404260a9803SDavid Howells * - dentry data changed (write, truncate) 405260a9803SDavid Howells * - dentry metadata changed (security changes) 406260a9803SDavid Howells */ 407260a9803SDavid Howells int afs_validate(struct afs_vnode *vnode, struct key *key) 408260a9803SDavid Howells { 409c435ee34SDavid Howells time64_t now = ktime_get_real_seconds(); 410ae3b7361SDavid Howells bool valid; 411260a9803SDavid Howells int ret; 412260a9803SDavid Howells 4133b6492dfSDavid Howells _enter("{v={%llx:%llu} fl=%lx},%x", 414260a9803SDavid Howells vnode->fid.vid, vnode->fid.vnode, vnode->flags, 415260a9803SDavid Howells key_serial(key)); 416260a9803SDavid Howells 417c435ee34SDavid Howells /* Quickly check the callback state. Ideally, we'd use read_seqbegin 418c435ee34SDavid Howells * here, but we have no way to pass the net namespace to the RCU 419c435ee34SDavid Howells * cleanup for the server record. 420c435ee34SDavid Howells */ 421c435ee34SDavid Howells read_seqlock_excl(&vnode->cb_lock); 422c435ee34SDavid Howells 423c435ee34SDavid Howells if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { 42468251f0aSDavid Howells if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break || 42568251f0aSDavid Howells vnode->cb_v_break != vnode->volume->cb_v_break) { 426c435ee34SDavid Howells vnode->cb_s_break = vnode->cb_interest->server->cb_s_break; 42768251f0aSDavid Howells vnode->cb_v_break = vnode->volume->cb_v_break; 42868251f0aSDavid Howells valid = false; 42963a4681fSDavid Howells } else if (vnode->status.type == AFS_FTYPE_DIR && 430ae3b7361SDavid Howells (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) || 431ae3b7361SDavid Howells vnode->cb_expires_at - 10 <= now)) { 432ae3b7361SDavid Howells valid = false; 433ae3b7361SDavid Howells } else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) || 434ae3b7361SDavid Howells vnode->cb_expires_at - 10 <= now) { 435ae3b7361SDavid Howells valid = false; 436ae3b7361SDavid Howells } else { 437c435ee34SDavid Howells valid = true; 438260a9803SDavid Howells } 439c435ee34SDavid Howells } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { 440c435ee34SDavid Howells valid = true; 441ae3b7361SDavid Howells } else { 442ae3b7361SDavid Howells vnode->cb_v_break = vnode->volume->cb_v_break; 443ae3b7361SDavid Howells valid = false; 444260a9803SDavid Howells } 445260a9803SDavid Howells 446c435ee34SDavid Howells read_sequnlock_excl(&vnode->cb_lock); 447440fbc3aSDavid Howells 448440fbc3aSDavid Howells if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) 449440fbc3aSDavid Howells clear_nlink(&vnode->vfs_inode); 450440fbc3aSDavid Howells 451c435ee34SDavid Howells if (valid) 452260a9803SDavid Howells goto valid; 453260a9803SDavid Howells 454b61f7dcfSDavid Howells down_write(&vnode->validate_lock); 455260a9803SDavid Howells 456260a9803SDavid Howells /* if the promise has expired, we need to check the server again to get 457260a9803SDavid Howells * a new promise - note that if the (parent) directory's metadata was 458260a9803SDavid Howells * changed then the security may be different and we may no longer have 459260a9803SDavid Howells * access */ 460c435ee34SDavid Howells if (!test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { 461260a9803SDavid Howells _debug("not promised"); 4620c3a5ac2SDavid Howells ret = afs_fetch_status(vnode, key, false); 463c435ee34SDavid Howells if (ret < 0) { 464c435ee34SDavid Howells if (ret == -ENOENT) { 465c435ee34SDavid Howells set_bit(AFS_VNODE_DELETED, &vnode->flags); 466c435ee34SDavid Howells ret = -ESTALE; 467c435ee34SDavid Howells } 468260a9803SDavid Howells goto error_unlock; 469c435ee34SDavid Howells } 470260a9803SDavid Howells _debug("new promise [fl=%lx]", vnode->flags); 471260a9803SDavid Howells } 472260a9803SDavid Howells 473260a9803SDavid Howells if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { 474260a9803SDavid Howells _debug("file already deleted"); 475260a9803SDavid Howells ret = -ESTALE; 476260a9803SDavid Howells goto error_unlock; 477260a9803SDavid Howells } 478260a9803SDavid Howells 479260a9803SDavid Howells /* if the vnode's data version number changed then its contents are 480260a9803SDavid Howells * different */ 481416351f2SDavid Howells if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) 482416351f2SDavid Howells afs_zap_data(vnode); 483b61f7dcfSDavid Howells up_write(&vnode->validate_lock); 484260a9803SDavid Howells valid: 485260a9803SDavid Howells _leave(" = 0"); 486260a9803SDavid Howells return 0; 487260a9803SDavid Howells 488260a9803SDavid Howells error_unlock: 489b61f7dcfSDavid Howells up_write(&vnode->validate_lock); 490260a9803SDavid Howells _leave(" = %d", ret); 491260a9803SDavid Howells return ret; 492260a9803SDavid Howells } 493260a9803SDavid Howells 494260a9803SDavid Howells /* 4951da177e4SLinus Torvalds * read the attributes of an inode 4961da177e4SLinus Torvalds */ 497a528d35eSDavid Howells int afs_getattr(const struct path *path, struct kstat *stat, 498a528d35eSDavid Howells u32 request_mask, unsigned int query_flags) 4991da177e4SLinus Torvalds { 500a528d35eSDavid Howells struct inode *inode = d_inode(path->dentry); 501c435ee34SDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 502c435ee34SDavid Howells int seq = 0; 5031da177e4SLinus Torvalds 504d6e43f75SDavid Howells _enter("{ ino=%lu v=%u }", inode->i_ino, inode->i_generation); 5051da177e4SLinus Torvalds 506c435ee34SDavid Howells do { 507c435ee34SDavid Howells read_seqbegin_or_lock(&vnode->cb_lock, &seq); 5081da177e4SLinus Torvalds generic_fillattr(inode, stat); 509c435ee34SDavid Howells } while (need_seqretry(&vnode->cb_lock, seq)); 510c435ee34SDavid Howells 511c435ee34SDavid Howells done_seqretry(&vnode->cb_lock, seq); 5121da177e4SLinus Torvalds return 0; 513ec26815aSDavid Howells } 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds /* 516bec5eb61Swanglei * discard an AFS inode 517bec5eb61Swanglei */ 518bec5eb61Swanglei int afs_drop_inode(struct inode *inode) 519bec5eb61Swanglei { 520bec5eb61Swanglei _enter(""); 521bec5eb61Swanglei 522bec5eb61Swanglei if (test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(inode)->flags)) 523bec5eb61Swanglei return generic_delete_inode(inode); 524bec5eb61Swanglei else 525bec5eb61Swanglei return generic_drop_inode(inode); 526bec5eb61Swanglei } 527bec5eb61Swanglei 528bec5eb61Swanglei /* 5291da177e4SLinus Torvalds * clear an AFS inode 5301da177e4SLinus Torvalds */ 531b57922d9SAl Viro void afs_evict_inode(struct inode *inode) 5321da177e4SLinus Torvalds { 5331da177e4SLinus Torvalds struct afs_vnode *vnode; 5341da177e4SLinus Torvalds 5351da177e4SLinus Torvalds vnode = AFS_FS_I(inode); 5361da177e4SLinus Torvalds 5373b6492dfSDavid Howells _enter("{%llx:%llu.%d}", 538260a9803SDavid Howells vnode->fid.vid, 5391da177e4SLinus Torvalds vnode->fid.vnode, 540c435ee34SDavid Howells vnode->fid.unique); 5411da177e4SLinus Torvalds 54208e0e7c8SDavid Howells _debug("CLEAR INODE %p", inode); 5431da177e4SLinus Torvalds 54408e0e7c8SDavid Howells ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode); 54508e0e7c8SDavid Howells 54691b0abe3SJohannes Weiner truncate_inode_pages_final(&inode->i_data); 547dbd5768fSJan Kara clear_inode(inode); 548b57922d9SAl Viro 549c435ee34SDavid Howells if (vnode->cb_interest) { 550c435ee34SDavid Howells afs_put_cb_interest(afs_i2net(inode), vnode->cb_interest); 551c435ee34SDavid Howells vnode->cb_interest = NULL; 55208e0e7c8SDavid Howells } 55308e0e7c8SDavid Howells 5544343d008SDavid Howells while (!list_empty(&vnode->wb_keys)) { 5554343d008SDavid Howells struct afs_wb_key *wbk = list_entry(vnode->wb_keys.next, 5564343d008SDavid Howells struct afs_wb_key, vnode_link); 5574343d008SDavid Howells list_del(&wbk->vnode_link); 5584343d008SDavid Howells afs_put_wb_key(wbk); 5594343d008SDavid Howells } 5601da177e4SLinus Torvalds 5619b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE 562402cb8ddSDavid Howells { 563402cb8ddSDavid Howells struct afs_vnode_cache_aux aux; 564402cb8ddSDavid Howells 565402cb8ddSDavid Howells aux.data_version = vnode->status.data_version; 566402cb8ddSDavid Howells fscache_relinquish_cookie(vnode->cache, &aux, 567678edd09SDavid Howells test_bit(AFS_VNODE_DELETED, &vnode->flags)); 5681da177e4SLinus Torvalds vnode->cache = NULL; 569402cb8ddSDavid Howells } 5701da177e4SLinus Torvalds #endif 5711da177e4SLinus Torvalds 572fe342cf7SDavid Howells afs_put_permits(rcu_access_pointer(vnode->permit_cache)); 57379ddbfa5SDavid Howells key_put(vnode->silly_key); 57479ddbfa5SDavid Howells vnode->silly_key = NULL; 57559d49076SDavid Howells key_put(vnode->lock_key); 57659d49076SDavid Howells vnode->lock_key = NULL; 5771da177e4SLinus Torvalds _leave(""); 578ec26815aSDavid Howells } 57931143d5dSDavid Howells 58031143d5dSDavid Howells /* 58131143d5dSDavid Howells * set the attributes of an inode 58231143d5dSDavid Howells */ 58331143d5dSDavid Howells int afs_setattr(struct dentry *dentry, struct iattr *attr) 58431143d5dSDavid Howells { 585d2ddc776SDavid Howells struct afs_fs_cursor fc; 5862b0143b5SDavid Howells struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); 58731143d5dSDavid Howells struct key *key; 58831143d5dSDavid Howells int ret; 58931143d5dSDavid Howells 5903b6492dfSDavid Howells _enter("{%llx:%llu},{n=%pd},%x", 591a455589fSAl Viro vnode->fid.vid, vnode->fid.vnode, dentry, 59231143d5dSDavid Howells attr->ia_valid); 59331143d5dSDavid Howells 59431143d5dSDavid Howells if (!(attr->ia_valid & (ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID | 59531143d5dSDavid Howells ATTR_MTIME))) { 59631143d5dSDavid Howells _leave(" = 0 [unsupported]"); 59731143d5dSDavid Howells return 0; 59831143d5dSDavid Howells } 59931143d5dSDavid Howells 60031143d5dSDavid Howells /* flush any dirty data outstanding on a regular file */ 6014343d008SDavid Howells if (S_ISREG(vnode->vfs_inode.i_mode)) 60231143d5dSDavid Howells filemap_write_and_wait(vnode->vfs_inode.i_mapping); 60331143d5dSDavid Howells 60431143d5dSDavid Howells if (attr->ia_valid & ATTR_FILE) { 605215804a9SDavid Howells key = afs_file_key(attr->ia_file); 60631143d5dSDavid Howells } else { 60731143d5dSDavid Howells key = afs_request_key(vnode->volume->cell); 60831143d5dSDavid Howells if (IS_ERR(key)) { 60931143d5dSDavid Howells ret = PTR_ERR(key); 61031143d5dSDavid Howells goto error; 61131143d5dSDavid Howells } 61231143d5dSDavid Howells } 61331143d5dSDavid Howells 614d2ddc776SDavid Howells ret = -ERESTARTSYS; 615d2ddc776SDavid Howells if (afs_begin_vnode_operation(&fc, vnode, key)) { 616d2ddc776SDavid Howells while (afs_select_fileserver(&fc)) { 61768251f0aSDavid Howells fc.cb_break = afs_calc_vnode_cb_break(vnode); 618d2ddc776SDavid Howells afs_fs_setattr(&fc, attr); 619d2ddc776SDavid Howells } 620d2ddc776SDavid Howells 621d2ddc776SDavid Howells afs_check_for_remote_deletion(&fc, fc.vnode); 622d2ddc776SDavid Howells afs_vnode_commit_status(&fc, vnode, fc.cb_break); 623d2ddc776SDavid Howells ret = afs_end_vnode_operation(&fc); 624d2ddc776SDavid Howells } 625d2ddc776SDavid Howells 62631143d5dSDavid Howells if (!(attr->ia_valid & ATTR_FILE)) 62731143d5dSDavid Howells key_put(key); 62831143d5dSDavid Howells 62931143d5dSDavid Howells error: 63031143d5dSDavid Howells _leave(" = %d", ret); 63131143d5dSDavid Howells return ret; 63231143d5dSDavid Howells } 633