Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 21 Nov 2011 20:10:47 +0000 (12:10 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 21 Nov 2011 20:10:47 +0000 (12:10 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  VFS: Log the fact that we've given ELOOP rather than creating a loop
  minixfs: kill manual hweight(), simplify
  fs/minix: Verify bitmap block counts before mounting

fs/dcache.c
fs/minix/bitmap.c
fs/minix/inode.c
fs/minix/minix.h

index a901c6901bce1cf0a8b1823e8c87d83424594474..10ba92def3f675985871f0fc72e9c6d7126357a3 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/bit_spinlock.h>
 #include <linux/rculist_bl.h>
 #include <linux/prefetch.h>
+#include <linux/ratelimit.h>
 #include "internal.h"
 
 /*
@@ -2383,8 +2384,16 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
                                actual = __d_unalias(inode, dentry, alias);
                        }
                        write_sequnlock(&rename_lock);
-                       if (IS_ERR(actual))
+                       if (IS_ERR(actual)) {
+                               if (PTR_ERR(actual) == -ELOOP)
+                                       pr_warn_ratelimited(
+                                               "VFS: Lookup of '%s' in %s %s"
+                                               " would have caused loop\n",
+                                               dentry->d_name.name,
+                                               inode->i_sb->s_type->name,
+                                               inode->i_sb->s_id);
                                dput(alias);
+                       }
                        goto out_nolock;
                }
        }
index 3f32bcb0d9bd5beb882b67480ff3593d202f5837..ef175cb8cfd8e20be4be8496660521a371297a50 100644 (file)
 #include <linux/bitops.h>
 #include <linux/sched.h>
 
-static const int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 };
-
 static DEFINE_SPINLOCK(bitmap_lock);
 
-static unsigned long count_free(struct buffer_head *map[], unsigned numblocks, __u32 numbits)
+/*
+ * bitmap consists of blocks filled with 16bit words
+ * bit set == busy, bit clear == free
+ * endianness is a mess, but for counting zero bits it really doesn't matter...
+ */
+static __u32 count_free(struct buffer_head *map[], unsigned blocksize, __u32 numbits)
 {
-       unsigned i, j, sum = 0;
-       struct buffer_head *bh;
-  
-       for (i=0; i<numblocks-1; i++) {
-               if (!(bh=map[i])) 
-                       return(0);
-               for (j=0; j<bh->b_size; j++)
-                       sum += nibblemap[bh->b_data[j] & 0xf]
-                               + nibblemap[(bh->b_data[j]>>4) & 0xf];
-       }
+       __u32 sum = 0;
+       unsigned blocks = DIV_ROUND_UP(numbits, blocksize * 8);
 
-       if (numblocks==0 || !(bh=map[numblocks-1]))
-               return(0);
-       i = ((numbits - (numblocks-1) * bh->b_size * 8) / 16) * 2;
-       for (j=0; j<i; j++) {
-               sum += nibblemap[bh->b_data[j] & 0xf]
-                       + nibblemap[(bh->b_data[j]>>4) & 0xf];
+       while (blocks--) {
+               unsigned words = blocksize / 2;
+               __u16 *p = (__u16 *)(*map++)->b_data;
+               while (words--)
+                       sum += 16 - hweight16(*p++);
        }
 
-       i = numbits%16;
-       if (i!=0) {
-               i = *(__u16 *)(&bh->b_data[j]) | ~((1<<i) - 1);
-               sum += nibblemap[i & 0xf] + nibblemap[(i>>4) & 0xf];
-               sum += nibblemap[(i>>8) & 0xf] + nibblemap[(i>>12) & 0xf];
-       }
-       return(sum);
+       return sum;
 }
 
 void minix_free_block(struct inode *inode, unsigned long block)
@@ -105,10 +93,12 @@ int minix_new_block(struct inode * inode)
        return 0;
 }
 
-unsigned long minix_count_free_blocks(struct minix_sb_info *sbi)
+unsigned long minix_count_free_blocks(struct super_block *sb)
 {
-       return (count_free(sbi->s_zmap, sbi->s_zmap_blocks,
-               sbi->s_nzones - sbi->s_firstdatazone + 1)
+       struct minix_sb_info *sbi = minix_sb(sb);
+       u32 bits = sbi->s_nzones - (sbi->s_firstdatazone + 1);
+
+       return (count_free(sbi->s_zmap, sb->s_blocksize, bits)
                << sbi->s_log_zone_size);
 }
 
@@ -273,7 +263,10 @@ struct inode *minix_new_inode(const struct inode *dir, int mode, int *error)
        return inode;
 }
 
-unsigned long minix_count_free_inodes(struct minix_sb_info *sbi)
+unsigned long minix_count_free_inodes(struct super_block *sb)
 {
-       return count_free(sbi->s_imap, sbi->s_imap_blocks, sbi->s_ninodes + 1);
+       struct minix_sb_info *sbi = minix_sb(sb);
+       u32 bits = sbi->s_ninodes + 1;
+
+       return count_free(sbi->s_imap, sb->s_blocksize, bits);
 }
index 64cdcd662ffccca98fecad85103f10a2348a76bc..1d9e33966db089eb2ba5ed3f7aab9967bd2c0b4e 100644 (file)
@@ -279,6 +279,27 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
        else if (sbi->s_mount_state & MINIX_ERROR_FS)
                printk("MINIX-fs: mounting file system with errors, "
                        "running fsck is recommended\n");
+
+       /* Apparently minix can create filesystems that allocate more blocks for
+        * the bitmaps than needed.  We simply ignore that, but verify it didn't
+        * create one with not enough blocks and bail out if so.
+        */
+       block = minix_blocks_needed(sbi->s_ninodes, s->s_blocksize);
+       if (sbi->s_imap_blocks < block) {
+               printk("MINIX-fs: file system does not have enough "
+                               "imap blocks allocated.  Refusing to mount\n");
+               goto out_iput;
+       }
+
+       block = minix_blocks_needed(
+                       (sbi->s_nzones - (sbi->s_firstdatazone + 1)),
+                       s->s_blocksize);
+       if (sbi->s_zmap_blocks < block) {
+               printk("MINIX-fs: file system does not have enough "
+                               "zmap blocks allocated.  Refusing to mount.\n");
+               goto out_iput;
+       }
+
        return 0;
 
 out_iput:
@@ -339,10 +360,10 @@ static int minix_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_type = sb->s_magic;
        buf->f_bsize = sb->s_blocksize;
        buf->f_blocks = (sbi->s_nzones - sbi->s_firstdatazone) << sbi->s_log_zone_size;
-       buf->f_bfree = minix_count_free_blocks(sbi);
+       buf->f_bfree = minix_count_free_blocks(sb);
        buf->f_bavail = buf->f_bfree;
        buf->f_files = sbi->s_ninodes;
-       buf->f_ffree = minix_count_free_inodes(sbi);
+       buf->f_ffree = minix_count_free_inodes(sb);
        buf->f_namelen = sbi->s_namelen;
        buf->f_fsid.val[0] = (u32)id;
        buf->f_fsid.val[1] = (u32)(id >> 32);
index 341e2122879a7604611426d4f702f211ee3ed59a..26bbd55e82ea2ab42f61fa2898fd45fee17f7074 100644 (file)
@@ -48,10 +48,10 @@ extern struct minix_inode * minix_V1_raw_inode(struct super_block *, ino_t, stru
 extern struct minix2_inode * minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **);
 extern struct inode * minix_new_inode(const struct inode *, int, int *);
 extern void minix_free_inode(struct inode * inode);
-extern unsigned long minix_count_free_inodes(struct minix_sb_info *sbi);
+extern unsigned long minix_count_free_inodes(struct super_block *sb);
 extern int minix_new_block(struct inode * inode);
 extern void minix_free_block(struct inode *inode, unsigned long block);
-extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi);
+extern unsigned long minix_count_free_blocks(struct super_block *sb);
 extern int minix_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern int minix_prepare_chunk(struct page *page, loff_t pos, unsigned len);
 
@@ -88,6 +88,11 @@ static inline struct minix_inode_info *minix_i(struct inode *inode)
        return list_entry(inode, struct minix_inode_info, vfs_inode);
 }
 
+static inline unsigned minix_blocks_needed(unsigned bits, unsigned blocksize)
+{
+       return DIV_ROUND_UP(bits, blocksize * 8);
+}
+
 #if defined(CONFIG_MINIX_FS_NATIVE_ENDIAN) && \
        defined(CONFIG_MINIX_FS_BIG_ENDIAN_16BIT_INDEXED)
 
@@ -125,7 +130,7 @@ static inline int minix_find_first_zero_bit(const void *vaddr, unsigned size)
        if (!size)
                return 0;
 
-       size = (size >> 4) + ((size & 15) > 0);
+       size >>= 4;
        while (*p++ == 0xffff) {
                if (--size == 0)
                        return (p - addr) << 4;