aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/afs/inode.c')
-rw-r--r--fs/afs/inode.c115
1 files changed, 105 insertions, 10 deletions
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 227336228299..56ca8581b37f 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -33,7 +33,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
33{ 33{
34 struct inode *inode = AFS_VNODE_TO_I(vnode); 34 struct inode *inode = AFS_VNODE_TO_I(vnode);
35 35
36 _debug("FS: ft=%d lk=%d sz=%Zu ver=%Lu mod=%hu", 36 _debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu",
37 vnode->status.type, 37 vnode->status.type,
38 vnode->status.nlink, 38 vnode->status.nlink,
39 vnode->status.size, 39 vnode->status.size,
@@ -115,8 +115,9 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
115/* 115/*
116 * inode retrieval 116 * inode retrieval
117 */ 117 */
118inline struct inode *afs_iget(struct super_block *sb, struct key *key, 118struct inode *afs_iget(struct super_block *sb, struct key *key,
119 struct afs_fid *fid) 119 struct afs_fid *fid, struct afs_file_status *status,
120 struct afs_callback *cb)
120{ 121{
121 struct afs_iget_data data = { .fid = *fid }; 122 struct afs_iget_data data = { .fid = *fid };
122 struct afs_super_info *as; 123 struct afs_super_info *as;
@@ -156,16 +157,37 @@ inline struct inode *afs_iget(struct super_block *sb, struct key *key,
156 &vnode->cache); 157 &vnode->cache);
157#endif 158#endif
158 159
159 /* okay... it's a new inode */ 160 if (!status) {
160 set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); 161 /* it's a remotely extant inode */
161 ret = afs_vnode_fetch_status(vnode, NULL, key); 162 set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
162 if (ret < 0) 163 ret = afs_vnode_fetch_status(vnode, NULL, key);
163 goto bad_inode; 164 if (ret < 0)
165 goto bad_inode;
166 } else {
167 /* it's an inode we just created */
168 memcpy(&vnode->status, status, sizeof(vnode->status));
169
170 if (!cb) {
171 /* it's a symlink we just created (the fileserver
172 * didn't give us a callback) */
173 vnode->cb_version = 0;
174 vnode->cb_expiry = 0;
175 vnode->cb_type = 0;
176 vnode->cb_expires = get_seconds();
177 } else {
178 vnode->cb_version = cb->version;
179 vnode->cb_expiry = cb->expiry;
180 vnode->cb_type = cb->type;
181 vnode->cb_expires = vnode->cb_expiry + get_seconds();
182 }
183 }
184
164 ret = afs_inode_map_status(vnode, key); 185 ret = afs_inode_map_status(vnode, key);
165 if (ret < 0) 186 if (ret < 0)
166 goto bad_inode; 187 goto bad_inode;
167 188
168 /* success */ 189 /* success */
190 clear_bit(AFS_VNODE_UNSET, &vnode->flags);
169 inode->i_flags |= S_NOATIME; 191 inode->i_flags |= S_NOATIME;
170 unlock_new_inode(inode); 192 unlock_new_inode(inode);
171 _leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type); 193 _leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type);
@@ -182,6 +204,78 @@ bad_inode:
182} 204}
183 205
184/* 206/*
207 * validate a vnode/inode
208 * - there are several things we need to check
209 * - parent dir data changes (rm, rmdir, rename, mkdir, create, link,
210 * symlink)
211 * - parent dir metadata changed (security changes)
212 * - dentry data changed (write, truncate)
213 * - dentry metadata changed (security changes)
214 */
215int afs_validate(struct afs_vnode *vnode, struct key *key)
216{
217 int ret;
218
219 _enter("{v={%x:%u} fl=%lx},%x",
220 vnode->fid.vid, vnode->fid.vnode, vnode->flags,
221 key_serial(key));
222
223 if (vnode->cb_promised &&
224 !test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
225 !test_bit(AFS_VNODE_MODIFIED, &vnode->flags) &&
226 !test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
227 if (vnode->cb_expires < get_seconds() + 10) {
228 _debug("callback expired");
229 set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
230 } else {
231 goto valid;
232 }
233 }
234
235 if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
236 goto valid;
237
238 mutex_lock(&vnode->validate_lock);
239
240 /* if the promise has expired, we need to check the server again to get
241 * a new promise - note that if the (parent) directory's metadata was
242 * changed then the security may be different and we may no longer have
243 * access */
244 if (!vnode->cb_promised ||
245 test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) {
246 _debug("not promised");
247 ret = afs_vnode_fetch_status(vnode, NULL, key);
248 if (ret < 0)
249 goto error_unlock;
250 _debug("new promise [fl=%lx]", vnode->flags);
251 }
252
253 if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
254 _debug("file already deleted");
255 ret = -ESTALE;
256 goto error_unlock;
257 }
258
259 /* if the vnode's data version number changed then its contents are
260 * different */
261 if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
262 _debug("zap data {%x:%d}", vnode->fid.vid, vnode->fid.vnode);
263 invalidate_remote_inode(&vnode->vfs_inode);
264 }
265
266 clear_bit(AFS_VNODE_MODIFIED, &vnode->flags);
267 mutex_unlock(&vnode->validate_lock);
268valid:
269 _leave(" = 0");
270 return 0;
271
272error_unlock:
273 mutex_unlock(&vnode->validate_lock);
274 _leave(" = %d", ret);
275 return ret;
276}
277
278/*
185 * read the attributes of an inode 279 * read the attributes of an inode
186 */ 280 */
187int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, 281int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
@@ -207,9 +301,10 @@ void afs_clear_inode(struct inode *inode)
207 301
208 vnode = AFS_FS_I(inode); 302 vnode = AFS_FS_I(inode);
209 303
210 _enter("ino=%lu { vn=%08x v=%u x=%u t=%u }", 304 _enter("{%x:%d.%d} v=%u x=%u t=%u }",
211 inode->i_ino, 305 vnode->fid.vid,
212 vnode->fid.vnode, 306 vnode->fid.vnode,
307 vnode->fid.unique,
213 vnode->cb_version, 308 vnode->cb_version,
214 vnode->cb_expiry, 309 vnode->cb_expiry,
215 vnode->cb_type); 310 vnode->cb_type);