minixfs: don't rely on page contents outside i_size
PATCH 1/1 minixfs: don't rely on page contents outside i_size
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).
fs/minix/dir.c renamed from fs/minix/dir.c~dallocbase-85-minix_dir +34 -8
@@ -24,6 +24,20 @@ static inline void dir_put_page(struct ppage_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 * fcontinue ; 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 *dentryunsigned 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 ) {
-