diff options
author | Evgeniy Dushistov <dushistov@mail.ru> | 2006-06-25 08:47:22 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-25 13:01:02 -0400 |
commit | b71034e5e67d1577424cebe7bbb7d0ce134a4cd8 (patch) | |
tree | 4e4ffe95db731bbdc81d086d2b4462b3ab5867c2 /fs/ufs/namei.c | |
parent | 826843a347cc8fd596a4c73d3fbdf04a1f130b8a (diff) |
[PATCH] ufs: directory and page cache: from blocks to pages
Change function in fs/ufs/dir.c and fs/ufs/namei.c to work with pages
instead of straight work with blocks. It fixed such bugs:
* for i in `seq 1 1000`; do touch $i; done - crash system
* mkdir create directory without "." and ".." entries
Signed-off-by: Evgeniy Dushistov <dushistov@mail.ru>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/ufs/namei.c')
-rw-r--r-- | fs/ufs/namei.c | 62 |
1 files changed, 35 insertions, 27 deletions
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 51f702700308..364bb92b0917 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c | |||
@@ -1,6 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * linux/fs/ufs/namei.c | 2 | * linux/fs/ufs/namei.c |
3 | * | 3 | * |
4 | * Migration to usage of "page cache" on May 2006 by | ||
5 | * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base. | ||
6 | * | ||
4 | * Copyright (C) 1998 | 7 | * Copyright (C) 1998 |
5 | * Daniel Pirkl <daniel.pirkl@email.cz> | 8 | * Daniel Pirkl <daniel.pirkl@email.cz> |
6 | * Charles University, Faculty of Mathematics and Physics | 9 | * Charles University, Faculty of Mathematics and Physics |
@@ -28,7 +31,6 @@ | |||
28 | #include <linux/fs.h> | 31 | #include <linux/fs.h> |
29 | #include <linux/ufs_fs.h> | 32 | #include <linux/ufs_fs.h> |
30 | #include <linux/smp_lock.h> | 33 | #include <linux/smp_lock.h> |
31 | #include <linux/buffer_head.h> | ||
32 | #include "swab.h" /* will go away - see comment in mknod() */ | 34 | #include "swab.h" /* will go away - see comment in mknod() */ |
33 | #include "util.h" | 35 | #include "util.h" |
34 | 36 | ||
@@ -232,19 +234,18 @@ out_dir: | |||
232 | goto out; | 234 | goto out; |
233 | } | 235 | } |
234 | 236 | ||
235 | static int ufs_unlink(struct inode * dir, struct dentry *dentry) | 237 | static int ufs_unlink(struct inode *dir, struct dentry *dentry) |
236 | { | 238 | { |
237 | struct inode * inode = dentry->d_inode; | 239 | struct inode * inode = dentry->d_inode; |
238 | struct buffer_head * bh; | 240 | struct ufs_dir_entry *de; |
239 | struct ufs_dir_entry * de; | 241 | struct page *page; |
240 | int err = -ENOENT; | 242 | int err = -ENOENT; |
241 | 243 | ||
242 | lock_kernel(); | 244 | de = ufs_find_entry(dir, dentry, &page); |
243 | de = ufs_find_entry (dentry, &bh); | ||
244 | if (!de) | 245 | if (!de) |
245 | goto out; | 246 | goto out; |
246 | 247 | ||
247 | err = ufs_delete_entry (dir, de, bh); | 248 | err = ufs_delete_entry(dir, de, page); |
248 | if (err) | 249 | if (err) |
249 | goto out; | 250 | goto out; |
250 | 251 | ||
@@ -252,7 +253,6 @@ static int ufs_unlink(struct inode * dir, struct dentry *dentry) | |||
252 | inode_dec_link_count(inode); | 253 | inode_dec_link_count(inode); |
253 | err = 0; | 254 | err = 0; |
254 | out: | 255 | out: |
255 | unlock_kernel(); | ||
256 | return err; | 256 | return err; |
257 | } | 257 | } |
258 | 258 | ||
@@ -274,42 +274,42 @@ static int ufs_rmdir (struct inode * dir, struct dentry *dentry) | |||
274 | return err; | 274 | return err; |
275 | } | 275 | } |
276 | 276 | ||
277 | static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry, | 277 | static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry, |
278 | struct inode * new_dir, struct dentry * new_dentry ) | 278 | struct inode *new_dir, struct dentry *new_dentry) |
279 | { | 279 | { |
280 | struct inode *old_inode = old_dentry->d_inode; | 280 | struct inode *old_inode = old_dentry->d_inode; |
281 | struct inode *new_inode = new_dentry->d_inode; | 281 | struct inode *new_inode = new_dentry->d_inode; |
282 | struct buffer_head *dir_bh = NULL; | 282 | struct page *dir_page = NULL; |
283 | struct ufs_dir_entry *dir_de = NULL; | 283 | struct ufs_dir_entry * dir_de = NULL; |
284 | struct buffer_head *old_bh; | 284 | struct page *old_page; |
285 | struct ufs_dir_entry *old_de; | 285 | struct ufs_dir_entry *old_de; |
286 | int err = -ENOENT; | 286 | int err = -ENOENT; |
287 | 287 | ||
288 | lock_kernel(); | 288 | old_de = ufs_find_entry(old_dir, old_dentry, &old_page); |
289 | old_de = ufs_find_entry (old_dentry, &old_bh); | ||
290 | if (!old_de) | 289 | if (!old_de) |
291 | goto out; | 290 | goto out; |
292 | 291 | ||
293 | if (S_ISDIR(old_inode->i_mode)) { | 292 | if (S_ISDIR(old_inode->i_mode)) { |
294 | err = -EIO; | 293 | err = -EIO; |
295 | dir_de = ufs_dotdot(old_inode, &dir_bh); | 294 | dir_de = ufs_dotdot(old_inode, &dir_page); |
296 | if (!dir_de) | 295 | if (!dir_de) |
297 | goto out_old; | 296 | goto out_old; |
298 | } | 297 | } |
299 | 298 | ||
300 | if (new_inode) { | 299 | if (new_inode) { |
301 | struct buffer_head *new_bh; | 300 | struct page *new_page; |
302 | struct ufs_dir_entry *new_de; | 301 | struct ufs_dir_entry *new_de; |
303 | 302 | ||
304 | err = -ENOTEMPTY; | 303 | err = -ENOTEMPTY; |
305 | if (dir_de && !ufs_empty_dir (new_inode)) | 304 | if (dir_de && !ufs_empty_dir(new_inode)) |
306 | goto out_dir; | 305 | goto out_dir; |
306 | |||
307 | err = -ENOENT; | 307 | err = -ENOENT; |
308 | new_de = ufs_find_entry (new_dentry, &new_bh); | 308 | new_de = ufs_find_entry(new_dir, new_dentry, &new_page); |
309 | if (!new_de) | 309 | if (!new_de) |
310 | goto out_dir; | 310 | goto out_dir; |
311 | inode_inc_link_count(old_inode); | 311 | inode_inc_link_count(old_inode); |
312 | ufs_set_link(new_dir, new_de, new_bh, old_inode); | 312 | ufs_set_link(new_dir, new_de, new_page, old_inode); |
313 | new_inode->i_ctime = CURRENT_TIME_SEC; | 313 | new_inode->i_ctime = CURRENT_TIME_SEC; |
314 | if (dir_de) | 314 | if (dir_de) |
315 | new_inode->i_nlink--; | 315 | new_inode->i_nlink--; |
@@ -330,24 +330,32 @@ static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry, | |||
330 | inode_inc_link_count(new_dir); | 330 | inode_inc_link_count(new_dir); |
331 | } | 331 | } |
332 | 332 | ||
333 | ufs_delete_entry (old_dir, old_de, old_bh); | 333 | /* |
334 | * Like most other Unix systems, set the ctime for inodes on a | ||
335 | * rename. | ||
336 | * inode_dec_link_count() will mark the inode dirty. | ||
337 | */ | ||
338 | old_inode->i_ctime = CURRENT_TIME_SEC; | ||
334 | 339 | ||
340 | ufs_delete_entry(old_dir, old_de, old_page); | ||
335 | inode_dec_link_count(old_inode); | 341 | inode_dec_link_count(old_inode); |
336 | 342 | ||
337 | if (dir_de) { | 343 | if (dir_de) { |
338 | ufs_set_link(old_inode, dir_de, dir_bh, new_dir); | 344 | ufs_set_link(old_inode, dir_de, dir_page, new_dir); |
339 | inode_dec_link_count(old_dir); | 345 | inode_dec_link_count(old_dir); |
340 | } | 346 | } |
341 | unlock_kernel(); | ||
342 | return 0; | 347 | return 0; |
343 | 348 | ||
349 | |||
344 | out_dir: | 350 | out_dir: |
345 | if (dir_de) | 351 | if (dir_de) { |
346 | brelse(dir_bh); | 352 | kunmap(dir_page); |
353 | page_cache_release(dir_page); | ||
354 | } | ||
347 | out_old: | 355 | out_old: |
348 | brelse (old_bh); | 356 | kunmap(old_page); |
357 | page_cache_release(old_page); | ||
349 | out: | 358 | out: |
350 | unlock_kernel(); | ||
351 | return err; | 359 | return err; |
352 | } | 360 | } |
353 | 361 | ||