Commit b71034e5 authored by Evgeniy Dushistov's avatar Evgeniy Dushistov Committed by Linus Torvalds

[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: default avatarEvgeniy Dushistov <dushistov@mail.ru>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 826843a3
This diff is collapsed.
/* /*
* linux/fs/ufs/namei.c * 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 * Copyright (C) 1998
* Daniel Pirkl <daniel.pirkl@email.cz> * Daniel Pirkl <daniel.pirkl@email.cz>
* Charles University, Faculty of Mathematics and Physics * Charles University, Faculty of Mathematics and Physics
...@@ -28,7 +31,6 @@ ...@@ -28,7 +31,6 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ufs_fs.h> #include <linux/ufs_fs.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include "swab.h" /* will go away - see comment in mknod() */ #include "swab.h" /* will go away - see comment in mknod() */
#include "util.h" #include "util.h"
...@@ -232,19 +234,18 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode) ...@@ -232,19 +234,18 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
goto out; 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 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; int err = -ENOENT;
lock_kernel(); de = ufs_find_entry(dir, dentry, &page);
de = ufs_find_entry (dentry, &bh);
if (!de) if (!de)
goto out; goto out;
err = ufs_delete_entry (dir, de, bh); err = ufs_delete_entry(dir, de, page);
if (err) if (err)
goto out; goto out;
...@@ -252,7 +253,6 @@ static int ufs_unlink(struct inode * dir, struct dentry *dentry) ...@@ -252,7 +253,6 @@ static int ufs_unlink(struct inode * dir, struct dentry *dentry)
inode_dec_link_count(inode); inode_dec_link_count(inode);
err = 0; err = 0;
out: out:
unlock_kernel();
return err; return err;
} }
...@@ -274,42 +274,42 @@ static int ufs_rmdir (struct inode * dir, struct dentry *dentry) ...@@ -274,42 +274,42 @@ static int ufs_rmdir (struct inode * dir, struct dentry *dentry)
return err; return err;
} }
static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry, static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode * new_dir, struct dentry * new_dentry ) struct inode *new_dir, struct dentry *new_dentry)
{ {
struct inode *old_inode = old_dentry->d_inode; struct inode *old_inode = old_dentry->d_inode;
struct inode *new_inode = new_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode;
struct buffer_head *dir_bh = NULL; struct page *dir_page = NULL;
struct ufs_dir_entry *dir_de = NULL; struct ufs_dir_entry * dir_de = NULL;
struct buffer_head *old_bh; struct page *old_page;
struct ufs_dir_entry *old_de; struct ufs_dir_entry *old_de;
int err = -ENOENT; int err = -ENOENT;
lock_kernel(); old_de = ufs_find_entry(old_dir, old_dentry, &old_page);
old_de = ufs_find_entry (old_dentry, &old_bh);
if (!old_de) if (!old_de)
goto out; goto out;
if (S_ISDIR(old_inode->i_mode)) { if (S_ISDIR(old_inode->i_mode)) {
err = -EIO; err = -EIO;
dir_de = ufs_dotdot(old_inode, &dir_bh); dir_de = ufs_dotdot(old_inode, &dir_page);
if (!dir_de) if (!dir_de)
goto out_old; goto out_old;
} }
if (new_inode) { if (new_inode) {
struct buffer_head *new_bh; struct page *new_page;
struct ufs_dir_entry *new_de; struct ufs_dir_entry *new_de;
err = -ENOTEMPTY; err = -ENOTEMPTY;
if (dir_de && !ufs_empty_dir (new_inode)) if (dir_de && !ufs_empty_dir(new_inode))
goto out_dir; goto out_dir;
err = -ENOENT; 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) if (!new_de)
goto out_dir; goto out_dir;
inode_inc_link_count(old_inode); 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; new_inode->i_ctime = CURRENT_TIME_SEC;
if (dir_de) if (dir_de)
new_inode->i_nlink--; new_inode->i_nlink--;
...@@ -330,24 +330,32 @@ static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry, ...@@ -330,24 +330,32 @@ static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
inode_inc_link_count(new_dir); 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); inode_dec_link_count(old_inode);
if (dir_de) { 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); inode_dec_link_count(old_dir);
} }
unlock_kernel();
return 0; return 0;
out_dir: out_dir:
if (dir_de) if (dir_de) {
brelse(dir_bh); kunmap(dir_page);
page_cache_release(dir_page);
}
out_old: out_old:
brelse (old_bh); kunmap(old_page);
page_cache_release(old_page);
out: out:
unlock_kernel();
return err; return err;
} }
......
...@@ -887,11 +887,12 @@ extern struct inode_operations ufs_dir_inode_operations; ...@@ -887,11 +887,12 @@ extern struct inode_operations ufs_dir_inode_operations;
extern int ufs_add_link (struct dentry *, struct inode *); extern int ufs_add_link (struct dentry *, struct inode *);
extern ino_t ufs_inode_by_name(struct inode *, struct dentry *); extern ino_t ufs_inode_by_name(struct inode *, struct dentry *);
extern int ufs_make_empty(struct inode *, struct inode *); extern int ufs_make_empty(struct inode *, struct inode *);
extern struct ufs_dir_entry * ufs_find_entry (struct dentry *, 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 buffer_head *); extern int ufs_delete_entry(struct inode *, struct ufs_dir_entry *, struct page *);
extern int ufs_empty_dir (struct inode *); extern int ufs_empty_dir (struct inode *);
extern struct ufs_dir_entry * ufs_dotdot (struct inode *, struct buffer_head **); extern struct ufs_dir_entry *ufs_dotdot(struct inode *, struct page **);
extern void ufs_set_link(struct inode *, struct ufs_dir_entry *, struct buffer_head *, struct inode *); extern void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
struct page *page, struct inode *inode);
/* file.c */ /* file.c */
extern struct inode_operations ufs_file_inode_operations; extern struct inode_operations ufs_file_inode_operations;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment