diff options
author | David Howells <dhowells@redhat.com> | 2007-04-26 18:59:35 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-04-26 18:59:35 -0400 |
commit | 260a980317dac80182dd76140cf67c6e81d6d3dd (patch) | |
tree | 84f3e919fd33be56aad4fc57f5cb844df1a6b952 /fs/afs/inode.c | |
parent | c35eccb1f614954b10cba3f74b7c301993b2f42e (diff) |
[AFS]: Add "directory write" support.
Add support for the create, link, symlink, unlink, mkdir, rmdir and
rename VFS operations to the in-kernel AFS filesystem.
Also:
(1) Fix dentry and inode revalidation. d_revalidate should only look at
state of the dentry. Revalidation of the contents of an inode pointed to
by a dentry is now separate.
(2) Fix afs_lookup() to hash negative dentries as well as positive ones.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'fs/afs/inode.c')
-rw-r--r-- | fs/afs/inode.c | 115 |
1 files changed, 105 insertions, 10 deletions
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 22733622829..56ca8581b37 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 | */ |
118 | inline struct inode *afs_iget(struct super_block *sb, struct key *key, | 118 | struct 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 | */ | ||
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); | ||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | /* | ||
185 | * read the attributes of an inode | 279 | * read the attributes of an inode |
186 | */ | 280 | */ |
187 | int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, | 281 | int 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); |