diff options
Diffstat (limited to 'fs/afs/inode.c')
-rw-r--r-- | fs/afs/inode.c | 248 |
1 files changed, 152 insertions, 96 deletions
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 9d9bca6c28b5..c184a4ee5995 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
@@ -19,9 +19,6 @@ | |||
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
21 | #include <linux/pagemap.h> | 21 | #include <linux/pagemap.h> |
22 | #include "volume.h" | ||
23 | #include "vnode.h" | ||
24 | #include "super.h" | ||
25 | #include "internal.h" | 22 | #include "internal.h" |
26 | 23 | ||
27 | struct afs_iget_data { | 24 | struct afs_iget_data { |
@@ -29,26 +26,25 @@ struct afs_iget_data { | |||
29 | struct afs_volume *volume; /* volume on which resides */ | 26 | struct afs_volume *volume; /* volume on which resides */ |
30 | }; | 27 | }; |
31 | 28 | ||
32 | /*****************************************************************************/ | ||
33 | /* | 29 | /* |
34 | * map the AFS file status to the inode member variables | 30 | * map the AFS file status to the inode member variables |
35 | */ | 31 | */ |
36 | static int afs_inode_map_status(struct afs_vnode *vnode) | 32 | static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key) |
37 | { | 33 | { |
38 | struct inode *inode = AFS_VNODE_TO_I(vnode); | 34 | struct inode *inode = AFS_VNODE_TO_I(vnode); |
39 | 35 | ||
40 | _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", |
41 | vnode->status.type, | 37 | vnode->status.type, |
42 | vnode->status.nlink, | 38 | vnode->status.nlink, |
43 | vnode->status.size, | 39 | (unsigned long long) vnode->status.size, |
44 | vnode->status.version, | 40 | vnode->status.data_version, |
45 | vnode->status.mode); | 41 | vnode->status.mode); |
46 | 42 | ||
47 | switch (vnode->status.type) { | 43 | switch (vnode->status.type) { |
48 | case AFS_FTYPE_FILE: | 44 | case AFS_FTYPE_FILE: |
49 | inode->i_mode = S_IFREG | vnode->status.mode; | 45 | inode->i_mode = S_IFREG | vnode->status.mode; |
50 | inode->i_op = &afs_file_inode_operations; | 46 | inode->i_op = &afs_file_inode_operations; |
51 | inode->i_fop = &generic_ro_fops; | 47 | inode->i_fop = &afs_file_operations; |
52 | break; | 48 | break; |
53 | case AFS_FTYPE_DIR: | 49 | case AFS_FTYPE_DIR: |
54 | inode->i_mode = S_IFDIR | vnode->status.mode; | 50 | inode->i_mode = S_IFDIR | vnode->status.mode; |
@@ -77,9 +73,9 @@ static int afs_inode_map_status(struct afs_vnode *vnode) | |||
77 | 73 | ||
78 | /* check to see whether a symbolic link is really a mountpoint */ | 74 | /* check to see whether a symbolic link is really a mountpoint */ |
79 | if (vnode->status.type == AFS_FTYPE_SYMLINK) { | 75 | if (vnode->status.type == AFS_FTYPE_SYMLINK) { |
80 | afs_mntpt_check_symlink(vnode); | 76 | afs_mntpt_check_symlink(vnode, key); |
81 | 77 | ||
82 | if (vnode->flags & AFS_VNODE_MOUNTPOINT) { | 78 | if (test_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags)) { |
83 | inode->i_mode = S_IFDIR | vnode->status.mode; | 79 | inode->i_mode = S_IFDIR | vnode->status.mode; |
84 | inode->i_op = &afs_mntpt_inode_operations; | 80 | inode->i_op = &afs_mntpt_inode_operations; |
85 | inode->i_fop = &afs_mntpt_file_operations; | 81 | inode->i_fop = &afs_mntpt_file_operations; |
@@ -87,30 +83,8 @@ static int afs_inode_map_status(struct afs_vnode *vnode) | |||
87 | } | 83 | } |
88 | 84 | ||
89 | return 0; | 85 | return 0; |
90 | } /* end afs_inode_map_status() */ | 86 | } |
91 | 87 | ||
92 | /*****************************************************************************/ | ||
93 | /* | ||
94 | * attempt to fetch the status of an inode, coelescing multiple simultaneous | ||
95 | * fetches | ||
96 | */ | ||
97 | static int afs_inode_fetch_status(struct inode *inode) | ||
98 | { | ||
99 | struct afs_vnode *vnode; | ||
100 | int ret; | ||
101 | |||
102 | vnode = AFS_FS_I(inode); | ||
103 | |||
104 | ret = afs_vnode_fetch_status(vnode); | ||
105 | |||
106 | if (ret == 0) | ||
107 | ret = afs_inode_map_status(vnode); | ||
108 | |||
109 | return ret; | ||
110 | |||
111 | } /* end afs_inode_fetch_status() */ | ||
112 | |||
113 | /*****************************************************************************/ | ||
114 | /* | 88 | /* |
115 | * iget5() comparator | 89 | * iget5() comparator |
116 | */ | 90 | */ |
@@ -120,9 +94,8 @@ static int afs_iget5_test(struct inode *inode, void *opaque) | |||
120 | 94 | ||
121 | return inode->i_ino == data->fid.vnode && | 95 | return inode->i_ino == data->fid.vnode && |
122 | inode->i_version == data->fid.unique; | 96 | inode->i_version == data->fid.unique; |
123 | } /* end afs_iget5_test() */ | 97 | } |
124 | 98 | ||
125 | /*****************************************************************************/ | ||
126 | /* | 99 | /* |
127 | * iget5() inode initialiser | 100 | * iget5() inode initialiser |
128 | */ | 101 | */ |
@@ -137,14 +110,14 @@ static int afs_iget5_set(struct inode *inode, void *opaque) | |||
137 | vnode->volume = data->volume; | 110 | vnode->volume = data->volume; |
138 | 111 | ||
139 | return 0; | 112 | return 0; |
140 | } /* end afs_iget5_set() */ | 113 | } |
141 | 114 | ||
142 | /*****************************************************************************/ | ||
143 | /* | 115 | /* |
144 | * inode retrieval | 116 | * inode retrieval |
145 | */ | 117 | */ |
146 | inline int afs_iget(struct super_block *sb, struct afs_fid *fid, | 118 | struct inode *afs_iget(struct super_block *sb, struct key *key, |
147 | struct inode **_inode) | 119 | struct afs_fid *fid, struct afs_file_status *status, |
120 | struct afs_callback *cb) | ||
148 | { | 121 | { |
149 | struct afs_iget_data data = { .fid = *fid }; | 122 | struct afs_iget_data data = { .fid = *fid }; |
150 | struct afs_super_info *as; | 123 | struct afs_super_info *as; |
@@ -161,20 +134,18 @@ inline int afs_iget(struct super_block *sb, struct afs_fid *fid, | |||
161 | &data); | 134 | &data); |
162 | if (!inode) { | 135 | if (!inode) { |
163 | _leave(" = -ENOMEM"); | 136 | _leave(" = -ENOMEM"); |
164 | return -ENOMEM; | 137 | return ERR_PTR(-ENOMEM); |
165 | } | 138 | } |
166 | 139 | ||
140 | _debug("GOT INODE %p { vl=%x vn=%x, u=%x }", | ||
141 | inode, fid->vid, fid->vnode, fid->unique); | ||
142 | |||
167 | vnode = AFS_FS_I(inode); | 143 | vnode = AFS_FS_I(inode); |
168 | 144 | ||
169 | /* deal with an existing inode */ | 145 | /* deal with an existing inode */ |
170 | if (!(inode->i_state & I_NEW)) { | 146 | if (!(inode->i_state & I_NEW)) { |
171 | ret = afs_vnode_fetch_status(vnode); | 147 | _leave(" = %p", inode); |
172 | if (ret==0) | 148 | return inode; |
173 | *_inode = inode; | ||
174 | else | ||
175 | iput(inode); | ||
176 | _leave(" = %d", ret); | ||
177 | return ret; | ||
178 | } | 149 | } |
179 | 150 | ||
180 | #ifdef AFS_CACHING_SUPPORT | 151 | #ifdef AFS_CACHING_SUPPORT |
@@ -186,100 +157,185 @@ inline int afs_iget(struct super_block *sb, struct afs_fid *fid, | |||
186 | &vnode->cache); | 157 | &vnode->cache); |
187 | #endif | 158 | #endif |
188 | 159 | ||
189 | /* okay... it's a new inode */ | 160 | if (!status) { |
190 | inode->i_flags |= S_NOATIME; | 161 | /* it's a remotely extant inode */ |
191 | vnode->flags |= AFS_VNODE_CHANGED; | 162 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); |
192 | ret = afs_inode_fetch_status(inode); | 163 | ret = afs_vnode_fetch_status(vnode, NULL, key); |
193 | if (ret<0) | 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 | |||
185 | ret = afs_inode_map_status(vnode, key); | ||
186 | if (ret < 0) | ||
194 | goto bad_inode; | 187 | goto bad_inode; |
195 | 188 | ||
196 | /* success */ | 189 | /* success */ |
190 | clear_bit(AFS_VNODE_UNSET, &vnode->flags); | ||
191 | inode->i_flags |= S_NOATIME; | ||
197 | unlock_new_inode(inode); | 192 | unlock_new_inode(inode); |
198 | 193 | _leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type); | |
199 | *_inode = inode; | 194 | return inode; |
200 | _leave(" = 0 [CB { v=%u x=%lu t=%u }]", | ||
201 | vnode->cb_version, | ||
202 | vnode->cb_timeout.timo_jif, | ||
203 | vnode->cb_type); | ||
204 | return 0; | ||
205 | 195 | ||
206 | /* failure */ | 196 | /* failure */ |
207 | bad_inode: | 197 | bad_inode: |
208 | make_bad_inode(inode); | 198 | make_bad_inode(inode); |
209 | unlock_new_inode(inode); | 199 | unlock_new_inode(inode); |
210 | iput(inode); | 200 | iput(inode); |
211 | 201 | ||
212 | _leave(" = %d [bad]", ret); | 202 | _leave(" = %d [bad]", ret); |
203 | return ERR_PTR(ret); | ||
204 | } | ||
205 | |||
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 | */ | ||
215 | int 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); | ||
268 | valid: | ||
269 | _leave(" = 0"); | ||
270 | return 0; | ||
271 | |||
272 | error_unlock: | ||
273 | mutex_unlock(&vnode->validate_lock); | ||
274 | _leave(" = %d", ret); | ||
213 | return ret; | 275 | return ret; |
214 | } /* end afs_iget() */ | 276 | } |
215 | 277 | ||
216 | /*****************************************************************************/ | ||
217 | /* | 278 | /* |
218 | * read the attributes of an inode | 279 | * read the attributes of an inode |
219 | */ | 280 | */ |
220 | int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, | 281 | int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, |
221 | struct kstat *stat) | 282 | struct kstat *stat) |
222 | { | 283 | { |
223 | struct afs_vnode *vnode; | ||
224 | struct inode *inode; | 284 | struct inode *inode; |
225 | int ret; | ||
226 | 285 | ||
227 | inode = dentry->d_inode; | 286 | inode = dentry->d_inode; |
228 | 287 | ||
229 | _enter("{ ino=%lu v=%lu }", inode->i_ino, inode->i_version); | 288 | _enter("{ ino=%lu v=%lu }", inode->i_ino, inode->i_version); |
230 | 289 | ||
231 | vnode = AFS_FS_I(inode); | ||
232 | |||
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); | ||
237 | return ret; | ||
238 | } | ||
239 | else if (ret < 0) { | ||
240 | make_bad_inode(inode); | ||
241 | _leave(" = %d", ret); | ||
242 | return ret; | ||
243 | } | ||
244 | |||
245 | /* transfer attributes from the inode structure to the stat | ||
246 | * structure */ | ||
247 | generic_fillattr(inode, stat); | 290 | generic_fillattr(inode, stat); |
248 | |||
249 | _leave(" = 0 CB { v=%u x=%u t=%u }", | ||
250 | vnode->cb_version, | ||
251 | vnode->cb_expiry, | ||
252 | vnode->cb_type); | ||
253 | |||
254 | return 0; | 291 | return 0; |
255 | } /* end afs_inode_getattr() */ | 292 | } |
256 | 293 | ||
257 | /*****************************************************************************/ | ||
258 | /* | 294 | /* |
259 | * clear an AFS inode | 295 | * clear an AFS inode |
260 | */ | 296 | */ |
261 | void afs_clear_inode(struct inode *inode) | 297 | void afs_clear_inode(struct inode *inode) |
262 | { | 298 | { |
299 | struct afs_permits *permits; | ||
263 | struct afs_vnode *vnode; | 300 | struct afs_vnode *vnode; |
264 | 301 | ||
265 | vnode = AFS_FS_I(inode); | 302 | vnode = AFS_FS_I(inode); |
266 | 303 | ||
267 | _enter("ino=%lu { vn=%08x v=%u x=%u t=%u }", | 304 | _enter("{%x:%d.%d} v=%u x=%u t=%u }", |
268 | inode->i_ino, | 305 | vnode->fid.vid, |
269 | vnode->fid.vnode, | 306 | vnode->fid.vnode, |
307 | vnode->fid.unique, | ||
270 | vnode->cb_version, | 308 | vnode->cb_version, |
271 | vnode->cb_expiry, | 309 | vnode->cb_expiry, |
272 | vnode->cb_type | 310 | vnode->cb_type); |
273 | ); | ||
274 | 311 | ||
275 | BUG_ON(inode->i_ino != vnode->fid.vnode); | 312 | _debug("CLEAR INODE %p", inode); |
276 | 313 | ||
277 | afs_vnode_give_up_callback(vnode); | 314 | ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode); |
315 | |||
316 | afs_give_up_callback(vnode); | ||
317 | |||
318 | if (vnode->server) { | ||
319 | spin_lock(&vnode->server->fs_lock); | ||
320 | rb_erase(&vnode->server_rb, &vnode->server->fs_vnodes); | ||
321 | spin_unlock(&vnode->server->fs_lock); | ||
322 | afs_put_server(vnode->server); | ||
323 | vnode->server = NULL; | ||
324 | } | ||
325 | |||
326 | ASSERT(!vnode->cb_promised); | ||
278 | 327 | ||
279 | #ifdef AFS_CACHING_SUPPORT | 328 | #ifdef AFS_CACHING_SUPPORT |
280 | cachefs_relinquish_cookie(vnode->cache, 0); | 329 | cachefs_relinquish_cookie(vnode->cache, 0); |
281 | vnode->cache = NULL; | 330 | vnode->cache = NULL; |
282 | #endif | 331 | #endif |
283 | 332 | ||
333 | mutex_lock(&vnode->permits_lock); | ||
334 | permits = vnode->permits; | ||
335 | rcu_assign_pointer(vnode->permits, NULL); | ||
336 | mutex_unlock(&vnode->permits_lock); | ||
337 | if (permits) | ||
338 | call_rcu(&permits->rcu, afs_zap_permits); | ||
339 | |||
284 | _leave(""); | 340 | _leave(""); |
285 | } /* end afs_clear_inode() */ | 341 | } |