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) ...@@ -24,6 +24,20 @@ static inline void dir_put_page(struct page *page)
page_cache_release(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) static inline unsigned long dir_pages(struct inode *inode)
{ {
return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; 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) ...@@ -90,7 +104,7 @@ static int minix_readdir(struct file * filp, void * dirent, filldir_t filldir)
continue; continue;
kaddr = (char *)page_address(page); kaddr = (char *)page_address(page);
p = kaddr+offset; 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)) { for ( ; p <= limit ; p = minix_next_entry(p, sbi)) {
minix_dirent *de = (minix_dirent *)p; minix_dirent *de = (minix_dirent *)p;
if (de->inode) { if (de->inode) {
...@@ -154,7 +168,7 @@ minix_dirent *minix_find_entry(struct dentry *dentry, struct page **res_page) ...@@ -154,7 +168,7 @@ minix_dirent *minix_find_entry(struct dentry *dentry, struct page **res_page)
kaddr = (char*)page_address(page); kaddr = (char*)page_address(page);
de = (struct minix_dir_entry *) kaddr; 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)) { for ( ; (char *) de <= kaddr ; de = minix_next_entry(de,sbi)) {
if (!de->inode) if (!de->inode)
continue; continue;
...@@ -185,23 +199,37 @@ int minix_add_link(struct dentry *dentry, struct inode *inode) ...@@ -185,23 +199,37 @@ int minix_add_link(struct dentry *dentry, struct inode *inode)
unsigned from, to; unsigned from, to;
int err; 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++) { for (n = 0; n <= npages; n++) {
char *dir_end;
page = dir_get_page(dir, n); page = dir_get_page(dir, n);
err = PTR_ERR(page); err = PTR_ERR(page);
if (IS_ERR(page)) if (IS_ERR(page))
goto out; goto out;
lock_page(page);
kaddr = (char*)page_address(page); kaddr = (char*)page_address(page);
dir_end = kaddr + minix_last_byte(dir, n);
de = (minix_dirent *)kaddr; de = (minix_dirent *)kaddr;
kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize; kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize;
while ((char *)de <= kaddr) { while ((char *)de <= kaddr) {
if ((char *)de == dir_end) {
/* We hit i_size */
de->inode = 0;
goto got_it;
}
if (!de->inode) if (!de->inode)
goto got_it; goto got_it;
err = -EEXIST; err = -EEXIST;
if (namecompare(namelen,sbi->s_namelen,name,de->name)) if (namecompare(namelen,sbi->s_namelen,name,de->name))
goto out_page; goto out_unlock;
de = minix_next_entry(de, sbi); de = minix_next_entry(de, sbi);
} }
unlock_page(page);
dir_put_page(page); dir_put_page(page);
} }
BUG(); BUG();
...@@ -210,7 +238,6 @@ int minix_add_link(struct dentry *dentry, struct inode *inode) ...@@ -210,7 +238,6 @@ int minix_add_link(struct dentry *dentry, struct inode *inode)
got_it: got_it:
from = (char*)de - (char*)page_address(page); from = (char*)de - (char*)page_address(page);
to = from + sbi->s_dirsize; to = from + sbi->s_dirsize;
lock_page(page);
err = page->mapping->a_ops->prepare_write(NULL, page, from, to); err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
if (err) if (err)
goto out_unlock; goto out_unlock;
...@@ -221,8 +248,7 @@ int minix_add_link(struct dentry *dentry, struct inode *inode) ...@@ -221,8 +248,7 @@ int minix_add_link(struct dentry *dentry, struct inode *inode)
dir->i_mtime = dir->i_ctime = CURRENT_TIME; dir->i_mtime = dir->i_ctime = CURRENT_TIME;
mark_inode_dirty(dir); mark_inode_dirty(dir);
out_unlock: out_unlock:
UnlockPage(page); unlock_page(page);
out_page:
dir_put_page(page); dir_put_page(page);
out: out:
return err; return err;
...@@ -301,7 +327,7 @@ int minix_empty_dir(struct inode * inode) ...@@ -301,7 +327,7 @@ int minix_empty_dir(struct inode * inode)
kaddr = (char *)page_address(page); kaddr = (char *)page_address(page);
de = (minix_dirent *)kaddr; de = (minix_dirent *)kaddr;
kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize; kaddr += minix_last_byte(inode, i) - sbi->s_dirsize;
while ((char *)de <= kaddr) { while ((char *)de <= kaddr) {
if (de->inode != 0) { 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