This one modifies minixfs to not rely on the contents
of directory data outside i_size. (Minix actually
doesn't need this, because it works happily when
writepage is clearing the page outside i_size, but it's
neater this way).
--- 2.5.9/fs/minix/dir.c~dallocbase-85-minix_dir Wed Apr 24 01:06:10 2002
+++ 2.5.9-akpm/fs/minix/dir.c Wed Apr 24 01:45:06 2002
@@ -24,6 +24,20 @@ static inline void dir_put_page(struct p
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 * f
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 de
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
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
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 @@ got_it:
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) {
-
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/