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
;
76 inode
->i_version
= vnode
->fid
.unique
;
77 inode
->i_mapping
->a_ops
= &afs_fs_aops
;
79 /* check to see whether a symbolic link is really a mountpoint */
80 if (vnode
->status
.type
== AFS_FTYPE_SYMLINK
) {
81 afs_mntpt_check_symlink(vnode
);
83 if (vnode
->flags
& AFS_VNODE_MOUNTPOINT
) {
84 inode
->i_mode
= S_IFDIR
| vnode
->status
.mode
;
85 inode
->i_op
= &afs_mntpt_inode_operations
;
86 inode
->i_fop
= &afs_mntpt_file_operations
;
91 } /* end afs_inode_map_status() */
93 /*****************************************************************************/
95 * attempt to fetch the status of an inode, coelescing multiple simultaneous
98 static int afs_inode_fetch_status(struct inode
*inode
)
100 struct afs_vnode
*vnode
;
103 vnode
= AFS_FS_I(inode
);
105 ret
= afs_vnode_fetch_status(vnode
);
108 ret
= afs_inode_map_status(vnode
);
112 } /* end afs_inode_fetch_status() */
114 /*****************************************************************************/
118 static int afs_iget5_test(struct inode
*inode
, void *opaque
)
120 struct afs_iget_data
*data
= opaque
;
122 return inode
->i_ino
== data
->fid
.vnode
&&
123 inode
->i_version
== data
->fid
.unique
;
124 } /* end afs_iget5_test() */
126 /*****************************************************************************/
128 * iget5() inode initialiser
130 static int afs_iget5_set(struct inode
*inode
, void *opaque
)
132 struct afs_iget_data
*data
= opaque
;
133 struct afs_vnode
*vnode
= AFS_FS_I(inode
);
135 inode
->i_ino
= data
->fid
.vnode
;
136 inode
->i_version
= data
->fid
.unique
;
137 vnode
->fid
= data
->fid
;
138 vnode
->volume
= data
->volume
;
141 } /* end afs_iget5_set() */
143 /*****************************************************************************/
147 inline int afs_iget(struct super_block
*sb
, struct afs_fid
*fid
,
148 struct inode
**_inode
)
150 struct afs_iget_data data
= { .fid
= *fid
};
151 struct afs_super_info
*as
;
152 struct afs_vnode
*vnode
;
156 _enter(",{%u,%u,%u},,", fid
->vid
, fid
->vnode
, fid
->unique
);
159 data
.volume
= as
->volume
;
161 inode
= iget5_locked(sb
, fid
->vnode
, afs_iget5_test
, afs_iget5_set
,
164 _leave(" = -ENOMEM");
168 vnode
= AFS_FS_I(inode
);
170 /* deal with an existing inode */
171 if (!(inode
->i_state
& I_NEW
)) {
172 ret
= afs_vnode_fetch_status(vnode
);
177 _leave(" = %d", ret
);
181 #ifdef AFS_CACHING_SUPPORT
182 /* set up caching before reading the status, as fetch-status reads the
183 * first page of symlinks to see if they're really mntpts */
184 cachefs_acquire_cookie(vnode
->volume
->cache
,
190 /* okay... it's a new inode */
191 inode
->i_flags
|= S_NOATIME
;
192 vnode
->flags
|= AFS_VNODE_CHANGED
;
193 ret
= afs_inode_fetch_status(inode
);
198 unlock_new_inode(inode
);
201 _leave(" = 0 [CB { v=%u x=%lu t=%u }]",
203 vnode
->cb_timeout
.timo_jif
,
209 make_bad_inode(inode
);
210 unlock_new_inode(inode
);
213 _leave(" = %d [bad]", ret
);
215 } /* end afs_iget() */
217 /*****************************************************************************/
219 * read the attributes of an inode
221 int afs_inode_getattr(struct vfsmount
*mnt
, struct dentry
*dentry
,
224 struct afs_vnode
*vnode
;
228 inode
= dentry
->d_inode
;
230 _enter("{ ino=%lu v=%lu }", inode
->i_ino
, inode
->i_version
);
232 vnode
= AFS_FS_I(inode
);
234 ret
= afs_inode_fetch_status(inode
);
235 if (ret
== -ENOENT
) {
236 _leave(" = %d [%d %p]",
237 ret
, atomic_read(&dentry
->d_count
), dentry
->d_inode
);
241 make_bad_inode(inode
);
242 _leave(" = %d", ret
);
246 /* transfer attributes from the inode structure to the stat
248 generic_fillattr(inode
, stat
);
250 _leave(" = 0 CB { v=%u x=%u t=%u }",
256 } /* end afs_inode_getattr() */
258 /*****************************************************************************/
262 void afs_clear_inode(struct inode
*inode
)
264 struct afs_vnode
*vnode
;
266 vnode
= AFS_FS_I(inode
);
268 _enter("ino=%lu { vn=%08x v=%u x=%u t=%u }",
276 BUG_ON(inode
->i_ino
!= vnode
->fid
.vnode
);
278 afs_vnode_give_up_callback(vnode
);
280 #ifdef AFS_CACHING_SUPPORT
281 cachefs_relinquish_cookie(vnode
->cache
, 0);
286 } /* end afs_clear_inode() */