[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:
parent
826843a347
commit
b71034e5e6
999
fs/ufs/dir.c
999
fs/ufs/dir.c
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user