[patch] minixfs: don't rely on page contents outside i_size

From: Andrew Morton (akpm@zip.com.au)
Date: Wed Apr 24 2002 - 03:50:03 EST


This is the first of a bunch of patches which come after
the big writeback patch. Most of them are cleanups.
It's all still a couple of weeks out, but I may as well
unload them now, see if anyone has any comments.

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/



This archive was generated by hypermail 2b29 : Tue Apr 30 2002 - 22:00:08 EST