• R/O
  • HTTP
  • SSH
  • HTTPS

linux-2.4.36: Commit

2.4.36-stable kernel tree


Commit MetaInfo

Revision72a9d5aa5e1e1602f861f8b893d8d57a08f30734 (tree)
Zeit2008-04-16 17:06:58
AutorGlen Nakamura <glen@imod...>
CommiterWilly Tarreau

Log Message

ext2_readdir() filp->f_pos fix (try #2)

This patch reintroduces a fixed version of reverted commit
c30306fb287323591c854a0982d9fa5351859b45 from Dann Frazier :

This is a 2.4 backport of a linux-2.6 change by Jan Blunck
(old-2.6-bkcvs commit 2196b4744393d4f6c06fc4d63b98556d05b90933)
Commit log from 2.6 follows.
[PATCH] ext2_readdir() filp->f_pos fix
If the whole directory is read, ext2_readdir() sets the f_pos to a multiple
of the page size (because of the conditions of the outer for loop). This
sets the wrong f_pos for directory inodes on ext2 partitions with a block
size differing from the page size.

Note from Glen :

Perhaps the "filp->f_pos += le16_to_cpu(de->rec_len);" line should be
outside of the if statement like the indentation implies?
As it is, filp->f_pos gets corrupted if de->inode is ever zero...
This could possibly explain why I had a few strange directory
entries until I checked the filesystem with:
e2fsck -D -F -f /dev/{ext2 partition}

This fix was confirmed by both Dann Frazier and Pascal Hambourg.

Note from Willy :

The code now differs from 2.6 only by commit
2d7f2ea9c989853310c7f6e8be52cc090cc8e66b which is only in 2.6.

The reporter, Al Masoud, provided the test case which could not be
reproduced on 2.4 (neither with nor without the fix above), so the
patch in question has *not* been applied to 2.4.

Dann will take the same approach for the Debian update.

Ändern Zusammenfassung

Diff

--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -240,7 +240,7 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
240240 loff_t pos = filp->f_pos;
241241 struct inode *inode = filp->f_dentry->d_inode;
242242 struct super_block *sb = inode->i_sb;
243- unsigned offset = pos & ~PAGE_CACHE_MASK;
243+ unsigned int offset = pos & ~PAGE_CACHE_MASK;
244244 unsigned long n = pos >> PAGE_CACHE_SHIFT;
245245 unsigned long npages = dir_pages(inode);
246246 unsigned chunk_mask = ~(ext2_chunk_size(inode)-1);
@@ -260,6 +260,10 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
260260 struct page *page = ext2_get_page(inode, n);
261261
262262 if (IS_ERR(page)) {
263+ ext2_error(sb, __FUNCTION__,
264+ "bad page in #%lu",
265+ inode->i_ino);
266+ filp->f_pos += PAGE_CACHE_SIZE - offset;
263267 ret = -EIO;
264268 goto done;
265269 }
@@ -270,7 +274,7 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
270274 }
271275 de = (ext2_dirent *)(kaddr+offset);
272276 limit = kaddr + PAGE_CACHE_SIZE - EXT2_DIR_REC_LEN(1);
273- for ( ;(char*)de <= limit; de = ext2_next_entry(de))
277+ for ( ;(char*)de <= limit; de = ext2_next_entry(de)) {
274278 if (de->inode) {
275279 int over;
276280 unsigned char d_type = DT_UNKNOWN;
@@ -287,11 +291,12 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
287291 goto done;
288292 }
289293 }
294+ filp->f_pos += le16_to_cpu(de->rec_len);
295+ }
290296 ext2_put_page(page);
291297 }
292298
293299 done:
294- filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
295300 filp->f_version = inode->i_version;
296301 UPDATE_ATIME(inode);
297302 return ret;
Show on old repository browser