2 * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
4 * This software may be freely redistributed under the terms of the
5 * GNU General Public License.
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.
11 * Authors: David Woodhouse <dwmw2@cambridge.redhat.com>
12 * David Howells <dhowells@redhat.com>
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>
22 #include <linux/pagemap.h>
28 struct afs_iget_data
{
30 struct afs_volume
*volume
; /* volume on which resides */
33 /*****************************************************************************/
35 * map the AFS file status to the inode member variables
37 static int afs_inode_map_status(struct afs_vnode
*vnode
)
39 struct inode
*inode
= AFS_VNODE_TO_I(vnode
);
41 _debug("FS: ft=%d lk=%d sz=%Zu ver=%Lu mod=%hu",
45 vnode
->status
.version
,
48 switch (vnode
->status
.type
) {
50 inode
->i_mode
= S_IFREG
| vnode
->status
.mode
;
51 inode
->i_op
= &afs_file_inode_operations
;
52 inode
->i_fop
= &generic_ro_fops
;
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
;
59 case AFS_FTYPE_SYMLINK
:
60 inode
->i_mode
= S_IFLNK
| vnode
->status
.mode
;
61 inode
->i_op
= &page_symlink_inode_operations
;
64 printk("kAFS: AFS vnode with undefined type\n");
68 inode
->i_nlink
= vnode
->status
.nlink
;
69 inode
->i_uid
= vnode
->status
.owner
;
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
;
77 inode
->i_version
= vnode
->fid
.unique
;
78 inode
->i_mapping
->a_ops
= &afs_fs_aops
;
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
);
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
;
92 } /* end afs_inode_map_status() */
94 /*****************************************************************************/
96 * attempt to fetch the status of an inode, coelescing multiple simultaneous
99 static int afs_inode_fetch_status(struct inode
*inode
)
101 struct afs_vnode
*vnode
;
104 vnode
= AFS_FS_I(inode
);
106 ret
= afs_vnode_fetch_status(vnode
);
109 ret
= afs_inode_map_status(vnode
);
113 } /* end afs_inode_fetch_status() */
115 /*****************************************************************************/
119 static int afs_iget5_test(struct inode
*inode
, void *opaque
)
121 struct afs_iget_data
*data
= opaque
;
123 return inode
->i_ino
== data
->fid
.vnode
&&
124 inode
->i_version
== data
->fid
.unique
;
125 } /* end afs_iget5_test() */
127 /*****************************************************************************/
129 * iget5() inode initialiser
131 static int afs_iget5_set(struct inode
*inode
, void *opaque
)
133 struct afs_iget_data
*data
= opaque
;
134 struct afs_vnode
*vnode
= AFS_FS_I(inode
);
136 inode
->i_ino
= data
->fid
.vnode
;
137 inode
->i_version
= data
->fid
.unique
;
138 vnode
->fid
= data
->fid
;
139 vnode
->volume
= data
->volume
;
142 } /* end afs_iget5_set() */
144 /*****************************************************************************/
148 inline int afs_iget(struct super_block
*sb
, struct afs_fid
*fid
,
149 struct inode
**_inode
)
151 struct afs_iget_data data
= { .fid
= *fid
};
152 struct afs_super_info
*as
;
153 struct afs_vnode
*vnode
;
157 _enter(",{%u,%u,%u},,", fid
->vid
, fid
->vnode
, fid
->unique
);
160 data
.volume
= as
->volume
;
162 inode
= iget5_locked(sb
, fid
->vnode
, afs_iget5_test
, afs_iget5_set
,
165 _leave(" = -ENOMEM");
169 vnode
= AFS_FS_I(inode
);
171 /* deal with an existing inode */
172 if (!(inode
->i_state
& I_NEW
)) {
173 ret
= afs_vnode_fetch_status(vnode
);
178 _leave(" = %d", ret
);
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
,
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
);
199 unlock_new_inode(inode
);
202 _leave(" = 0 [CB { v=%u x=%lu t=%u }]",
204 vnode
->cb_timeout
.timo_jif
,
210 make_bad_inode(inode
);
211 unlock_new_inode(inode
);
214 _leave(" = %d [bad]", ret
);
216 } /* end afs_iget() */
218 /*****************************************************************************/
220 * read the attributes of an inode
222 int afs_inode_getattr(struct vfsmount
*mnt
, struct dentry
*dentry
,
225 struct afs_vnode
*vnode
;
229 inode
= dentry
->d_inode
;
231 _enter("{ ino=%lu v=%lu }", inode
->i_ino
, inode
->i_version
);
233 vnode
= AFS_FS_I(inode
);
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
);
242 make_bad_inode(inode
);
243 _leave(" = %d", ret
);
247 /* transfer attributes from the inode structure to the stat
249 generic_fillattr(inode
, stat
);
251 _leave(" = 0 CB { v=%u x=%u t=%u }",
257 } /* end afs_inode_getattr() */
259 /*****************************************************************************/
263 void afs_clear_inode(struct inode
*inode
)
265 struct afs_vnode
*vnode
;
267 vnode
= AFS_FS_I(inode
);
269 _enter("ino=%lu { vn=%08x v=%u x=%u t=%u }",
277 BUG_ON(inode
->i_ino
!= vnode
->fid
.vnode
);
279 afs_vnode_give_up_callback(vnode
);
281 #ifdef AFS_CACHING_SUPPORT
282 cachefs_relinquish_cookie(vnode
->cache
, 0);
287 } /* end afs_clear_inode() */