Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / fs / ufs / super.c
index 4347518..db98a4c 100644 (file)
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/bitops.h>
 
 #include <stdarg.h>
 
-#include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
@@ -221,7 +221,7 @@ void ufs_error (struct super_block * sb, const char * function,
        va_list args;
 
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
        
        if (!(sb->s_flags & MS_RDONLY)) {
                usb1->fs_clean = UFS_FSBAD;
@@ -253,7 +253,7 @@ void ufs_panic (struct super_block * sb, const char * function,
        va_list args;
        
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
        
        if (!(sb->s_flags & MS_RDONLY)) {
                usb1->fs_clean = UFS_FSBAD;
@@ -388,7 +388,8 @@ static int ufs_parse_options (char * options, unsigned * mount_options)
 /*
  * Read on-disk structures associated with cylinder groups
  */
-int ufs_read_cylinder_structures (struct super_block * sb) {
+static int ufs_read_cylinder_structures (struct super_block *sb)
+{
        struct ufs_sb_info * sbi = UFS_SB(sb);
        struct ufs_sb_private_info * uspi;
        struct ufs_super_block *usb;
@@ -415,26 +416,23 @@ int ufs_read_cylinder_structures (struct super_block * sb) {
        base = space = kmalloc(size, GFP_KERNEL);
        if (!base)
                goto failed; 
+       sbi->s_csp = (struct ufs_csum *)space;
        for (i = 0; i < blks; i += uspi->s_fpb) {
                size = uspi->s_bsize;
                if (i + uspi->s_fpb > blks)
                        size = (blks - i) * uspi->s_fsize;
 
-               if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+               if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) 
                        ubh = ubh_bread(sb,
                                fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_csaddr) + i, size);
-                       if (!ubh)
-                               goto failed;
-                       ubh_ubhcpymem (space, ubh, size);
-                       sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space;
-               }
-               else {
+               else 
                        ubh = ubh_bread(sb, uspi->s_csaddr + i, size);
-                       if (!ubh)
-                               goto failed;
-                       ubh_ubhcpymem(space, ubh, size);
-                       sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space;
-               }
+               
+               if (!ubh)
+                       goto failed;
+
+               ubh_ubhcpymem (space, ubh, size);
+
                space += size;
                ubh_brelse (ubh);
                ubh = NULL;
@@ -472,13 +470,14 @@ int ufs_read_cylinder_structures (struct super_block * sb) {
        return 1;
 
 failed:
-       if (base) kfree (base);
+       kfree (base);
        if (sbi->s_ucg) {
                for (i = 0; i < uspi->s_ncg; i++)
-                       if (sbi->s_ucg[i]) brelse (sbi->s_ucg[i]);
+                       if (sbi->s_ucg[i])
+                               brelse (sbi->s_ucg[i]);
                kfree (sbi->s_ucg);
                for (i = 0; i < UFS_MAX_GROUP_LOADED; i++)
-                       if (sbi->s_ucpi[i]) kfree (sbi->s_ucpi[i]);
+                       kfree (sbi->s_ucpi[i]);
        }
        UFSD(("EXIT (FAILED)\n"))
        return 0;
@@ -488,7 +487,8 @@ failed:
  * Put on-disk structures associated with cylinder groups and 
  * write them back to disk
  */
-void ufs_put_cylinder_structures (struct super_block * sb) {
+static void ufs_put_cylinder_structures (struct super_block *sb)
+{
        struct ufs_sb_info * sbi = UFS_SB(sb);
        struct ufs_sb_private_info * uspi;
        struct ufs_buffer_head * ubh;
@@ -501,7 +501,7 @@ void ufs_put_cylinder_structures (struct super_block * sb) {
 
        size = uspi->s_cssize;
        blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift;
-       base = space = (char*) sbi->s_csp[0];
+       base = space = (char*) sbi->s_csp;
        for (i = 0; i < blks; i += uspi->s_fpb) {
                size = uspi->s_bsize;
                if (i + uspi->s_fpb > blks)
@@ -538,6 +538,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
        struct inode *inode;
        unsigned block_size, super_block_size;
        unsigned flags;
+       unsigned super_block_offset;
 
        uspi = NULL;
        ubh = NULL;
@@ -574,7 +575,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
                if (!silent)
                        printk("You didn't specify the type of your ufs filesystem\n\n"
                        "mount -t ufs -o ufstype="
-                       "sun|sunx86|44bsd|ufs2|5xbsd|old|hp|nextstep|netxstep-cd|openstep ...\n\n"
+                       "sun|sunx86|44bsd|ufs2|5xbsd|old|hp|nextstep|nextstep-cd|openstep ...\n\n"
                        ">>>WARNING<<< Wrong ufstype may corrupt your filesystem, "
                        "default is ufstype=old\n");
                ufs_set_opt (sbi->s_mount_opt, UFSTYPE_OLD);
@@ -585,10 +586,11 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
        if (!uspi)
                goto failed;
 
+       super_block_offset=UFS_SBLOCK;
+
        /* Keep 2Gig file limit. Some UFS variants need to override 
           this but as I don't know which I'll let those in the know loosen
           the rules */
-          
        switch (sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) {
        case UFS_MOUNT_UFSTYPE_44BSD:
                UFSD(("ufstype=44bsd\n"))
@@ -600,7 +602,8 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
                flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
                break;
        case UFS_MOUNT_UFSTYPE_UFS2:
-               UFSD(("ufstype=ufs2\n"))
+               UFSD(("ufstype=ufs2\n"));
+               super_block_offset=SBLOCK_UFS2;
                uspi->s_fsize = block_size = 512;
                uspi->s_fmask = ~(512 - 1);
                uspi->s_fshift = 9;
@@ -724,41 +727,38 @@ again:
        /*
         * read ufs super block from device
         */
-       if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
-               ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + SBLOCK_UFS2/block_size, super_block_size);
-       }
-       else {
-               ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size);
-       }
+
+       ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + super_block_offset/block_size, super_block_size);
+       
        if (!ubh) 
             goto failed;
 
        
-       usb1 = ubh_get_usb_first(USPI_UBH);
-       usb2 = ubh_get_usb_second(USPI_UBH);
-       usb3 = ubh_get_usb_third(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
+       usb2 = ubh_get_usb_second(uspi);
+       usb3 = ubh_get_usb_third(uspi);
        usb  = (struct ufs_super_block *)
                ((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
 
        /*
         * Check ufs magic number
         */
-       switch ((uspi->fs_magic = __constant_le32_to_cpu(usb3->fs_magic))) {
+       sbi->s_bytesex = BYTESEX_LE;
+       switch ((uspi->fs_magic = fs32_to_cpu(sb, usb3->fs_magic))) {
                case UFS_MAGIC:
                case UFS2_MAGIC:
                case UFS_MAGIC_LFN:
                case UFS_MAGIC_FEA:
                case UFS_MAGIC_4GB:
-                       sbi->s_bytesex = BYTESEX_LE;
                        goto magic_found;
        }
-       switch ((uspi->fs_magic = __constant_be32_to_cpu(usb3->fs_magic))) {
+       sbi->s_bytesex = BYTESEX_BE;
+       switch ((uspi->fs_magic = fs32_to_cpu(sb, usb3->fs_magic))) {
                case UFS_MAGIC:
                case UFS2_MAGIC:
                case UFS_MAGIC_LFN:
                case UFS_MAGIC_FEA:
                case UFS_MAGIC_4GB:
-                       sbi->s_bytesex = BYTESEX_BE;
                        goto magic_found;
        }
 
@@ -981,9 +981,10 @@ magic_found:
 dalloc_failed:
        iput(inode);
 failed:
-       if (ubh) ubh_brelse_uspi (uspi);
-       if (uspi) kfree (uspi);
-       if (sbi) kfree(sbi);
+       if (ubh)
+               ubh_brelse_uspi (uspi);
+       kfree (uspi);
+       kfree(sbi);
        sb->s_fs_info = NULL;
        UFSD(("EXIT (FAILED)\n"))
        return -EINVAL;
@@ -993,7 +994,7 @@ failed_nomem:
        return -ENOMEM;
 }
 
-void ufs_write_super (struct super_block * sb) {
+static void ufs_write_super (struct super_block *sb) {
        struct ufs_sb_private_info * uspi;
        struct ufs_super_block_first * usb1;
        struct ufs_super_block_third * usb3;
@@ -1004,8 +1005,8 @@ void ufs_write_super (struct super_block * sb) {
        UFSD(("ENTER\n"))
        flags = UFS_SB(sb)->s_flags;
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(USPI_UBH);
-       usb3 = ubh_get_usb_third(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
+       usb3 = ubh_get_usb_third(uspi);
 
        if (!(sb->s_flags & MS_RDONLY)) {
                usb1->fs_time = cpu_to_fs32(sb, get_seconds());
@@ -1020,7 +1021,7 @@ void ufs_write_super (struct super_block * sb) {
        unlock_kernel();
 }
 
-void ufs_put_super (struct super_block * sb)
+static void ufs_put_super (struct super_block *sb)
 {
        struct ufs_sb_info * sbi = UFS_SB(sb);
                
@@ -1037,7 +1038,7 @@ void ufs_put_super (struct super_block * sb)
 }
 
 
-int ufs_remount (struct super_block * sb, int * mount_flags, char * data)
+static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
 {
        struct ufs_sb_private_info * uspi;
        struct ufs_super_block_first * usb1;
@@ -1047,8 +1048,8 @@ int ufs_remount (struct super_block * sb, int * mount_flags, char * data)
        
        uspi = UFS_SB(sb)->s_uspi;
        flags = UFS_SB(sb)->s_flags;
-       usb1 = ubh_get_usb_first(USPI_UBH);
-       usb3 = ubh_get_usb_third(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
+       usb3 = ubh_get_usb_third(uspi);
        
        /*
         * Allow the "check" option to be passed as a remount option.
@@ -1112,7 +1113,7 @@ int ufs_remount (struct super_block * sb, int * mount_flags, char * data)
        return 0;
 }
 
-int ufs_statfs (struct super_block * sb, struct kstatfs * buf)
+static int ufs_statfs (struct super_block *sb, struct kstatfs *buf)
 {
        struct ufs_sb_private_info * uspi;
        struct ufs_super_block_first * usb1;
@@ -1122,14 +1123,14 @@ int ufs_statfs (struct super_block * sb, struct kstatfs * buf)
        lock_kernel();
 
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first (USPI_UBH);
+       usb1 = ubh_get_usb_first (uspi);
        usb  = (struct ufs_super_block *)
                ((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
        
        flags = UFS_SB(sb)->s_flags;
        if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
                buf->f_type = UFS2_MAGIC;
-               buf->f_blocks = usb->fs_u11.fs_u2.fs_dsize;
+               buf->f_blocks = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize);
                buf->f_bfree = ufs_blkstofrags(fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree)) +
                        fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nffree);
                buf->f_ffree = fs64_to_cpu(sb,
@@ -1183,7 +1184,8 @@ static int init_inodecache(void)
 {
        ufs_inode_cachep = kmem_cache_create("ufs_inode_cache",
                                             sizeof(struct ufs_inode_info),
-                                            0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+                                            0, (SLAB_RECLAIM_ACCOUNT|
+                                               SLAB_MEM_SPREAD),
                                             init_once, NULL);
        if (ufs_inode_cachep == NULL)
                return -ENOMEM;
@@ -1196,6 +1198,11 @@ static void destroy_inodecache(void)
                printk(KERN_INFO "ufs_inode_cache: not all structures were freed\n");
 }
 
+#ifdef CONFIG_QUOTA
+static ssize_t ufs_quota_read(struct super_block *, int, char *,size_t, loff_t);
+static ssize_t ufs_quota_write(struct super_block *, int, const char *, size_t, loff_t);
+#endif
+
 static struct super_operations ufs_super_ops = {
        .alloc_inode    = ufs_alloc_inode,
        .destroy_inode  = ufs_destroy_inode,
@@ -1206,8 +1213,104 @@ static struct super_operations ufs_super_ops = {
        .write_super    = ufs_write_super,
        .statfs         = ufs_statfs,
        .remount_fs     = ufs_remount,
+#ifdef CONFIG_QUOTA
+       .quota_read     = ufs_quota_read,
+       .quota_write    = ufs_quota_write,
+#endif
 };
 
+#ifdef CONFIG_QUOTA
+
+/* Read data from quotafile - avoid pagecache and such because we cannot afford
+ * acquiring the locks... As quota files are never truncated and quota code
+ * itself serializes the operations (and noone else should touch the files)
+ * we don't have to be afraid of races */
+static ssize_t ufs_quota_read(struct super_block *sb, int type, char *data,
+                              size_t len, loff_t off)
+{
+       struct inode *inode = sb_dqopt(sb)->files[type];
+       sector_t blk = off >> sb->s_blocksize_bits;
+       int err = 0;
+       int offset = off & (sb->s_blocksize - 1);
+       int tocopy;
+       size_t toread;
+       struct buffer_head *bh;
+       loff_t i_size = i_size_read(inode);
+
+       if (off > i_size)
+               return 0;
+       if (off+len > i_size)
+               len = i_size-off;
+       toread = len;
+       while (toread > 0) {
+               tocopy = sb->s_blocksize - offset < toread ?
+                               sb->s_blocksize - offset : toread;
+
+               bh = ufs_bread(inode, blk, 0, &err);
+               if (err)
+                       return err;
+               if (!bh)        /* A hole? */
+                       memset(data, 0, tocopy);
+               else {
+                       memcpy(data, bh->b_data+offset, tocopy);
+                       brelse(bh);
+               }
+               offset = 0;
+               toread -= tocopy;
+               data += tocopy;
+               blk++;
+       }
+       return len;
+}
+
+/* Write to quotafile */
+static ssize_t ufs_quota_write(struct super_block *sb, int type,
+                               const char *data, size_t len, loff_t off)
+{
+       struct inode *inode = sb_dqopt(sb)->files[type];
+       sector_t blk = off >> sb->s_blocksize_bits;
+       int err = 0;
+       int offset = off & (sb->s_blocksize - 1);
+       int tocopy;
+       size_t towrite = len;
+       struct buffer_head *bh;
+
+       mutex_lock(&inode->i_mutex);
+       while (towrite > 0) {
+               tocopy = sb->s_blocksize - offset < towrite ?
+                               sb->s_blocksize - offset : towrite;
+
+               bh = ufs_bread(inode, blk, 1, &err);
+               if (!bh)
+                       goto out;
+               lock_buffer(bh);
+               memcpy(bh->b_data+offset, data, tocopy);
+               flush_dcache_page(bh->b_page);
+               set_buffer_uptodate(bh);
+               mark_buffer_dirty(bh);
+               unlock_buffer(bh);
+               brelse(bh);
+               offset = 0;
+               towrite -= tocopy;
+               data += tocopy;
+               blk++;
+       }
+out:
+       if (len == towrite) {
+               mutex_unlock(&inode->i_mutex);
+               return err;
+       }
+       if (inode->i_size < off+len-towrite)
+               i_size_write(inode, off+len-towrite);
+       inode->i_version++;
+       inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+       mark_inode_dirty(inode);
+       mutex_unlock(&inode->i_mutex);
+       return len - towrite;
+}
+
+#endif
+
 static struct super_block *ufs_get_sb(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
 {