Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+512 −477

File changed.

Preview size limit exceeded, changes collapsed.

+35 −27
Original line number Diff line number Diff line
/*
 * 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"

@@ -235,16 +237,15 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
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 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;
}

@@ -279,37 +279,37 @@ static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
{
	struct inode *old_inode = old_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 buffer_head *old_bh;
	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))
			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;
}

+5 −4
Original line number Diff line number Diff line
@@ -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;