From b71034e5e67d1577424cebe7bbb7d0ce134a4cd8 Mon Sep 17 00:00:00 2001 From: Evgeniy Dushistov Date: Sun, 25 Jun 2006 05:47:22 -0700 Subject: [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 Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ufs/namei.c | 62 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 27 deletions(-) (limited to 'fs/ufs/namei.c') 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 based on ext2 code base. + * * Copyright (C) 1998 * Daniel Pirkl * Charles University, Faculty of Mathematics and Physics @@ -28,7 +31,6 @@ #include #include #include -#include #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; } -- cgit v1.2.1