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 321da177e4SLinus Torvalds /* 33dd9fbcb8SDavid Howells * Initialise an inode from the vnode status. 341da177e4SLinus Torvalds */ 35dd9fbcb8SDavid Howells static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key) 361da177e4SLinus Torvalds { 371da177e4SLinus Torvalds struct inode *inode = AFS_VNODE_TO_I(vnode); 381da177e4SLinus Torvalds 39260a9803SDavid Howells _debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu", 401da177e4SLinus Torvalds vnode->status.type, 411da177e4SLinus Torvalds vnode->status.nlink, 42ba3e0e1aSDavid S. Miller (unsigned long long) vnode->status.size, 4308e0e7c8SDavid Howells vnode->status.data_version, 441da177e4SLinus Torvalds vnode->status.mode); 451da177e4SLinus Torvalds 46c435ee34SDavid Howells read_seqlock_excl(&vnode->cb_lock); 47c435ee34SDavid Howells 48dd9fbcb8SDavid Howells afs_update_inode_from_status(vnode, &vnode->status, NULL, 49dd9fbcb8SDavid Howells AFS_VNODE_NOT_YET_SET); 50dd9fbcb8SDavid Howells 511da177e4SLinus Torvalds switch (vnode->status.type) { 521da177e4SLinus Torvalds case AFS_FTYPE_FILE: 531da177e4SLinus Torvalds inode->i_mode = S_IFREG | vnode->status.mode; 541da177e4SLinus Torvalds inode->i_op = &afs_file_inode_operations; 5500d3b7a4SDavid Howells inode->i_fop = &afs_file_operations; 56f3ddee8dSDavid Howells inode->i_mapping->a_ops = &afs_fs_aops; 571da177e4SLinus Torvalds break; 581da177e4SLinus Torvalds case AFS_FTYPE_DIR: 591da177e4SLinus Torvalds inode->i_mode = S_IFDIR | vnode->status.mode; 601da177e4SLinus Torvalds inode->i_op = &afs_dir_inode_operations; 611da177e4SLinus Torvalds inode->i_fop = &afs_dir_file_operations; 62f3ddee8dSDavid Howells inode->i_mapping->a_ops = &afs_dir_aops; 631da177e4SLinus Torvalds break; 641da177e4SLinus Torvalds case AFS_FTYPE_SYMLINK: 65944c74f4SDavid Howells /* Symlinks with a mode of 0644 are actually mountpoints. */ 66944c74f4SDavid Howells if ((vnode->status.mode & 0777) == 0644) { 67944c74f4SDavid Howells inode->i_flags |= S_AUTOMOUNT; 68944c74f4SDavid Howells 69944c74f4SDavid Howells set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); 70944c74f4SDavid Howells 71944c74f4SDavid Howells inode->i_mode = S_IFDIR | 0555; 72944c74f4SDavid Howells inode->i_op = &afs_mntpt_inode_operations; 73944c74f4SDavid Howells inode->i_fop = &afs_mntpt_file_operations; 74f3ddee8dSDavid Howells inode->i_mapping->a_ops = &afs_fs_aops; 75944c74f4SDavid Howells } else { 761da177e4SLinus Torvalds inode->i_mode = S_IFLNK | vnode->status.mode; 77d3e3b7eaSDavid Howells inode->i_op = &afs_symlink_inode_operations; 78f3ddee8dSDavid Howells inode->i_mapping->a_ops = &afs_fs_aops; 79944c74f4SDavid Howells } 8021fc61c7SAl Viro inode_nohighmem(inode); 811da177e4SLinus Torvalds break; 821da177e4SLinus Torvalds default: 831da177e4SLinus Torvalds printk("kAFS: AFS vnode with undefined type\n"); 84c435ee34SDavid Howells read_sequnlock_excl(&vnode->cb_lock); 85160cb957SDavid Howells return afs_protocol_error(NULL, -EBADMSG, afs_eproto_file_type); 861da177e4SLinus Torvalds } 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds inode->i_blocks = 0; 89a4ff7401SDavid Howells vnode->invalid_before = vnode->status.data_version; 90c435ee34SDavid Howells 91c435ee34SDavid Howells read_sequnlock_excl(&vnode->cb_lock); 921da177e4SLinus Torvalds return 0; 93ec26815aSDavid Howells } 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds /* 96d2ddc776SDavid Howells * Fetch file status from the volume. 97d2ddc776SDavid Howells */ 980c3a5ac2SDavid Howells int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode) 99d2ddc776SDavid Howells { 100d2ddc776SDavid Howells struct afs_fs_cursor fc; 101d2ddc776SDavid Howells int ret; 102d2ddc776SDavid Howells 1033b6492dfSDavid Howells _enter("%s,{%llx:%llu.%u,S=%lx}", 104d2ddc776SDavid Howells vnode->volume->name, 105d2ddc776SDavid Howells vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique, 106d2ddc776SDavid Howells vnode->flags); 107d2ddc776SDavid Howells 108d2ddc776SDavid Howells ret = -ERESTARTSYS; 109d2ddc776SDavid Howells if (afs_begin_vnode_operation(&fc, vnode, key)) { 110d2ddc776SDavid Howells while (afs_select_fileserver(&fc)) { 11168251f0aSDavid Howells fc.cb_break = afs_calc_vnode_cb_break(vnode); 1120c3a5ac2SDavid Howells afs_fs_fetch_file_status(&fc, NULL, new_inode); 113d2ddc776SDavid Howells } 114d2ddc776SDavid Howells 115d2ddc776SDavid Howells afs_check_for_remote_deletion(&fc, fc.vnode); 116d2ddc776SDavid Howells afs_vnode_commit_status(&fc, vnode, fc.cb_break); 117d2ddc776SDavid Howells ret = afs_end_vnode_operation(&fc); 118d2ddc776SDavid Howells } 119d2ddc776SDavid Howells 120d2ddc776SDavid Howells _leave(" = %d", ret); 121d2ddc776SDavid Howells return ret; 122d2ddc776SDavid Howells } 123d2ddc776SDavid Howells 124d2ddc776SDavid Howells /* 1251da177e4SLinus Torvalds * iget5() comparator 1261da177e4SLinus Torvalds */ 127c435ee34SDavid Howells int afs_iget5_test(struct inode *inode, void *opaque) 1281da177e4SLinus Torvalds { 1291da177e4SLinus Torvalds struct afs_iget_data *data = opaque; 1303b6492dfSDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 1311da177e4SLinus Torvalds 1323b6492dfSDavid Howells return memcmp(&vnode->fid, &data->fid, sizeof(data->fid)) == 0; 133ec26815aSDavid Howells } 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds /* 136bec5eb61Swanglei * iget5() comparator for inode created by autocell operations 137bec5eb61Swanglei * 138bec5eb61Swanglei * These pseudo inodes don't match anything. 139bec5eb61Swanglei */ 1404d673da1SDavid Howells static int afs_iget5_pseudo_dir_test(struct inode *inode, void *opaque) 141bec5eb61Swanglei { 142bec5eb61Swanglei return 0; 143bec5eb61Swanglei } 144bec5eb61Swanglei 145bec5eb61Swanglei /* 1461da177e4SLinus Torvalds * iget5() inode initialiser 1471da177e4SLinus Torvalds */ 1481da177e4SLinus Torvalds static int afs_iget5_set(struct inode *inode, void *opaque) 1491da177e4SLinus Torvalds { 1501da177e4SLinus Torvalds struct afs_iget_data *data = opaque; 1511da177e4SLinus Torvalds struct afs_vnode *vnode = AFS_FS_I(inode); 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds vnode->fid = data->fid; 1541da177e4SLinus Torvalds vnode->volume = data->volume; 1551da177e4SLinus Torvalds 1563b6492dfSDavid Howells /* YFS supports 96-bit vnode IDs, but Linux only supports 1573b6492dfSDavid Howells * 64-bit inode numbers. 1583b6492dfSDavid Howells */ 1593b6492dfSDavid Howells inode->i_ino = data->fid.vnode; 1603b6492dfSDavid Howells inode->i_generation = data->fid.unique; 1611da177e4SLinus Torvalds return 0; 162ec26815aSDavid Howells } 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds /* 1654d673da1SDavid Howells * Create an inode for a dynamic root directory or an autocell dynamic 1664d673da1SDavid Howells * automount dir. 167bec5eb61Swanglei */ 1684d673da1SDavid Howells struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root) 169bec5eb61Swanglei { 170bec5eb61Swanglei struct afs_iget_data data; 171bec5eb61Swanglei struct afs_super_info *as; 172bec5eb61Swanglei struct afs_vnode *vnode; 173bec5eb61Swanglei struct inode *inode; 174bec5eb61Swanglei static atomic_t afs_autocell_ino; 175bec5eb61Swanglei 1764d673da1SDavid Howells _enter(""); 177bec5eb61Swanglei 178bec5eb61Swanglei as = sb->s_fs_info; 1794d673da1SDavid Howells if (as->volume) { 180bec5eb61Swanglei data.volume = as->volume; 181bec5eb61Swanglei data.fid.vid = as->volume->vid; 1824d673da1SDavid Howells } 1834d673da1SDavid Howells if (root) { 1844d673da1SDavid Howells data.fid.vnode = 1; 1854d673da1SDavid Howells data.fid.unique = 1; 1864d673da1SDavid Howells } else { 1874d673da1SDavid Howells data.fid.vnode = atomic_inc_return(&afs_autocell_ino); 188bec5eb61Swanglei data.fid.unique = 0; 1894d673da1SDavid Howells } 190bec5eb61Swanglei 1914d673da1SDavid Howells inode = iget5_locked(sb, data.fid.vnode, 1924d673da1SDavid Howells afs_iget5_pseudo_dir_test, afs_iget5_set, 193bec5eb61Swanglei &data); 194bec5eb61Swanglei if (!inode) { 195bec5eb61Swanglei _leave(" = -ENOMEM"); 196bec5eb61Swanglei return ERR_PTR(-ENOMEM); 197bec5eb61Swanglei } 198bec5eb61Swanglei 1993b6492dfSDavid Howells _debug("GOT INODE %p { ino=%lu, vl=%llx, vn=%llx, u=%x }", 200bec5eb61Swanglei inode, inode->i_ino, data.fid.vid, data.fid.vnode, 201bec5eb61Swanglei data.fid.unique); 202bec5eb61Swanglei 203bec5eb61Swanglei vnode = AFS_FS_I(inode); 204bec5eb61Swanglei 205bec5eb61Swanglei /* there shouldn't be an existing inode */ 206bec5eb61Swanglei BUG_ON(!(inode->i_state & I_NEW)); 207bec5eb61Swanglei 208bec5eb61Swanglei inode->i_size = 0; 209bec5eb61Swanglei inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 2104d673da1SDavid Howells if (root) { 2114d673da1SDavid Howells inode->i_op = &afs_dynroot_inode_operations; 2124d673da1SDavid Howells inode->i_fop = &afs_dynroot_file_operations; 2134d673da1SDavid Howells } else { 214bec5eb61Swanglei inode->i_op = &afs_autocell_inode_operations; 2154d673da1SDavid Howells } 216bfe86848SMiklos Szeredi set_nlink(inode, 2); 217a0a5386aSEric W. Biederman inode->i_uid = GLOBAL_ROOT_UID; 218a0a5386aSEric W. Biederman inode->i_gid = GLOBAL_ROOT_GID; 219bec5eb61Swanglei inode->i_ctime.tv_sec = get_seconds(); 220bec5eb61Swanglei inode->i_ctime.tv_nsec = 0; 221bec5eb61Swanglei inode->i_atime = inode->i_mtime = inode->i_ctime; 222bec5eb61Swanglei inode->i_blocks = 0; 223a01179e6SJeff Layton inode_set_iversion_raw(inode, 0); 224bec5eb61Swanglei inode->i_generation = 0; 225bec5eb61Swanglei 226bec5eb61Swanglei set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags); 2274d673da1SDavid Howells if (!root) { 228d18610b0SDavid Howells set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); 2294d673da1SDavid Howells inode->i_flags |= S_AUTOMOUNT; 2304d673da1SDavid Howells } 2314d673da1SDavid Howells 2324d673da1SDavid Howells inode->i_flags |= S_NOATIME; 233bec5eb61Swanglei unlock_new_inode(inode); 234bec5eb61Swanglei _leave(" = %p", inode); 235bec5eb61Swanglei return inode; 236bec5eb61Swanglei } 237bec5eb61Swanglei 238bec5eb61Swanglei /* 239402cb8ddSDavid Howells * Get a cache cookie for an inode. 240402cb8ddSDavid Howells */ 241402cb8ddSDavid Howells static void afs_get_inode_cache(struct afs_vnode *vnode) 242402cb8ddSDavid Howells { 243402cb8ddSDavid Howells #ifdef CONFIG_AFS_FSCACHE 244402cb8ddSDavid Howells struct { 245402cb8ddSDavid Howells u32 vnode_id; 246402cb8ddSDavid Howells u32 unique; 247402cb8ddSDavid Howells u32 vnode_id_ext[2]; /* Allow for a 96-bit key */ 248402cb8ddSDavid Howells } __packed key; 249402cb8ddSDavid Howells struct afs_vnode_cache_aux aux; 250402cb8ddSDavid Howells 251f3ddee8dSDavid Howells if (vnode->status.type == AFS_FTYPE_DIR) { 252f3ddee8dSDavid Howells vnode->cache = NULL; 253f3ddee8dSDavid Howells return; 254f3ddee8dSDavid Howells } 255f3ddee8dSDavid Howells 256402cb8ddSDavid Howells key.vnode_id = vnode->fid.vnode; 257402cb8ddSDavid Howells key.unique = vnode->fid.unique; 2583b6492dfSDavid Howells key.vnode_id_ext[0] = vnode->fid.vnode >> 32; 2593b6492dfSDavid Howells key.vnode_id_ext[1] = vnode->fid.vnode_hi; 260402cb8ddSDavid Howells aux.data_version = vnode->status.data_version; 261402cb8ddSDavid Howells 262402cb8ddSDavid Howells vnode->cache = fscache_acquire_cookie(vnode->volume->cache, 263402cb8ddSDavid Howells &afs_vnode_cache_index_def, 264402cb8ddSDavid Howells &key, sizeof(key), 265402cb8ddSDavid Howells &aux, sizeof(aux), 266ee1235a9SDavid Howells vnode, vnode->status.size, true); 267402cb8ddSDavid Howells #endif 268402cb8ddSDavid Howells } 269402cb8ddSDavid Howells 270402cb8ddSDavid Howells /* 2711da177e4SLinus Torvalds * inode retrieval 2721da177e4SLinus Torvalds */ 273260a9803SDavid Howells struct inode *afs_iget(struct super_block *sb, struct key *key, 274260a9803SDavid Howells struct afs_fid *fid, struct afs_file_status *status, 275d2ddc776SDavid Howells struct afs_callback *cb, struct afs_cb_interest *cbi) 2761da177e4SLinus Torvalds { 2771da177e4SLinus Torvalds struct afs_iget_data data = { .fid = *fid }; 2781da177e4SLinus Torvalds struct afs_super_info *as; 2791da177e4SLinus Torvalds struct afs_vnode *vnode; 2801da177e4SLinus Torvalds struct inode *inode; 2811da177e4SLinus Torvalds int ret; 2821da177e4SLinus Torvalds 2833b6492dfSDavid Howells _enter(",{%llx:%llu.%u},,", fid->vid, fid->vnode, fid->unique); 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds as = sb->s_fs_info; 2861da177e4SLinus Torvalds data.volume = as->volume; 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds inode = iget5_locked(sb, fid->vnode, afs_iget5_test, afs_iget5_set, 2891da177e4SLinus Torvalds &data); 2901da177e4SLinus Torvalds if (!inode) { 2911da177e4SLinus Torvalds _leave(" = -ENOMEM"); 29208e0e7c8SDavid Howells return ERR_PTR(-ENOMEM); 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 2953b6492dfSDavid Howells _debug("GOT INODE %p { vl=%llx vn=%llx, u=%x }", 29608e0e7c8SDavid Howells inode, fid->vid, fid->vnode, fid->unique); 29708e0e7c8SDavid Howells 2981da177e4SLinus Torvalds vnode = AFS_FS_I(inode); 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds /* deal with an existing inode */ 3011da177e4SLinus Torvalds if (!(inode->i_state & I_NEW)) { 30208e0e7c8SDavid Howells _leave(" = %p", inode); 30308e0e7c8SDavid Howells return inode; 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds 306260a9803SDavid Howells if (!status) { 307260a9803SDavid Howells /* it's a remotely extant inode */ 3080c3a5ac2SDavid Howells ret = afs_fetch_status(vnode, key, true); 30908e0e7c8SDavid Howells if (ret < 0) 31008e0e7c8SDavid Howells goto bad_inode; 311260a9803SDavid Howells } else { 312260a9803SDavid Howells /* it's an inode we just created */ 313260a9803SDavid Howells memcpy(&vnode->status, status, sizeof(vnode->status)); 314260a9803SDavid Howells 315260a9803SDavid Howells if (!cb) { 316260a9803SDavid Howells /* it's a symlink we just created (the fileserver 317260a9803SDavid Howells * didn't give us a callback) */ 318260a9803SDavid Howells vnode->cb_version = 0; 319260a9803SDavid Howells vnode->cb_type = 0; 32012d8e95aSDavid Howells vnode->cb_expires_at = ktime_get(); 321260a9803SDavid Howells } else { 322260a9803SDavid Howells vnode->cb_version = cb->version; 323260a9803SDavid Howells vnode->cb_type = cb->type; 32412d8e95aSDavid Howells vnode->cb_expires_at = cb->expires_at; 325d2ddc776SDavid Howells vnode->cb_interest = afs_get_cb_interest(cbi); 326c435ee34SDavid Howells set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); 327260a9803SDavid Howells } 328c435ee34SDavid Howells 329c435ee34SDavid Howells vnode->cb_expires_at += ktime_get_real_seconds(); 330260a9803SDavid Howells } 331260a9803SDavid Howells 332dd9fbcb8SDavid Howells ret = afs_inode_init_from_status(vnode, key); 3331da177e4SLinus Torvalds if (ret < 0) 3341da177e4SLinus Torvalds goto bad_inode; 3351da177e4SLinus Torvalds 3365800db81SDavid Howells afs_get_inode_cache(vnode); 3375800db81SDavid Howells 3381da177e4SLinus Torvalds /* success */ 339260a9803SDavid Howells clear_bit(AFS_VNODE_UNSET, &vnode->flags); 34008e0e7c8SDavid Howells inode->i_flags |= S_NOATIME; 3411da177e4SLinus Torvalds unlock_new_inode(inode); 34208e0e7c8SDavid Howells _leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type); 34308e0e7c8SDavid Howells return inode; 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds /* failure */ 3461da177e4SLinus Torvalds bad_inode: 347aa7fa240SDavid Howells iget_failed(inode); 3481da177e4SLinus Torvalds _leave(" = %d [bad]", ret); 34908e0e7c8SDavid Howells return ERR_PTR(ret); 350ec26815aSDavid Howells } 3511da177e4SLinus Torvalds 3521da177e4SLinus Torvalds /* 353416351f2SDavid Howells * mark the data attached to an inode as obsolete due to a write on the server 354416351f2SDavid Howells * - might also want to ditch all the outstanding writes and dirty pages 355416351f2SDavid Howells */ 356416351f2SDavid Howells void afs_zap_data(struct afs_vnode *vnode) 357416351f2SDavid Howells { 3583b6492dfSDavid Howells _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode); 359416351f2SDavid Howells 360c1515999SDavid Howells #ifdef CONFIG_AFS_FSCACHE 361c1515999SDavid Howells fscache_invalidate(vnode->cache); 362c1515999SDavid Howells #endif 363c1515999SDavid Howells 364416351f2SDavid Howells /* nuke all the non-dirty pages that aren't locked, mapped or being 3650f300ca9SDavid Howells * written back in a regular file and completely discard the pages in a 3660f300ca9SDavid Howells * directory or symlink */ 3670f300ca9SDavid Howells if (S_ISREG(vnode->vfs_inode.i_mode)) 368416351f2SDavid Howells invalidate_remote_inode(&vnode->vfs_inode); 3690f300ca9SDavid Howells else 3700f300ca9SDavid Howells invalidate_inode_pages2(vnode->vfs_inode.i_mapping); 371416351f2SDavid Howells } 372416351f2SDavid Howells 373416351f2SDavid Howells /* 374260a9803SDavid Howells * validate a vnode/inode 375260a9803SDavid Howells * - there are several things we need to check 376260a9803SDavid Howells * - parent dir data changes (rm, rmdir, rename, mkdir, create, link, 377260a9803SDavid Howells * symlink) 378260a9803SDavid Howells * - parent dir metadata changed (security changes) 379260a9803SDavid Howells * - dentry data changed (write, truncate) 380260a9803SDavid Howells * - dentry metadata changed (security changes) 381260a9803SDavid Howells */ 382260a9803SDavid Howells int afs_validate(struct afs_vnode *vnode, struct key *key) 383260a9803SDavid Howells { 384c435ee34SDavid Howells time64_t now = ktime_get_real_seconds(); 385ae3b7361SDavid Howells bool valid; 386260a9803SDavid Howells int ret; 387260a9803SDavid Howells 3883b6492dfSDavid Howells _enter("{v={%llx:%llu} fl=%lx},%x", 389260a9803SDavid Howells vnode->fid.vid, vnode->fid.vnode, vnode->flags, 390260a9803SDavid Howells key_serial(key)); 391260a9803SDavid Howells 392c435ee34SDavid Howells /* Quickly check the callback state. Ideally, we'd use read_seqbegin 393c435ee34SDavid Howells * here, but we have no way to pass the net namespace to the RCU 394c435ee34SDavid Howells * cleanup for the server record. 395c435ee34SDavid Howells */ 396c435ee34SDavid Howells read_seqlock_excl(&vnode->cb_lock); 397c435ee34SDavid Howells 398c435ee34SDavid Howells if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { 39968251f0aSDavid Howells if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break || 40068251f0aSDavid Howells vnode->cb_v_break != vnode->volume->cb_v_break) { 401c435ee34SDavid Howells vnode->cb_s_break = vnode->cb_interest->server->cb_s_break; 40268251f0aSDavid Howells vnode->cb_v_break = vnode->volume->cb_v_break; 40368251f0aSDavid Howells valid = false; 40463a4681fSDavid Howells } else if (vnode->status.type == AFS_FTYPE_DIR && 405ae3b7361SDavid Howells (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) || 406ae3b7361SDavid Howells vnode->cb_expires_at - 10 <= now)) { 407ae3b7361SDavid Howells valid = false; 408ae3b7361SDavid Howells } else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) || 409ae3b7361SDavid Howells vnode->cb_expires_at - 10 <= now) { 410ae3b7361SDavid Howells valid = false; 411ae3b7361SDavid Howells } else { 412c435ee34SDavid Howells valid = true; 413260a9803SDavid Howells } 414c435ee34SDavid Howells } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { 415c435ee34SDavid Howells valid = true; 416ae3b7361SDavid Howells } else { 417ae3b7361SDavid Howells vnode->cb_v_break = vnode->volume->cb_v_break; 418ae3b7361SDavid Howells valid = false; 419260a9803SDavid Howells } 420260a9803SDavid Howells 421c435ee34SDavid Howells read_sequnlock_excl(&vnode->cb_lock); 422440fbc3aSDavid Howells 423440fbc3aSDavid Howells if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) 424440fbc3aSDavid Howells clear_nlink(&vnode->vfs_inode); 425440fbc3aSDavid Howells 426c435ee34SDavid Howells if (valid) 427260a9803SDavid Howells goto valid; 428260a9803SDavid Howells 429b61f7dcfSDavid Howells down_write(&vnode->validate_lock); 430260a9803SDavid Howells 431260a9803SDavid Howells /* if the promise has expired, we need to check the server again to get 432260a9803SDavid Howells * a new promise - note that if the (parent) directory's metadata was 433260a9803SDavid Howells * changed then the security may be different and we may no longer have 434260a9803SDavid Howells * access */ 435c435ee34SDavid Howells if (!test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { 436260a9803SDavid Howells _debug("not promised"); 4370c3a5ac2SDavid Howells ret = afs_fetch_status(vnode, key, false); 438c435ee34SDavid Howells if (ret < 0) { 439c435ee34SDavid Howells if (ret == -ENOENT) { 440c435ee34SDavid Howells set_bit(AFS_VNODE_DELETED, &vnode->flags); 441c435ee34SDavid Howells ret = -ESTALE; 442c435ee34SDavid Howells } 443260a9803SDavid Howells goto error_unlock; 444c435ee34SDavid Howells } 445260a9803SDavid Howells _debug("new promise [fl=%lx]", vnode->flags); 446260a9803SDavid Howells } 447260a9803SDavid Howells 448260a9803SDavid Howells if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { 449260a9803SDavid Howells _debug("file already deleted"); 450260a9803SDavid Howells ret = -ESTALE; 451260a9803SDavid Howells goto error_unlock; 452260a9803SDavid Howells } 453260a9803SDavid Howells 454260a9803SDavid Howells /* if the vnode's data version number changed then its contents are 455260a9803SDavid Howells * different */ 456416351f2SDavid Howells if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) 457416351f2SDavid Howells afs_zap_data(vnode); 458b61f7dcfSDavid Howells up_write(&vnode->validate_lock); 459260a9803SDavid Howells valid: 460260a9803SDavid Howells _leave(" = 0"); 461260a9803SDavid Howells return 0; 462260a9803SDavid Howells 463260a9803SDavid Howells error_unlock: 464b61f7dcfSDavid Howells up_write(&vnode->validate_lock); 465260a9803SDavid Howells _leave(" = %d", ret); 466260a9803SDavid Howells return ret; 467260a9803SDavid Howells } 468260a9803SDavid Howells 469260a9803SDavid Howells /* 4701da177e4SLinus Torvalds * read the attributes of an inode 4711da177e4SLinus Torvalds */ 472a528d35eSDavid Howells int afs_getattr(const struct path *path, struct kstat *stat, 473a528d35eSDavid Howells u32 request_mask, unsigned int query_flags) 4741da177e4SLinus Torvalds { 475a528d35eSDavid Howells struct inode *inode = d_inode(path->dentry); 476c435ee34SDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 477c435ee34SDavid Howells int seq = 0; 4781da177e4SLinus Torvalds 479d6e43f75SDavid Howells _enter("{ ino=%lu v=%u }", inode->i_ino, inode->i_generation); 4801da177e4SLinus Torvalds 481c435ee34SDavid Howells do { 482c435ee34SDavid Howells read_seqbegin_or_lock(&vnode->cb_lock, &seq); 4831da177e4SLinus Torvalds generic_fillattr(inode, stat); 484c435ee34SDavid Howells } while (need_seqretry(&vnode->cb_lock, seq)); 485c435ee34SDavid Howells 486c435ee34SDavid Howells done_seqretry(&vnode->cb_lock, seq); 4871da177e4SLinus Torvalds return 0; 488ec26815aSDavid Howells } 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds /* 491bec5eb61Swanglei * discard an AFS inode 492bec5eb61Swanglei */ 493bec5eb61Swanglei int afs_drop_inode(struct inode *inode) 494bec5eb61Swanglei { 495bec5eb61Swanglei _enter(""); 496bec5eb61Swanglei 497bec5eb61Swanglei if (test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(inode)->flags)) 498bec5eb61Swanglei return generic_delete_inode(inode); 499bec5eb61Swanglei else 500bec5eb61Swanglei return generic_drop_inode(inode); 501bec5eb61Swanglei } 502bec5eb61Swanglei 503bec5eb61Swanglei /* 5041da177e4SLinus Torvalds * clear an AFS inode 5051da177e4SLinus Torvalds */ 506b57922d9SAl Viro void afs_evict_inode(struct inode *inode) 5071da177e4SLinus Torvalds { 5081da177e4SLinus Torvalds struct afs_vnode *vnode; 5091da177e4SLinus Torvalds 5101da177e4SLinus Torvalds vnode = AFS_FS_I(inode); 5111da177e4SLinus Torvalds 5123b6492dfSDavid Howells _enter("{%llx:%llu.%d}", 513260a9803SDavid Howells vnode->fid.vid, 5141da177e4SLinus Torvalds vnode->fid.vnode, 515c435ee34SDavid Howells vnode->fid.unique); 5161da177e4SLinus Torvalds 51708e0e7c8SDavid Howells _debug("CLEAR INODE %p", inode); 5181da177e4SLinus Torvalds 51908e0e7c8SDavid Howells ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode); 52008e0e7c8SDavid Howells 52191b0abe3SJohannes Weiner truncate_inode_pages_final(&inode->i_data); 522dbd5768fSJan Kara clear_inode(inode); 523b57922d9SAl Viro 524c435ee34SDavid Howells if (vnode->cb_interest) { 525c435ee34SDavid Howells afs_put_cb_interest(afs_i2net(inode), vnode->cb_interest); 526c435ee34SDavid Howells vnode->cb_interest = NULL; 52708e0e7c8SDavid Howells } 52808e0e7c8SDavid Howells 5294343d008SDavid Howells while (!list_empty(&vnode->wb_keys)) { 5304343d008SDavid Howells struct afs_wb_key *wbk = list_entry(vnode->wb_keys.next, 5314343d008SDavid Howells struct afs_wb_key, vnode_link); 5324343d008SDavid Howells list_del(&wbk->vnode_link); 5334343d008SDavid Howells afs_put_wb_key(wbk); 5344343d008SDavid Howells } 5351da177e4SLinus Torvalds 5369b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE 537402cb8ddSDavid Howells { 538402cb8ddSDavid Howells struct afs_vnode_cache_aux aux; 539402cb8ddSDavid Howells 540402cb8ddSDavid Howells aux.data_version = vnode->status.data_version; 541402cb8ddSDavid Howells fscache_relinquish_cookie(vnode->cache, &aux, 542678edd09SDavid Howells test_bit(AFS_VNODE_DELETED, &vnode->flags)); 5431da177e4SLinus Torvalds vnode->cache = NULL; 544402cb8ddSDavid Howells } 5451da177e4SLinus Torvalds #endif 5461da177e4SLinus Torvalds 547fe342cf7SDavid Howells afs_put_permits(rcu_access_pointer(vnode->permit_cache)); 548*59d49076SDavid Howells key_put(vnode->lock_key); 549*59d49076SDavid Howells vnode->lock_key = NULL; 5501da177e4SLinus Torvalds _leave(""); 551ec26815aSDavid Howells } 55231143d5dSDavid Howells 55331143d5dSDavid Howells /* 55431143d5dSDavid Howells * set the attributes of an inode 55531143d5dSDavid Howells */ 55631143d5dSDavid Howells int afs_setattr(struct dentry *dentry, struct iattr *attr) 55731143d5dSDavid Howells { 558d2ddc776SDavid Howells struct afs_fs_cursor fc; 5592b0143b5SDavid Howells struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); 56031143d5dSDavid Howells struct key *key; 56131143d5dSDavid Howells int ret; 56231143d5dSDavid Howells 5633b6492dfSDavid Howells _enter("{%llx:%llu},{n=%pd},%x", 564a455589fSAl Viro vnode->fid.vid, vnode->fid.vnode, dentry, 56531143d5dSDavid Howells attr->ia_valid); 56631143d5dSDavid Howells 56731143d5dSDavid Howells if (!(attr->ia_valid & (ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID | 56831143d5dSDavid Howells ATTR_MTIME))) { 56931143d5dSDavid Howells _leave(" = 0 [unsupported]"); 57031143d5dSDavid Howells return 0; 57131143d5dSDavid Howells } 57231143d5dSDavid Howells 57331143d5dSDavid Howells /* flush any dirty data outstanding on a regular file */ 5744343d008SDavid Howells if (S_ISREG(vnode->vfs_inode.i_mode)) 57531143d5dSDavid Howells filemap_write_and_wait(vnode->vfs_inode.i_mapping); 57631143d5dSDavid Howells 57731143d5dSDavid Howells if (attr->ia_valid & ATTR_FILE) { 578215804a9SDavid Howells key = afs_file_key(attr->ia_file); 57931143d5dSDavid Howells } else { 58031143d5dSDavid Howells key = afs_request_key(vnode->volume->cell); 58131143d5dSDavid Howells if (IS_ERR(key)) { 58231143d5dSDavid Howells ret = PTR_ERR(key); 58331143d5dSDavid Howells goto error; 58431143d5dSDavid Howells } 58531143d5dSDavid Howells } 58631143d5dSDavid Howells 587d2ddc776SDavid Howells ret = -ERESTARTSYS; 588d2ddc776SDavid Howells if (afs_begin_vnode_operation(&fc, vnode, key)) { 589d2ddc776SDavid Howells while (afs_select_fileserver(&fc)) { 59068251f0aSDavid Howells fc.cb_break = afs_calc_vnode_cb_break(vnode); 591d2ddc776SDavid Howells afs_fs_setattr(&fc, attr); 592d2ddc776SDavid Howells } 593d2ddc776SDavid Howells 594d2ddc776SDavid Howells afs_check_for_remote_deletion(&fc, fc.vnode); 595d2ddc776SDavid Howells afs_vnode_commit_status(&fc, vnode, fc.cb_break); 596d2ddc776SDavid Howells ret = afs_end_vnode_operation(&fc); 597d2ddc776SDavid Howells } 598d2ddc776SDavid Howells 59931143d5dSDavid Howells if (!(attr->ia_valid & ATTR_FILE)) 60031143d5dSDavid Howells key_put(key); 60131143d5dSDavid Howells 60231143d5dSDavid Howells error: 60331143d5dSDavid Howells _leave(" = %d", ret); 60431143d5dSDavid Howells return ret; 60531143d5dSDavid Howells } 606