Commit 68872e78 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] minix directory handling

Convert minixfs directory code to not rely on the state of data outside
i_size.
parent 4beda7c1
......@@ -24,6 +24,20 @@ static inline void dir_put_page(struct page *page)
page_cache_release(page);
}
/*
* Return the offset into page `page_nr' of the last valid
* byte in that page, plus one.
*/
static unsigned
minix_last_byte(struct inode *inode, unsigned long page_nr)
{
unsigned last_byte = PAGE_CACHE_SIZE;
if (page_nr == (inode->i_size >> PAGE_CACHE_SHIFT))
last_byte = inode->i_size & (PAGE_CACHE_SIZE - 1);
return last_byte;
}
static inline unsigned long dir_pages(struct inode *inode)
{
return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
......@@ -90,7 +104,7 @@ static int minix_readdir(struct file * filp, void * dirent, filldir_t filldir)
continue;
kaddr = (char *)page_address(page);
p = kaddr+offset;
limit = kaddr + PAGE_CACHE_SIZE - chunk_size;
limit = kaddr + minix_last_byte(inode, n) - chunk_size;
for ( ; p <= limit ; p = minix_next_entry(p, sbi)) {
minix_dirent *de = (minix_dirent *)p;
if (de->inode) {
......@@ -154,7 +168,7 @@ minix_dirent *minix_find_entry(struct dentry *dentry, struct page **res_page)
kaddr = (char*)page_address(page);
de = (struct minix_dir_entry *) kaddr;
kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize;
kaddr += minix_last_byte(dir, n) - sbi->s_dirsize;
for ( ; (char *) de <= kaddr ; de = minix_next_entry(de,sbi)) {
if (!de->inode)
continue;
......@@ -185,23 +199,37 @@ int minix_add_link(struct dentry *dentry, struct inode *inode)
unsigned from, to;
int err;
/* We take care of directory expansion in the same loop */
/*
* We take care of directory expansion in the same loop
* This code plays outside i_size, so it locks the page
* to protect that region.
*/
for (n = 0; n <= npages; n++) {
char *dir_end;
page = dir_get_page(dir, n);
err = PTR_ERR(page);
if (IS_ERR(page))
goto out;
lock_page(page);
kaddr = (char*)page_address(page);
dir_end = kaddr + minix_last_byte(dir, n);
de = (minix_dirent *)kaddr;
kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize;
while ((char *)de <= kaddr) {
if ((char *)de == dir_end) {
/* We hit i_size */
de->inode = 0;
goto got_it;
}
if (!de->inode)
goto got_it;
err = -EEXIST;
if (namecompare(namelen,sbi->s_namelen,name,de->name))
goto out_page;
goto out_unlock;
de = minix_next_entry(de, sbi);
}
unlock_page(page);
dir_put_page(page);
}
BUG();
......@@ -210,7 +238,6 @@ int minix_add_link(struct dentry *dentry, struct inode *inode)
got_it:
from = (char*)de - (char*)page_address(page);
to = from + sbi->s_dirsize;
lock_page(page);
err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
if (err)
goto out_unlock;
......@@ -221,8 +248,7 @@ int minix_add_link(struct dentry *dentry, struct inode *inode)
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
mark_inode_dirty(dir);
out_unlock:
UnlockPage(page);
out_page:
unlock_page(page);
dir_put_page(page);
out:
return err;
......@@ -301,7 +327,7 @@ int minix_empty_dir(struct inode * inode)
kaddr = (char *)page_address(page);
de = (minix_dirent *)kaddr;
kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize;
kaddr += minix_last_byte(inode, i) - sbi->s_dirsize;
while ((char *)de <= kaddr) {
if (de->inode != 0) {
......
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