diff options
author | Evgeniy Dushistov <dushistov@mail.ru> | 2006-06-25 16:47:22 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-25 21:01:02 +0400 |
commit | b71034e5e67d1577424cebe7bbb7d0ce134a4cd8 (patch) | |
tree | 4e4ffe95db731bbdc81d086d2b4462b3ab5867c2 /fs/ufs/namei.c | |
parent | 826843a347cc8fd596a4c73d3fbdf04a1f130b8a (diff) | |
download | linux-b71034e5e67d1577424cebe7bbb7d0ce134a4cd8.tar.xz |
[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 @@ /* * linux/fs/ufs/namei.c * + * Migration to usage of "page cache" on May 2006 by + * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base. + * * Copyright (C) 1998 * Daniel Pirkl <daniel.pirkl@email.cz> * Charles University, Faculty of Mathematics and Physics @@ -28,7 +31,6 @@ #include <linux/fs.h> #include <linux/ufs_fs.h> #include <linux/smp_lock.h> -#include <linux/buffer_head.h> #include "swab.h" /* will go away - see comment in mknod() */ #include "util.h" @@ -232,19 +234,18 @@ out_dir: goto out; } -static int ufs_unlink(struct inode * dir, struct dentry *dentry) +static int ufs_unlink(struct inode *dir, struct dentry *dentry) { struct inode * inode = dentry->d_inode; - struct buffer_head * bh; - struct ufs_dir_entry * de; + struct ufs_dir_entry *de; + struct page *page; int err = -ENOENT; - lock_kernel(); - de = ufs_find_entry (dentry, &bh); + de = ufs_find_entry(dir, dentry, &page); if (!de) goto out; - err = ufs_delete_entry (dir, de, bh); + err = ufs_delete_entry(dir, de, page); if (err) goto out; @@ -252,7 +253,6 @@ static int ufs_unlink(struct inode * dir, struct dentry *dentry) inode_dec_link_count(inode); err = 0; out: - unlock_kernel(); return err; } @@ -274,42 +274,42 @@ static int ufs_rmdir (struct inode * dir, struct dentry *dentry) return err; } -static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry, - struct inode * new_dir, struct dentry * new_dentry ) +static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) { struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; - struct buffer_head *dir_bh = NULL; - struct ufs_dir_entry *dir_de = NULL; - struct buffer_head *old_bh; + struct page *dir_page = NULL; + struct ufs_dir_entry * dir_de = NULL; + struct page *old_page; struct ufs_dir_entry *old_de; int err = -ENOENT; - lock_kernel(); - old_de = ufs_find_entry (old_dentry, &old_bh); + old_de = ufs_find_entry(old_dir, old_dentry, &old_page); if (!old_de) goto out; if (S_ISDIR(old_inode->i_mode)) { err = -EIO; - dir_de = ufs_dotdot(old_inode, &dir_bh); + dir_de = ufs_dotdot(old_inode, &dir_page); if (!dir_de) goto out_old; } if (new_inode) { - struct buffer_head *new_bh; + struct page *new_page; struct ufs_dir_entry *new_de; err = -ENOTEMPTY; - if (dir_de && !ufs_empty_dir (new_inode)) + if (dir_de && !ufs_empty_dir(new_inode)) goto out_dir; + err = -ENOENT; - new_de = ufs_find_entry (new_dentry, &new_bh); + new_de = ufs_find_entry(new_dir, new_dentry, &new_page); if (!new_de) goto out_dir; inode_inc_link_count(old_inode); - ufs_set_link(new_dir, new_de, new_bh, old_inode); + ufs_set_link(new_dir, new_de, new_page, old_inode); new_inode->i_ctime = CURRENT_TIME_SEC; if (dir_de) new_inode->i_nlink--; @@ -330,24 +330,32 @@ static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry, inode_inc_link_count(new_dir); } - ufs_delete_entry (old_dir, old_de, old_bh); + /* + * Like most other Unix systems, set the ctime for inodes on a + * rename. + * inode_dec_link_count() will mark the inode dirty. + */ + old_inode->i_ctime = CURRENT_TIME_SEC; + ufs_delete_entry(old_dir, old_de, old_page); inode_dec_link_count(old_inode); if (dir_de) { - ufs_set_link(old_inode, dir_de, dir_bh, new_dir); + ufs_set_link(old_inode, dir_de, dir_page, new_dir); inode_dec_link_count(old_dir); } - unlock_kernel(); return 0; + out_dir: - if (dir_de) - brelse(dir_bh); + if (dir_de) { + kunmap(dir_page); + page_cache_release(dir_page); + } out_old: - brelse (old_bh); + kunmap(old_page); + page_cache_release(old_page); out: - unlock_kernel(); return err; } |