[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>
This commit is contained in:
Evgeniy Dushistov 2006-06-25 05:47:22 -07:00 committed by Linus Torvalds
parent 826843a347
commit b71034e5e6
3 changed files with 557 additions and 513 deletions

File diff suppressed because it is too large Load diff

View file

@ -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;
}

View file

@ -887,11 +887,12 @@ extern struct inode_operations ufs_dir_inode_operations;
extern int ufs_add_link (struct dentry *, struct inode *);
extern ino_t ufs_inode_by_name(struct inode *, struct dentry *);
extern int ufs_make_empty(struct inode *, struct inode *);
extern struct ufs_dir_entry * ufs_find_entry (struct dentry *, struct buffer_head **);
extern int ufs_delete_entry (struct inode *, struct ufs_dir_entry *, struct buffer_head *);
extern struct ufs_dir_entry *ufs_find_entry(struct inode *, struct dentry *, struct page **);
extern int ufs_delete_entry(struct inode *, struct ufs_dir_entry *, struct page *);
extern int ufs_empty_dir (struct inode *);
extern struct ufs_dir_entry * ufs_dotdot (struct inode *, struct buffer_head **);
extern void ufs_set_link(struct inode *, struct ufs_dir_entry *, struct buffer_head *, struct inode *);
extern struct ufs_dir_entry *ufs_dotdot(struct inode *, struct page **);
extern void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
struct page *page, struct inode *inode);
/* file.c */
extern struct inode_operations ufs_file_inode_operations;