1 /* 2 * Copyright (c) 2002 Red Hat, Inc. All rights reserved. 3 * 4 * This software may be freely redistributed under the terms of the 5 * GNU General Public License. 6 * 7 * You should have received a copy of the GNU General Public License 8 * along with this program; if not, write to the Free Software 9 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 10 * 11 * Authors: David Woodhouse <dwmw2@cambridge.redhat.com> 12 * David Howells <dhowells@redhat.com> 13 * 14 */ 15 16 #include <linux/kernel.h> 17 #include <linux/module.h> 18 #include <linux/init.h> 19 #include <linux/sched.h> 20 #include <linux/slab.h> 21 #include <linux/fs.h> 22 #include <linux/pagemap.h> 23 #include "volume.h" 24 #include "vnode.h" 25 #include "super.h" 26 #include "internal.h" 27 28 struct afs_iget_data { 29 struct afs_fid fid; 30 struct afs_volume *volume; /* volume on which resides */ 31 }; 32 33 /*****************************************************************************/ 34 /* 35 * map the AFS file status to the inode member variables 36 */ 37 static int afs_inode_map_status(struct afs_vnode *vnode) 38 { 39 struct inode *inode = AFS_VNODE_TO_I(vnode); 40 41 _debug("FS: ft=%d lk=%d sz=%Zu ver=%Lu mod=%hu", 42 vnode->status.type, 43 vnode->status.nlink, 44 vnode->status.size, 45 vnode->status.version, 46 vnode->status.mode); 47 48 switch (vnode->status.type) { 49 case AFS_FTYPE_FILE: 50 inode->i_mode = S_IFREG | vnode->status.mode; 51 inode->i_op = &afs_file_inode_operations; 52 inode->i_fop = &afs_file_file_operations; 53 break; 54 case AFS_FTYPE_DIR: 55 inode->i_mode = S_IFDIR | vnode->status.mode; 56 inode->i_op = &afs_dir_inode_operations; 57 inode->i_fop = &afs_dir_file_operations; 58 break; 59 case AFS_FTYPE_SYMLINK: 60 inode->i_mode = S_IFLNK | vnode->status.mode; 61 inode->i_op = &page_symlink_inode_operations; 62 break; 63 default: 64 printk("kAFS: AFS vnode with undefined type\n"); 65 return -EBADMSG; 66 } 67 68 inode->i_nlink = vnode->status.nlink; 69 inode->i_uid = vnode->status.owner; 70 inode->i_gid = 0; 71 inode->i_size = vnode->status.size; 72 inode->i_ctime.tv_sec = vnode->status.mtime_server; 73 inode->i_ctime.tv_nsec = 0; 74 inode->i_atime = inode->i_mtime = inode->i_ctime; 75 inode->i_blksize = PAGE_CACHE_SIZE; 76 inode->i_blocks = 0; 77 inode->i_version = vnode->fid.unique; 78 inode->i_mapping->a_ops = &afs_fs_aops; 79 80 /* check to see whether a symbolic link is really a mountpoint */ 81 if (vnode->status.type == AFS_FTYPE_SYMLINK) { 82 afs_mntpt_check_symlink(vnode); 83 84 if (vnode->flags & AFS_VNODE_MOUNTPOINT) { 85 inode->i_mode = S_IFDIR | vnode->status.mode; 86 inode->i_op = &afs_mntpt_inode_operations; 87 inode->i_fop = &afs_mntpt_file_operations; 88 } 89 } 90 91 return 0; 92 } /* end afs_inode_map_status() */ 93 94 /*****************************************************************************/ 95 /* 96 * attempt to fetch the status of an inode, coelescing multiple simultaneous 97 * fetches 98 */ 99 static int afs_inode_fetch_status(struct inode *inode) 100 { 101 struct afs_vnode *vnode; 102 int ret; 103 104 vnode = AFS_FS_I(inode); 105 106 ret = afs_vnode_fetch_status(vnode); 107 108 if (ret == 0) 109 ret = afs_inode_map_status(vnode); 110 111 return ret; 112 113 } /* end afs_inode_fetch_status() */ 114 115 /*****************************************************************************/ 116 /* 117 * iget5() comparator 118 */ 119 static int afs_iget5_test(struct inode *inode, void *opaque) 120 { 121 struct afs_iget_data *data = opaque; 122 123 return inode->i_ino == data->fid.vnode && 124 inode->i_version == data->fid.unique; 125 } /* end afs_iget5_test() */ 126 127 /*****************************************************************************/ 128 /* 129 * iget5() inode initialiser 130 */ 131 static int afs_iget5_set(struct inode *inode, void *opaque) 132 { 133 struct afs_iget_data *data = opaque; 134 struct afs_vnode *vnode = AFS_FS_I(inode); 135 136 inode->i_ino = data->fid.vnode; 137 inode->i_version = data->fid.unique; 138 vnode->fid = data->fid; 139 vnode->volume = data->volume; 140 141 return 0; 142 } /* end afs_iget5_set() */ 143 144 /*****************************************************************************/ 145 /* 146 * inode retrieval 147 */ 148 inline int afs_iget(struct super_block *sb, struct afs_fid *fid, 149 struct inode **_inode) 150 { 151 struct afs_iget_data data = { .fid = *fid }; 152 struct afs_super_info *as; 153 struct afs_vnode *vnode; 154 struct inode *inode; 155 int ret; 156 157 _enter(",{%u,%u,%u},,", fid->vid, fid->vnode, fid->unique); 158 159 as = sb->s_fs_info; 160 data.volume = as->volume; 161 162 inode = iget5_locked(sb, fid->vnode, afs_iget5_test, afs_iget5_set, 163 &data); 164 if (!inode) { 165 _leave(" = -ENOMEM"); 166 return -ENOMEM; 167 } 168 169 vnode = AFS_FS_I(inode); 170 171 /* deal with an existing inode */ 172 if (!(inode->i_state & I_NEW)) { 173 ret = afs_vnode_fetch_status(vnode); 174 if (ret==0) 175 *_inode = inode; 176 else 177 iput(inode); 178 _leave(" = %d", ret); 179 return ret; 180 } 181 182 #ifdef AFS_CACHING_SUPPORT 183 /* set up caching before reading the status, as fetch-status reads the 184 * first page of symlinks to see if they're really mntpts */ 185 cachefs_acquire_cookie(vnode->volume->cache, 186 NULL, 187 vnode, 188 &vnode->cache); 189 #endif 190 191 /* okay... it's a new inode */ 192 inode->i_flags |= S_NOATIME; 193 vnode->flags |= AFS_VNODE_CHANGED; 194 ret = afs_inode_fetch_status(inode); 195 if (ret<0) 196 goto bad_inode; 197 198 /* success */ 199 unlock_new_inode(inode); 200 201 *_inode = inode; 202 _leave(" = 0 [CB { v=%u x=%lu t=%u }]", 203 vnode->cb_version, 204 vnode->cb_timeout.timo_jif, 205 vnode->cb_type); 206 return 0; 207 208 /* failure */ 209 bad_inode: 210 make_bad_inode(inode); 211 unlock_new_inode(inode); 212 iput(inode); 213 214 _leave(" = %d [bad]", ret); 215 return ret; 216 } /* end afs_iget() */ 217 218 /*****************************************************************************/ 219 /* 220 * read the attributes of an inode 221 */ 222 int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, 223 struct kstat *stat) 224 { 225 struct afs_vnode *vnode; 226 struct inode *inode; 227 int ret; 228 229 inode = dentry->d_inode; 230 231 _enter("{ ino=%lu v=%lu }", inode->i_ino, inode->i_version); 232 233 vnode = AFS_FS_I(inode); 234 235 ret = afs_inode_fetch_status(inode); 236 if (ret == -ENOENT) { 237 _leave(" = %d [%d %p]", 238 ret, atomic_read(&dentry->d_count), dentry->d_inode); 239 return ret; 240 } 241 else if (ret < 0) { 242 make_bad_inode(inode); 243 _leave(" = %d", ret); 244 return ret; 245 } 246 247 /* transfer attributes from the inode structure to the stat 248 * structure */ 249 generic_fillattr(inode, stat); 250 251 _leave(" = 0 CB { v=%u x=%u t=%u }", 252 vnode->cb_version, 253 vnode->cb_expiry, 254 vnode->cb_type); 255 256 return 0; 257 } /* end afs_inode_getattr() */ 258 259 /*****************************************************************************/ 260 /* 261 * clear an AFS inode 262 */ 263 void afs_clear_inode(struct inode *inode) 264 { 265 struct afs_vnode *vnode; 266 267 vnode = AFS_FS_I(inode); 268 269 _enter("ino=%lu { vn=%08x v=%u x=%u t=%u }", 270 inode->i_ino, 271 vnode->fid.vnode, 272 vnode->cb_version, 273 vnode->cb_expiry, 274 vnode->cb_type 275 ); 276 277 BUG_ON(inode->i_ino != vnode->fid.vnode); 278 279 afs_vnode_give_up_callback(vnode); 280 281 #ifdef AFS_CACHING_SUPPORT 282 cachefs_relinquish_cookie(vnode->cache, 0); 283 vnode->cache = NULL; 284 #endif 285 286 _leave(""); 287 } /* end afs_clear_inode() */ 288