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/slab.h>
21 #include <linux/pagemap.h>
27 struct afs_iget_data
{
29 struct afs_volume
*volume
; /* volume on which resides */
32 /*****************************************************************************/
34 * map the AFS file status to the inode member variables
36 static int afs_inode_map_status(struct afs_vnode
*vnode
)
38 struct inode
*inode
= AFS_VNODE_TO_I(vnode
);
40 _debug("FS: ft=%d lk=%d sz=%Zu ver=%Lu mod=%hu",
44 vnode
->status
.version
,
47 switch (vnode
->status
.type
) {
49 inode
->i_mode
= S_IFREG
| vnode
->status
.mode
;
50 inode
->i_op
= &afs_file_inode_operations
;
51 inode
->i_fop
= &generic_ro_fops
;
54 inode
->i_mode
= S_IFDIR
| vnode
->status
.mode
;
55 inode
->i_op
= &afs_dir_inode_operations
;
56 inode
->i_fop
= &afs_dir_file_operations
;
58 case AFS_FTYPE_SYMLINK
:
59 inode
->i_mode
= S_IFLNK
| vnode
->status
.mode
;
60 inode
->i_op
= &page_symlink_inode_operations
;
63 printk("kAFS: AFS vnode with undefined type\n");
67 inode
->i_nlink
= vnode
->status
.nlink
;
68 inode
->i_uid
= vnode
->status
.owner
;
70 inode
->i_size
= vnode
->status
.size
;
71 inode
->i_ctime
.tv_sec
= vnode
->status
.mtime_server
;
72 inode
->i_ctime
.tv_nsec
= 0;
73 inode
->i_atime
= inode
->i_mtime
= inode
->i_ctime
;
75 inode
->i_version
= vnode
->fid
.unique
;
76 inode
->i_mapping
->a_ops
= &afs_fs_aops
;
78 /* check to see whether a symbolic link is really a mountpoint */
79 if (vnode
->status
.type
== AFS_FTYPE_SYMLINK
) {
80 afs_mntpt_check_symlink(vnode
);
82 if (vnode
->flags
& AFS_VNODE_MOUNTPOINT
) {
83 inode
->i_mode
= S_IFDIR
| vnode
->status
.mode
;
84 inode
->i_op
= &afs_mntpt_inode_operations
;
85 inode
->i_fop
= &afs_mntpt_file_operations
;
90 } /* end afs_inode_map_status() */
92 /*****************************************************************************/
94 * attempt to fetch the status of an inode, coelescing multiple simultaneous
97 static int afs_inode_fetch_status(struct inode
*inode
)
99 struct afs_vnode
*vnode
;
102 vnode
= AFS_FS_I(inode
);
104 ret
= afs_vnode_fetch_status(vnode
);
107 ret
= afs_inode_map_status(vnode
);
111 } /* end afs_inode_fetch_status() */
113 /*****************************************************************************/
117 static int afs_iget5_test(struct inode
*inode
, void *opaque
)
119 struct afs_iget_data
*data
= opaque
;
121 return inode
->i_ino
== data
->fid
.vnode
&&
122 inode
->i_version
== data
->fid
.unique
;
123 } /* end afs_iget5_test() */
125 /*****************************************************************************/
127 * iget5() inode initialiser
129 static int afs_iget5_set(struct inode
*inode
, void *opaque
)
131 struct afs_iget_data
*data
= opaque
;
132 struct afs_vnode
*vnode
= AFS_FS_I(inode
);
134 inode
->i_ino
= data
->fid
.vnode
;
135 inode
->i_version
= data
->fid
.unique
;
136 vnode
->fid
= data
->fid
;
137 vnode
->volume
= data
->volume
;
140 } /* end afs_iget5_set() */
142 /*****************************************************************************/
146 inline int afs_iget(struct super_block
*sb
, struct afs_fid
*fid
,
147 struct inode
**_inode
)
149 struct afs_iget_data data
= { .fid
= *fid
};
150 struct afs_super_info
*as
;
151 struct afs_vnode
*vnode
;
155 _enter(",{%u,%u,%u},,", fid
->vid
, fid
->vnode
, fid
->unique
);
158 data
.volume
= as
->volume
;
160 inode
= iget5_locked(sb
, fid
->vnode
, afs_iget5_test
, afs_iget5_set
,
163 _leave(" = -ENOMEM");
167 vnode
= AFS_FS_I(inode
);
169 /* deal with an existing inode */
170 if (!(inode
->i_state
& I_NEW
)) {
171 ret
= afs_vnode_fetch_status(vnode
);
176 _leave(" = %d", ret
);
180 #ifdef AFS_CACHING_SUPPORT
181 /* set up caching before reading the status, as fetch-status reads the
182 * first page of symlinks to see if they're really mntpts */
183 cachefs_acquire_cookie(vnode
->volume
->cache
,
189 /* okay... it's a new inode */
190 inode
->i_flags
|= S_NOATIME
;
191 vnode
->flags
|= AFS_VNODE_CHANGED
;
192 ret
= afs_inode_fetch_status(inode
);
197 unlock_new_inode(inode
);
200 _leave(" = 0 [CB { v=%u x=%lu t=%u }]",
202 vnode
->cb_timeout
.timo_jif
,
208 make_bad_inode(inode
);
209 unlock_new_inode(inode
);
212 _leave(" = %d [bad]", ret
);
214 } /* end afs_iget() */
216 /*****************************************************************************/
218 * read the attributes of an inode
220 int afs_inode_getattr(struct vfsmount
*mnt
, struct dentry
*dentry
,
223 struct afs_vnode
*vnode
;
227 inode
= dentry
->d_inode
;
229 _enter("{ ino=%lu v=%lu }", inode
->i_ino
, inode
->i_version
);
231 vnode
= AFS_FS_I(inode
);
233 ret
= afs_inode_fetch_status(inode
);
234 if (ret
== -ENOENT
) {
235 _leave(" = %d [%d %p]",
236 ret
, atomic_read(&dentry
->d_count
), dentry
->d_inode
);
240 make_bad_inode(inode
);
241 _leave(" = %d", ret
);
245 /* transfer attributes from the inode structure to the stat
247 generic_fillattr(inode
, stat
);
249 _leave(" = 0 CB { v=%u x=%u t=%u }",
255 } /* end afs_inode_getattr() */
257 /*****************************************************************************/
261 void afs_clear_inode(struct inode
*inode
)
263 struct afs_vnode
*vnode
;
265 vnode
= AFS_FS_I(inode
);
267 _enter("ino=%lu { vn=%08x v=%u x=%u t=%u }",
275 BUG_ON(inode
->i_ino
!= vnode
->fid
.vnode
);
277 afs_vnode_give_up_callback(vnode
);
279 #ifdef AFS_CACHING_SUPPORT
280 cachefs_relinquish_cookie(vnode
->cache
, 0);
285 } /* end afs_clear_inode() */