/* * Read on-disk structures associated with cylinder groups */ int ufs_read_cylinder_structures (struct super_block * sb) { struct ufs_sb_private_info * uspi; struct ufs_buffer_head * ubh; unsigned char * base, * space; unsigned size, blks, i; UFSD(("ENTER\n")) uspi = sb->u.ufs_sb.s_uspi; /* * Read cs structures from (usually) first data block * on the device. */ size = uspi->s_cssize; blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift; base = space = kmalloc(size, GFP_KERNEL); if (!base) goto failed; 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; ubh = ubh_bread(sb, uspi->s_csaddr + i, size); if (!ubh) goto failed; ubh_ubhcpymem (space, ubh, size); sb->u.ufs_sb.s_csp[ufs_fragstoblks(i)] = (struct ufs_csum *)space; space += size; ubh_brelse (ubh); ubh = NULL; } /* * Read cylinder group (we read only first fragment from block * at this time) and prepare internal data structures for cg caching. */ if (!(sb->u.ufs_sb.s_ucg = kmalloc (sizeof(struct buffer_head *) * uspi->s_ncg, GFP_KERNEL))) goto failed; for (i = 0; i < uspi->s_ncg; i++) sb->u.ufs_sb.s_ucg[i] = NULL; for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) { sb->u.ufs_sb.s_ucpi[i] = NULL; sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY; } for (i = 0; i < uspi->s_ncg; i++) { UFSD(("read cg %u\n", i)) if (!(sb->u.ufs_sb.s_ucg[i] = sb_bread(sb, ufs_cgcmin(i)))) goto failed; if (!ufs_cg_chkmagic (sb, (struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data)) goto failed; #ifdef UFS_SUPER_DEBUG_MORE ufs_print_cylinder_stuff(sb, (struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data); #endif } for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) { if (!(sb->u.ufs_sb.s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL))) goto failed; sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY; } sb->u.ufs_sb.s_cg_loaded = 0; UFSD(("EXIT\n")) return 1; failed: if (base) kfree (base); if (sb->u.ufs_sb.s_ucg) { for (i = 0; i < uspi->s_ncg; i++) if (sb->u.ufs_sb.s_ucg[i]) brelse (sb->u.ufs_sb.s_ucg[i]); kfree (sb->u.ufs_sb.s_ucg); for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) if (sb->u.ufs_sb.s_ucpi[i]) kfree (sb->u.ufs_sb.s_ucpi[i]); } UFSD(("EXIT (FAILED)\n")) return 0; }
struct super_block * ufs_read_super (struct super_block * sb, void * data, int silent) { struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_super_block_second * usb2; struct ufs_super_block_third * usb3; struct ufs_buffer_head * ubh; struct inode *inode; unsigned block_size, super_block_size; unsigned flags; uspi = NULL; ubh = NULL; flags = 0; UFSD(("ENTER\n")) UFSD(("flag %u\n", (int)(sb->s_flags & MS_RDONLY))) #ifndef CONFIG_UFS_FS_WRITE if (!(sb->s_flags & MS_RDONLY)) { printk("ufs was compiled with read-only support, " "can't be mounted as read-write\n"); goto failed; } #endif /* * Set default mount options * Parse mount options */ sb->u.ufs_sb.s_mount_opt = 0; ufs_set_opt (sb->u.ufs_sb.s_mount_opt, ONERROR_LOCK); if (!ufs_parse_options ((char *) data, &sb->u.ufs_sb.s_mount_opt)) { printk("wrong mount options\n"); goto failed; } if (!(sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE)) { printk("You didn't specify the type of your ufs filesystem\n\n" "mount -t ufs -o ufstype=" "sun|sunx86|44bsd|old|hp|nextstep|netxstep-cd|openstep ...\n\n" ">>>WARNING<<< Wrong ufstype may corrupt your filesystem, " "default is ufstype=old\n"); ufs_set_opt (sb->u.ufs_sb.s_mount_opt, UFSTYPE_OLD); } sb->u.ufs_sb.s_uspi = uspi = kmalloc (sizeof(struct ufs_sb_private_info), GFP_KERNEL); if (!uspi) goto failed; /* 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 (sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) { case UFS_MOUNT_UFSTYPE_44BSD: UFSD(("ufstype=44bsd\n")) uspi->s_fsize = block_size = 512; uspi->s_fmask = ~(512 - 1); uspi->s_fshift = 9; uspi->s_sbsize = super_block_size = 1536; uspi->s_sbbase = 0; flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; break; case UFS_MOUNT_UFSTYPE_SUN: UFSD(("ufstype=sun\n")) uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; uspi->s_maxsymlinklen = 56; flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUN | UFS_CG_SUN; break; case UFS_MOUNT_UFSTYPE_SUNx86: UFSD(("ufstype=sunx86\n")) uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; uspi->s_maxsymlinklen = 56; flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUNx86 | UFS_CG_SUN; break; case UFS_MOUNT_UFSTYPE_OLD: UFSD(("ufstype=old\n")) uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD; if (!(sb->s_flags & MS_RDONLY)) { printk(KERN_INFO "ufstype=old is supported read-only\n"); sb->s_flags |= MS_RDONLY; } break; case UFS_MOUNT_UFSTYPE_NEXTSTEP: UFSD(("ufstype=nextstep\n")) uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD; if (!(sb->s_flags & MS_RDONLY)) { printk(KERN_INFO "ufstype=nextstep is supported read-only\n"); sb->s_flags |= MS_RDONLY; } break; case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD: UFSD(("ufstype=nextstep-cd\n")) uspi->s_fsize = block_size = 2048; uspi->s_fmask = ~(2048 - 1); uspi->s_fshift = 11; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD; if (!(sb->s_flags & MS_RDONLY)) { printk(KERN_INFO "ufstype=nextstep-cd is supported read-only\n"); sb->s_flags |= MS_RDONLY; } break; case UFS_MOUNT_UFSTYPE_OPENSTEP: UFSD(("ufstype=openstep\n")) uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; if (!(sb->s_flags & MS_RDONLY)) { printk(KERN_INFO "ufstype=openstep is supported read-only\n"); sb->s_flags |= MS_RDONLY; } break; case UFS_MOUNT_UFSTYPE_HP: UFSD(("ufstype=hp\n")) uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD; if (!(sb->s_flags & MS_RDONLY)) { printk(KERN_INFO "ufstype=hp is supported read-only\n"); sb->s_flags |= MS_RDONLY; } break; default: printk("unknown ufstype\n"); goto failed; } again: set_blocksize (sb->s_dev, block_size); sb->s_blocksize = block_size; /* * read ufs super block from device */ ubh = ubh_bread_uspi (uspi, sb, uspi->s_sbbase + UFS_SBLOCK/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); /* * Check ufs magic number */ switch (__constant_le32_to_cpu(usb3->fs_magic)) { case UFS_MAGIC: case UFS_MAGIC_LFN: case UFS_MAGIC_FEA: case UFS_MAGIC_4GB: sb->u.ufs_sb.s_bytesex = BYTESEX_LE; goto magic_found; } switch (__constant_be32_to_cpu(usb3->fs_magic)) { case UFS_MAGIC: case UFS_MAGIC_LFN: case UFS_MAGIC_FEA: case UFS_MAGIC_4GB: sb->u.ufs_sb.s_bytesex = BYTESEX_BE; goto magic_found; } if ((((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_NEXTSTEP) || ((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_NEXTSTEP_CD) || ((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_OPENSTEP)) && uspi->s_sbbase < 256) { ubh_brelse_uspi(uspi); ubh = NULL; uspi->s_sbbase += 8; goto again; } printk("ufs_read_super: bad magic number\n"); goto failed; magic_found: /* * Check block and fragment sizes */ uspi->s_bsize = fs32_to_cpu(sb, usb1->fs_bsize); uspi->s_fsize = fs32_to_cpu(sb, usb1->fs_fsize); uspi->s_sbsize = fs32_to_cpu(sb, usb1->fs_sbsize); uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask); uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift); if (uspi->s_bsize != 4096 && uspi->s_bsize != 8192 && uspi->s_bsize != 32768) { printk("ufs_read_super: fs_bsize %u != {4096, 8192, 32768}\n", uspi->s_bsize); goto failed; } if (uspi->s_fsize != 512 && uspi->s_fsize != 1024 && uspi->s_fsize != 2048 && uspi->s_fsize != 4096) { printk("ufs_read_super: fs_fsize %u != {512, 1024, 2048. 4096}\n", uspi->s_fsize); goto failed; } if (uspi->s_fsize != block_size || uspi->s_sbsize != super_block_size) { ubh_brelse_uspi(uspi); ubh = NULL; block_size = uspi->s_fsize; super_block_size = uspi->s_sbsize; UFSD(("another value of block_size or super_block_size %u, %u\n", block_size, super_block_size)) goto again; }
static int ufs_parse_options (char * options, unsigned * mount_options) { char * p; UFSD("ENTER\n"); if (!options) return 1; while ((p = strsep(&options, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; int token; if (!*p) continue; token = match_token(p, tokens, args); switch (token) { case Opt_type_old: ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_OLD); break; case Opt_type_sunx86: ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_SUNx86); break; case Opt_type_sun: ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_SUN); break; case Opt_type_sunos: ufs_clear_opt(*mount_options, UFSTYPE); ufs_set_opt(*mount_options, UFSTYPE_SUNOS); break; case Opt_type_44bsd: ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_44BSD); break; case Opt_type_ufs2: ufs_clear_opt(*mount_options, UFSTYPE); ufs_set_opt(*mount_options, UFSTYPE_UFS2); break; case Opt_type_hp: ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_HP); break; case Opt_type_nextstepcd: ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP_CD); break; case Opt_type_nextstep: ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP); break; case Opt_type_openstep: ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_OPENSTEP); break; case Opt_onerror_panic: ufs_clear_opt (*mount_options, ONERROR); ufs_set_opt (*mount_options, ONERROR_PANIC); break; case Opt_onerror_lock: ufs_clear_opt (*mount_options, ONERROR); ufs_set_opt (*mount_options, ONERROR_LOCK); break; case Opt_onerror_umount: ufs_clear_opt (*mount_options, ONERROR); ufs_set_opt (*mount_options, ONERROR_UMOUNT); break; case Opt_onerror_repair: printk("UFS-fs: Unable to do repair on error, " "will lock lock instead\n"); ufs_clear_opt (*mount_options, ONERROR); ufs_set_opt (*mount_options, ONERROR_REPAIR); break; default: printk("UFS-fs: Invalid option: \"%s\" " "or missing value\n", p); return 0; } } return 1; }
static int ufs_fill_super(struct super_block *sb, void *data, int silent) { struct ufs_sb_info * sbi; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_super_block_second * usb2; struct ufs_super_block_third * usb3; struct ufs_buffer_head * ubh; struct inode *inode; unsigned block_size, super_block_size; unsigned flags; unsigned super_block_offset; unsigned maxsymlen; int ret = -EINVAL; uspi = NULL; ubh = NULL; flags = 0; UFSD("ENTER\n"); sbi = kzalloc(sizeof(struct ufs_sb_info), GFP_KERNEL); if (!sbi) goto failed_nomem; sb->s_fs_info = sbi; UFSD("flag %u\n", (int)(sb->s_flags & MS_RDONLY)); #ifndef CONFIG_UFS_FS_WRITE if (!(sb->s_flags & MS_RDONLY)) { printk("ufs was compiled with read-only support, " "can't be mounted as read-write\n"); goto failed; } #endif mutex_init(&sbi->mutex); /* * Set default mount options * Parse mount options */ sbi->s_mount_opt = 0; ufs_set_opt (sbi->s_mount_opt, ONERROR_LOCK); if (!ufs_parse_options ((char *) data, &sbi->s_mount_opt)) { printk("wrong mount options\n"); goto failed; } if (!(sbi->s_mount_opt & UFS_MOUNT_UFSTYPE)) { 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|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); } uspi = kzalloc(sizeof(struct ufs_sb_private_info), GFP_KERNEL); sbi->s_uspi = uspi; if (!uspi) goto failed; uspi->s_dirblksize = UFS_SECTOR_SIZE; 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"); uspi->s_fsize = block_size = 512; uspi->s_fmask = ~(512 - 1); uspi->s_fshift = 9; uspi->s_sbsize = super_block_size = 1536; uspi->s_sbbase = 0; flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; break; case UFS_MOUNT_UFSTYPE_UFS2: UFSD("ufstype=ufs2\n"); super_block_offset=SBLOCK_UFS2; uspi->s_fsize = block_size = 512; uspi->s_fmask = ~(512 - 1); uspi->s_fshift = 9; uspi->s_sbsize = super_block_size = 1536; uspi->s_sbbase = 0; flags |= UFS_TYPE_UFS2 | UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; break; case UFS_MOUNT_UFSTYPE_SUN: UFSD("ufstype=sun\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; uspi->s_maxsymlinklen = 0; /* Not supported on disk */ flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUN | UFS_CG_SUN; break; case UFS_MOUNT_UFSTYPE_SUNOS: UFSD(("ufstype=sunos\n")) uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; uspi->s_sbsize = 2048; super_block_size = 2048; uspi->s_sbbase = 0; uspi->s_maxsymlinklen = 0; /* Not supported on disk */ flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_SUNOS | UFS_CG_SUN; break; case UFS_MOUNT_UFSTYPE_SUNx86: UFSD("ufstype=sunx86\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; uspi->s_maxsymlinklen = 0; /* Not supported on disk */ flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUNx86 | UFS_CG_SUN; break; case UFS_MOUNT_UFSTYPE_OLD: UFSD("ufstype=old\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD; if (!(sb->s_flags & MS_RDONLY)) { if (!silent) printk(KERN_INFO "ufstype=old is supported read-only\n"); sb->s_flags |= MS_RDONLY; } break; case UFS_MOUNT_UFSTYPE_NEXTSTEP: UFSD("ufstype=nextstep\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; uspi->s_dirblksize = 1024; flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD; if (!(sb->s_flags & MS_RDONLY)) { if (!silent) printk(KERN_INFO "ufstype=nextstep is supported read-only\n"); sb->s_flags |= MS_RDONLY; } break; case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD: UFSD("ufstype=nextstep-cd\n"); uspi->s_fsize = block_size = 2048; uspi->s_fmask = ~(2048 - 1); uspi->s_fshift = 11; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; uspi->s_dirblksize = 1024; flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD; if (!(sb->s_flags & MS_RDONLY)) { if (!silent) printk(KERN_INFO "ufstype=nextstep-cd is supported read-only\n"); sb->s_flags |= MS_RDONLY; } break; case UFS_MOUNT_UFSTYPE_OPENSTEP: UFSD("ufstype=openstep\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; uspi->s_dirblksize = 1024; flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; if (!(sb->s_flags & MS_RDONLY)) { if (!silent) printk(KERN_INFO "ufstype=openstep is supported read-only\n"); sb->s_flags |= MS_RDONLY; } break; case UFS_MOUNT_UFSTYPE_HP: UFSD("ufstype=hp\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD; if (!(sb->s_flags & MS_RDONLY)) { if (!silent) printk(KERN_INFO "ufstype=hp is supported read-only\n"); sb->s_flags |= MS_RDONLY; } break; default: if (!silent) printk("unknown ufstype\n"); goto failed; } again: if (!sb_set_blocksize(sb, block_size)) { printk(KERN_ERR "UFS: failed to set blocksize\n"); goto failed; } /* * read ufs super block from device */ 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); usb2 = ubh_get_usb_second(uspi); usb3 = ubh_get_usb_third(uspi); /* Sort out mod used on SunOS 4.1.3 for fs_state */ uspi->s_postblformat = fs32_to_cpu(sb, usb3->fs_postblformat); if (((flags & UFS_ST_MASK) == UFS_ST_SUNOS) && (uspi->s_postblformat != UFS_42POSTBLFMT)) { flags &= ~UFS_ST_MASK; flags |= UFS_ST_SUN; } /* * Check ufs magic number */ sbi->s_bytesex = BYTESEX_LE; switch ((uspi->fs_magic = fs32_to_cpu(sb, usb3->fs_magic))) { case UFS_MAGIC: case UFS_MAGIC_BW: case UFS2_MAGIC: case UFS_MAGIC_LFN: case UFS_MAGIC_FEA: case UFS_MAGIC_4GB: goto magic_found; } sbi->s_bytesex = BYTESEX_BE; switch ((uspi->fs_magic = fs32_to_cpu(sb, usb3->fs_magic))) { case UFS_MAGIC: case UFS_MAGIC_BW: case UFS2_MAGIC: case UFS_MAGIC_LFN: case UFS_MAGIC_FEA: case UFS_MAGIC_4GB: goto magic_found; } if ((((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_NEXTSTEP) || ((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_NEXTSTEP_CD) || ((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_OPENSTEP)) && uspi->s_sbbase < 256) { ubh_brelse_uspi(uspi); ubh = NULL; uspi->s_sbbase += 8; goto again; } if (!silent) printk("ufs_read_super: bad magic number\n"); goto failed; magic_found: /* * Check block and fragment sizes */ uspi->s_bsize = fs32_to_cpu(sb, usb1->fs_bsize); uspi->s_fsize = fs32_to_cpu(sb, usb1->fs_fsize); uspi->s_sbsize = fs32_to_cpu(sb, usb1->fs_sbsize); uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask); uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift); if (!is_power_of_2(uspi->s_fsize)) { printk(KERN_ERR "ufs_read_super: fragment size %u is not a power of 2\n", uspi->s_fsize); goto failed; } if (uspi->s_fsize < 512) { printk(KERN_ERR "ufs_read_super: fragment size %u is too small\n", uspi->s_fsize); goto failed; } if (uspi->s_fsize > 4096) { printk(KERN_ERR "ufs_read_super: fragment size %u is too large\n", uspi->s_fsize); goto failed; } if (!is_power_of_2(uspi->s_bsize)) { printk(KERN_ERR "ufs_read_super: block size %u is not a power of 2\n", uspi->s_bsize); goto failed; } if (uspi->s_bsize < 4096) { printk(KERN_ERR "ufs_read_super: block size %u is too small\n", uspi->s_bsize); goto failed; } if (uspi->s_bsize / uspi->s_fsize > 8) { printk(KERN_ERR "ufs_read_super: too many fragments per block (%u)\n", uspi->s_bsize / uspi->s_fsize); goto failed; } if (uspi->s_fsize != block_size || uspi->s_sbsize != super_block_size) { ubh_brelse_uspi(uspi); ubh = NULL; block_size = uspi->s_fsize; super_block_size = uspi->s_sbsize; UFSD("another value of block_size or super_block_size %u, %u\n", block_size, super_block_size); goto again; } sbi->s_flags = flags;/*after that line some functions use s_flags*/ ufs_print_super_stuff(sb, usb1, usb2, usb3); /* * Check, if file system was correctly unmounted. * If not, make it read only. */ if (((flags & UFS_ST_MASK) == UFS_ST_44BSD) || ((flags & UFS_ST_MASK) == UFS_ST_OLD) || (((flags & UFS_ST_MASK) == UFS_ST_SUN || (flags & UFS_ST_MASK) == UFS_ST_SUNOS || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) && (ufs_get_fs_state(sb, usb1, usb3) == (UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time))))) { switch(usb1->fs_clean) { case UFS_FSCLEAN: UFSD("fs is clean\n"); break; case UFS_FSSTABLE: UFSD("fs is stable\n"); break; case UFS_FSLOG: UFSD("fs is logging fs\n"); break; case UFS_FSOSF1: UFSD("fs is DEC OSF/1\n"); break; case UFS_FSACTIVE: printk("ufs_read_super: fs is active\n"); sb->s_flags |= MS_RDONLY; break; case UFS_FSBAD: printk("ufs_read_super: fs is bad\n"); sb->s_flags |= MS_RDONLY; break; default: printk("ufs_read_super: can't grok fs_clean 0x%x\n", usb1->fs_clean); sb->s_flags |= MS_RDONLY; break; } } else { printk("ufs_read_super: fs needs fsck\n"); sb->s_flags |= MS_RDONLY; } /* * Read ufs_super_block into internal data structures */ sb->s_op = &ufs_super_ops; sb->s_export_op = &ufs_export_ops; sb->s_magic = fs32_to_cpu(sb, usb3->fs_magic); uspi->s_sblkno = fs32_to_cpu(sb, usb1->fs_sblkno); uspi->s_cblkno = fs32_to_cpu(sb, usb1->fs_cblkno); uspi->s_iblkno = fs32_to_cpu(sb, usb1->fs_iblkno); uspi->s_dblkno = fs32_to_cpu(sb, usb1->fs_dblkno); uspi->s_cgoffset = fs32_to_cpu(sb, usb1->fs_cgoffset); uspi->s_cgmask = fs32_to_cpu(sb, usb1->fs_cgmask); if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { uspi->s_u2_size = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_size); uspi->s_u2_dsize = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize); } else { uspi->s_size = fs32_to_cpu(sb, usb1->fs_size); uspi->s_dsize = fs32_to_cpu(sb, usb1->fs_dsize); } uspi->s_ncg = fs32_to_cpu(sb, usb1->fs_ncg); /* s_bsize already set */ /* s_fsize already set */ uspi->s_fpb = fs32_to_cpu(sb, usb1->fs_frag); uspi->s_minfree = fs32_to_cpu(sb, usb1->fs_minfree); uspi->s_bmask = fs32_to_cpu(sb, usb1->fs_bmask); uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask); uspi->s_bshift = fs32_to_cpu(sb, usb1->fs_bshift); uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift); UFSD("uspi->s_bshift = %d,uspi->s_fshift = %d", uspi->s_bshift, uspi->s_fshift); uspi->s_fpbshift = fs32_to_cpu(sb, usb1->fs_fragshift); uspi->s_fsbtodb = fs32_to_cpu(sb, usb1->fs_fsbtodb); /* s_sbsize already set */ uspi->s_csmask = fs32_to_cpu(sb, usb1->fs_csmask); uspi->s_csshift = fs32_to_cpu(sb, usb1->fs_csshift); uspi->s_nindir = fs32_to_cpu(sb, usb1->fs_nindir); uspi->s_inopb = fs32_to_cpu(sb, usb1->fs_inopb); uspi->s_nspf = fs32_to_cpu(sb, usb1->fs_nspf); uspi->s_npsect = ufs_get_fs_npsect(sb, usb1, usb3); uspi->s_interleave = fs32_to_cpu(sb, usb1->fs_interleave); uspi->s_trackskew = fs32_to_cpu(sb, usb1->fs_trackskew); if (uspi->fs_magic == UFS2_MAGIC) uspi->s_csaddr = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_csaddr); else uspi->s_csaddr = fs32_to_cpu(sb, usb1->fs_csaddr); uspi->s_cssize = fs32_to_cpu(sb, usb1->fs_cssize); uspi->s_cgsize = fs32_to_cpu(sb, usb1->fs_cgsize); uspi->s_ntrak = fs32_to_cpu(sb, usb1->fs_ntrak); uspi->s_nsect = fs32_to_cpu(sb, usb1->fs_nsect); uspi->s_spc = fs32_to_cpu(sb, usb1->fs_spc); uspi->s_ipg = fs32_to_cpu(sb, usb1->fs_ipg); uspi->s_fpg = fs32_to_cpu(sb, usb1->fs_fpg); uspi->s_cpc = fs32_to_cpu(sb, usb2->fs_un.fs_u1.fs_cpc); uspi->s_contigsumsize = fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_contigsumsize); uspi->s_qbmask = ufs_get_fs_qbmask(sb, usb3); uspi->s_qfmask = ufs_get_fs_qfmask(sb, usb3); uspi->s_nrpos = fs32_to_cpu(sb, usb3->fs_nrpos); uspi->s_postbloff = fs32_to_cpu(sb, usb3->fs_postbloff); uspi->s_rotbloff = fs32_to_cpu(sb, usb3->fs_rotbloff); /* * Compute another frequently used values */ uspi->s_fpbmask = uspi->s_fpb - 1; if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) uspi->s_apbshift = uspi->s_bshift - 3; else uspi->s_apbshift = uspi->s_bshift - 2; uspi->s_2apbshift = uspi->s_apbshift * 2; uspi->s_3apbshift = uspi->s_apbshift * 3; uspi->s_apb = 1 << uspi->s_apbshift; uspi->s_2apb = 1 << uspi->s_2apbshift; uspi->s_3apb = 1 << uspi->s_3apbshift; uspi->s_apbmask = uspi->s_apb - 1; uspi->s_nspfshift = uspi->s_fshift - UFS_SECTOR_BITS; uspi->s_nspb = uspi->s_nspf << uspi->s_fpbshift; uspi->s_inopf = uspi->s_inopb >> uspi->s_fpbshift; uspi->s_bpf = uspi->s_fsize << 3; uspi->s_bpfshift = uspi->s_fshift + 3; uspi->s_bpfmask = uspi->s_bpf - 1; if ((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_44BSD || (sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_UFS2) uspi->s_maxsymlinklen = fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_maxsymlinklen); if (uspi->fs_magic == UFS2_MAGIC) maxsymlen = 2 * 4 * (UFS_NDADDR + UFS_NINDIR); else maxsymlen = 4 * (UFS_NDADDR + UFS_NINDIR); if (uspi->s_maxsymlinklen > maxsymlen) { ufs_warning(sb, __func__, "ufs_read_super: excessive maximum " "fast symlink size (%u)\n", uspi->s_maxsymlinklen); uspi->s_maxsymlinklen = maxsymlen; } sb->s_max_links = UFS_LINK_MAX; inode = ufs_iget(sb, UFS_ROOTINO); if (IS_ERR(inode)) { ret = PTR_ERR(inode); goto failed; } sb->s_root = d_make_root(inode); if (!sb->s_root) { ret = -ENOMEM; goto failed; } ufs_setup_cstotal(sb); /* * Read cylinder group structures */ if (!(sb->s_flags & MS_RDONLY)) if (!ufs_read_cylinder_structures(sb)) goto failed; UFSD("EXIT\n"); return 0; failed: if (ubh) ubh_brelse_uspi (uspi); kfree (uspi); kfree(sbi); sb->s_fs_info = NULL; UFSD("EXIT (FAILED)\n"); return ret; failed_nomem: UFSD("EXIT (NOMEM)\n"); return -ENOMEM; }
/* * Free 'count' fragments from fragment number 'fragment' */ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_cg_private_info * ucpi; struct ufs_cylinder_group * ucg; unsigned cgno, bit, end_bit, bbase, blkmap, i; u64 blkno; sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first(uspi); UFSD("ENTER, fragment %llu, count %u\n", (unsigned long long)fragment, count); if (ufs_fragnum(fragment) + count > uspi->s_fpg) ufs_error (sb, "ufs_free_fragments", "internal error"); lock_super(sb); cgno = ufs_dtog(uspi, fragment); bit = ufs_dtogd(uspi, fragment); if (cgno >= uspi->s_ncg) { ufs_panic (sb, "ufs_free_fragments", "freeing blocks are outside device"); goto failed; } ucpi = ufs_load_cylinder (sb, cgno); if (!ucpi) goto failed; ucg = ubh_get_ucg (UCPI_UBH(ucpi)); if (!ufs_cg_chkmagic(sb, ucg)) { ufs_panic (sb, "ufs_free_fragments", "internal error, bad magic number on cg %u", cgno); goto failed; } end_bit = bit + count; bbase = ufs_blknum (bit); blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase); ufs_fragacct (sb, blkmap, ucg->cg_frsum, -1); for (i = bit; i < end_bit; i++) { if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, i)) ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, i); else ufs_error (sb, "ufs_free_fragments", "bit already cleared for fragment %u", i); } fs32_add(sb, &ucg->cg_cs.cs_nffree, count); uspi->cs_total.cs_nffree += count; fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count); blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase); ufs_fragacct(sb, blkmap, ucg->cg_frsum, 1); /* * Trying to reassemble free fragments into block */ blkno = ufs_fragstoblks (bbase); if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) { fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb); uspi->cs_total.cs_nffree -= uspi->s_fpb; fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, uspi->s_fpb); if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD) ufs_clusteracct (sb, ucpi, blkno, 1); fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1); uspi->cs_total.cs_nbfree++; fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1); if (uspi->fs_magic != UFS2_MAGIC) { unsigned cylno = ufs_cbtocylno (bbase); fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(bbase)), 1); fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1); } } ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); if (sb->s_flags & MS_SYNCHRONOUS) { ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); ubh_wait_on_buffer (UCPI_UBH(ucpi)); } sb->s_dirt = 1; unlock_super (sb); UFSD("EXIT\n"); return; failed: unlock_super (sb); UFSD("EXIT (FAILED)\n"); return; }
static int ufs_trunc_dindirect (struct inode *inode, unsigned offset, __fs32 *p) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_buffer_head * dind_bh; unsigned i, tmp, dindirect_block; __fs32 * dind; int retry = 0; UFSD("ENTER\n"); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; dindirect_block = (DIRECT_BLOCK > offset) ? ((DIRECT_BLOCK - offset) >> uspi->s_apbshift) : 0; retry = 0; tmp = fs32_to_cpu(sb, *p); if (!tmp) return 0; dind_bh = ubh_bread(sb, tmp, uspi->s_bsize); if (tmp != fs32_to_cpu(sb, *p)) { ubh_brelse (dind_bh); return 1; } if (!dind_bh) { *p = 0; return 0; } for (i = dindirect_block ; i < uspi->s_apb ; i++) { dind = ubh_get_addr32 (dind_bh, i); tmp = fs32_to_cpu(sb, *dind); if (!tmp) continue; retry |= ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind); ubh_mark_buffer_dirty(dind_bh); } for (i = 0; i < uspi->s_apb; i++) if (*ubh_get_addr32 (dind_bh, i)) break; if (i >= uspi->s_apb) { tmp = fs32_to_cpu(sb, *p); *p = 0; ufs_free_blocks(inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); ubh_bforget(dind_bh); dind_bh = NULL; } if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) { ubh_ll_rw_block(SWRITE, dind_bh); ubh_wait_on_buffer (dind_bh); } ubh_brelse (dind_bh); UFSD("EXIT\n"); return retry; }
/* * NOTE! When we get the inode, we're the only people * that have access to it, and as such there are no * race conditions we have to worry about. The inode * is not on the hash-lists, and it cannot be reached * through the filesystem because the directory entry * has been deleted earlier. * * HOWEVER: we must make sure that we get no aliases, * which means that we have to call "clear_inode()" * _before_ we mark the inode not in use in the inode * bitmaps. Otherwise a newly created file might use * the same inode number (not actually the same pointer * though), and then we'd have two inodes sharing the * same inode number and space on the harddisk. */ void ufs_free_inode (struct inode * inode) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_cg_private_info * ucpi; struct ufs_cylinder_group * ucg; int is_directory; unsigned ino, cg, bit; UFSD("ENTER, ino %lu\n", inode->i_ino); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; ino = inode->i_ino; mutex_lock(&UFS_SB(sb)->s_lock); if (!((ino > 1) && (ino < (uspi->s_ncg * uspi->s_ipg )))) { ufs_warning(sb, "ufs_free_inode", "reserved inode or nonexistent inode %u\n", ino); mutex_unlock(&UFS_SB(sb)->s_lock); return; } cg = ufs_inotocg (ino); bit = ufs_inotocgoff (ino); ucpi = ufs_load_cylinder (sb, cg); if (!ucpi) { mutex_unlock(&UFS_SB(sb)->s_lock); return; } ucg = ubh_get_ucg(UCPI_UBH(ucpi)); if (!ufs_cg_chkmagic(sb, ucg)) ufs_panic (sb, "ufs_free_fragments", "internal error, bad cg magic number"); ucg->cg_time = cpu_to_fs32(sb, get_seconds()); is_directory = S_ISDIR(inode->i_mode); if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit)) ufs_error(sb, "ufs_free_inode", "bit already cleared for inode %u", ino); else { ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit); if (ino < ucpi->c_irotor) ucpi->c_irotor = ino; fs32_add(sb, &ucg->cg_cs.cs_nifree, 1); uspi->cs_total.cs_nifree++; fs32_add(sb, &UFS_SB(sb)->fs_cs(cg).cs_nifree, 1); if (is_directory) { fs32_sub(sb, &ucg->cg_cs.cs_ndir, 1); uspi->cs_total.cs_ndir--; fs32_sub(sb, &UFS_SB(sb)->fs_cs(cg).cs_ndir, 1); } } ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); if (sb->s_flags & MS_SYNCHRONOUS) ubh_sync_block(UCPI_UBH(ucpi)); ufs_mark_sb_dirty(sb); mutex_unlock(&UFS_SB(sb)->s_lock); UFSD("EXIT\n"); }
/* * Modify inode page cache in such way: * have - blocks with b_blocknr equal to oldb...oldb+count-1 * get - blocks with b_blocknr equal to newb...newb+count-1 * also we suppose that oldb...oldb+count-1 blocks * situated at the end of file. * * We can come here from ufs_writepage or ufs_prepare_write, * locked_page is argument of these functions, so we already lock it. */ static void ufs_change_blocknr(struct inode *inode, sector_t beg, unsigned int count, sector_t oldb, sector_t newb, struct page *locked_page) { const unsigned blks_per_page = 1 << (PAGE_CACHE_SHIFT - inode->i_blkbits); const unsigned mask = blks_per_page - 1; struct address_space * const mapping = inode->i_mapping; pgoff_t index, cur_index, last_index; unsigned pos, j, lblock; sector_t end, i; struct page *page; struct buffer_head *head, *bh; UFSD("ENTER, ino %lu, count %u, oldb %llu, newb %llu\n", inode->i_ino, count, (unsigned long long)oldb, (unsigned long long)newb); BUG_ON(!locked_page); BUG_ON(!PageLocked(locked_page)); cur_index = locked_page->index; end = count + beg; last_index = end >> (PAGE_CACHE_SHIFT - inode->i_blkbits); for (i = beg; i < end; i = (i | mask) + 1) { index = i >> (PAGE_CACHE_SHIFT - inode->i_blkbits); if (likely(cur_index != index)) { page = ufs_get_locked_page(mapping, index); if (!page)/* it was truncated */ continue; if (IS_ERR(page)) {/* or EIO */ ufs_error(inode->i_sb, __func__, "read of page %llu failed\n", (unsigned long long)index); continue; } } else page = locked_page; head = page_buffers(page); bh = head; pos = i & mask; for (j = 0; j < pos; ++j) bh = bh->b_this_page; if (unlikely(index == last_index)) lblock = end & mask; else lblock = blks_per_page; do { if (j >= lblock) break; pos = (i - beg) + j; if (!buffer_mapped(bh)) map_bh(bh, inode->i_sb, oldb + pos); if (!buffer_uptodate(bh)) { ll_rw_block(READ, 1, &bh); wait_on_buffer(bh); if (!buffer_uptodate(bh)) { ufs_error(inode->i_sb, __func__, "read of block failed\n"); break; } } UFSD(" change from %llu to %llu, pos %u\n", (unsigned long long)(pos + oldb), (unsigned long long)(pos + newb), pos); bh->b_blocknr = newb + pos; unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); mark_buffer_dirty(bh); ++j; bh = bh->b_this_page; } while (bh != head); if (likely(cur_index != index)) ufs_put_locked_page(page); } UFSD("EXIT\n"); }
static u64 ufs_alloccg_block(struct inode *inode, struct ufs_cg_private_info *ucpi, u64 goal, int *err) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_cylinder_group * ucg; u64 result, blkno; UFSD("ENTER, goal %llu\n", (unsigned long long)goal); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first(uspi); ucg = ubh_get_ucg(UCPI_UBH(ucpi)); if (goal == 0) { goal = ucpi->c_rotor; goto norot; } goal = ufs_blknum (goal); goal = ufs_dtogd(uspi, goal); /* * If the requested block is available, use it. */ if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, ufs_fragstoblks(goal))) { result = goal; goto gotit; } norot: result = ufs_bitmap_search (sb, ucpi, goal, uspi->s_fpb); if (result == INVBLOCK) return INVBLOCK; ucpi->c_rotor = result; gotit: blkno = ufs_fragstoblks(result); ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno); if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD) ufs_clusteracct (sb, ucpi, blkno, -1); if(DQUOT_ALLOC_BLOCK(inode, uspi->s_fpb)) { *err = -EDQUOT; return INVBLOCK; } fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1); uspi->cs_total.cs_nbfree--; fs32_sub(sb, &UFS_SB(sb)->fs_cs(ucpi->c_cgx).cs_nbfree, 1); if (uspi->fs_magic != UFS2_MAGIC) { unsigned cylno = ufs_cbtocylno((unsigned)result); fs16_sub(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos((unsigned)result)), 1); fs32_sub(sb, &ubh_cg_blktot(ucpi, cylno), 1); } UFSD("EXIT, result %llu\n", (unsigned long long)result); return result; }
/* * There are two policies for allocating an inode. If the new inode is * a directory, then a forward search is made for a block group with both * free space and a low directory-to-inode ratio; if that fails, then of * the groups with above-average free space, that group with the fewest * directories already is chosen. * * For other inodes, search forward from the parent directory's block * group to find a free inode. */ struct inode *ufs_new_inode(struct inode *dir, umode_t mode) { struct super_block * sb; struct ufs_sb_info * sbi; struct ufs_sb_private_info * uspi; struct ufs_cg_private_info * ucpi; struct ufs_cylinder_group * ucg; struct inode * inode; unsigned cg, bit, i, j, start; struct ufs_inode_info *ufsi; int err = -ENOSPC; UFSD("ENTER\n"); /* Cannot create files in a deleted directory */ if (!dir || !dir->i_nlink) return ERR_PTR(-EPERM); sb = dir->i_sb; inode = new_inode(sb); if (!inode) return ERR_PTR(-ENOMEM); ufsi = UFS_I(inode); sbi = UFS_SB(sb); uspi = sbi->s_uspi; mutex_lock(&sbi->s_lock); /* * Try to place the inode in its parent directory */ i = ufs_inotocg(dir->i_ino); if (sbi->fs_cs(i).cs_nifree) { cg = i; goto cg_found; } /* * Use a quadratic hash to find a group with a free inode */ for ( j = 1; j < uspi->s_ncg; j <<= 1 ) { i += j; if (i >= uspi->s_ncg) i -= uspi->s_ncg; if (sbi->fs_cs(i).cs_nifree) { cg = i; goto cg_found; } } /* * That failed: try linear search for a free inode */ i = ufs_inotocg(dir->i_ino) + 1; for (j = 2; j < uspi->s_ncg; j++) { i++; if (i >= uspi->s_ncg) i = 0; if (sbi->fs_cs(i).cs_nifree) { cg = i; goto cg_found; } } goto failed; cg_found: ucpi = ufs_load_cylinder (sb, cg); if (!ucpi) { err = -EIO; goto failed; } ucg = ubh_get_ucg(UCPI_UBH(ucpi)); if (!ufs_cg_chkmagic(sb, ucg)) ufs_panic (sb, "ufs_new_inode", "internal error, bad cg magic number"); start = ucpi->c_irotor; bit = ubh_find_next_zero_bit (UCPI_UBH(ucpi), ucpi->c_iusedoff, uspi->s_ipg, start); if (!(bit < uspi->s_ipg)) { bit = ubh_find_first_zero_bit (UCPI_UBH(ucpi), ucpi->c_iusedoff, start); if (!(bit < start)) { ufs_error (sb, "ufs_new_inode", "cylinder group %u corrupted - error in inode bitmap\n", cg); err = -EIO; goto failed; } } UFSD("start = %u, bit = %u, ipg = %u\n", start, bit, uspi->s_ipg); if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit)) ubh_setbit (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit); else { ufs_panic (sb, "ufs_new_inode", "internal error"); err = -EIO; goto failed; } if (uspi->fs_magic == UFS2_MAGIC) { u32 initediblk = fs32_to_cpu(sb, ucg->cg_u.cg_u2.cg_initediblk); if (bit + uspi->s_inopb > initediblk && initediblk < fs32_to_cpu(sb, ucg->cg_u.cg_u2.cg_niblk)) ufs2_init_inodes_chunk(sb, ucpi, ucg); } fs32_sub(sb, &ucg->cg_cs.cs_nifree, 1); uspi->cs_total.cs_nifree--; fs32_sub(sb, &sbi->fs_cs(cg).cs_nifree, 1); if (S_ISDIR(mode)) { fs32_add(sb, &ucg->cg_cs.cs_ndir, 1); uspi->cs_total.cs_ndir++; fs32_add(sb, &sbi->fs_cs(cg).cs_ndir, 1); } ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); if (sb->s_flags & MS_SYNCHRONOUS) ubh_sync_block(UCPI_UBH(ucpi)); ufs_mark_sb_dirty(sb); inode->i_ino = cg * uspi->s_ipg + bit; inode_init_owner(inode, dir, mode); inode->i_blocks = 0; inode->i_generation = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; ufsi->i_flags = UFS_I(dir)->i_flags; ufsi->i_lastfrag = 0; ufsi->i_shadow = 0; ufsi->i_osync = 0; ufsi->i_oeftflag = 0; ufsi->i_dir_start_lookup = 0; memset(&ufsi->i_u1, 0, sizeof(ufsi->i_u1)); insert_inode_hash(inode); mark_inode_dirty(inode); if (uspi->fs_magic == UFS2_MAGIC) { struct buffer_head *bh; struct ufs2_inode *ufs2_inode; /* * setup birth date, we do it here because of there is no sense * to hold it in struct ufs_inode_info, and lose 64 bit */ bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino)); if (!bh) { ufs_warning(sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino); err = -EIO; goto fail_remove_inode; } lock_buffer(bh); ufs2_inode = (struct ufs2_inode *)bh->b_data; ufs2_inode += ufs_inotofsbo(inode->i_ino); ufs2_inode->ui_birthtime = cpu_to_fs64(sb, CURRENT_TIME.tv_sec); ufs2_inode->ui_birthnsec = cpu_to_fs32(sb, CURRENT_TIME.tv_nsec); mark_buffer_dirty(bh); unlock_buffer(bh); if (sb->s_flags & MS_SYNCHRONOUS) sync_dirty_buffer(bh); brelse(bh); } mutex_unlock(&sbi->s_lock); UFSD("allocating inode %lu\n", inode->i_ino); UFSD("EXIT\n"); return inode; fail_remove_inode: mutex_unlock(&sbi->s_lock); clear_nlink(inode); iput(inode); UFSD("EXIT (FAILED): err %d\n", err); return ERR_PTR(err); failed: mutex_unlock(&sbi->s_lock); make_bad_inode(inode); iput (inode); UFSD("EXIT (FAILED): err %d\n", err); return ERR_PTR(err); }
/* * Modify inode page cache in such way: * have - blocks with b_blocknr equal to oldb...oldb+count-1 * get - blocks with b_blocknr equal to newb...newb+count-1 * also we suppose that oldb...oldb+count-1 blocks * situated at the end of file. * * We can come here from ufs_writepage or ufs_prepare_write, * locked_page is argument of these functions, so we already lock it. */ static void ufs_change_blocknr(struct inode *inode, unsigned int beg, unsigned int count, unsigned int oldb, unsigned int newb, struct page *locked_page) { const unsigned mask = (1 << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - 1; struct address_space * const mapping = inode->i_mapping; pgoff_t index, cur_index; unsigned end, pos, j; struct page *page; struct buffer_head *head, *bh; UFSD("ENTER, ino %lu, count %u, oldb %u, newb %u\n", inode->i_ino, count, oldb, newb); BUG_ON(!locked_page); BUG_ON(!PageLocked(locked_page)); cur_index = locked_page->index; for (end = count + beg; beg < end; beg = (beg | mask) + 1) { index = beg >> (PAGE_CACHE_SHIFT - inode->i_blkbits); if (likely(cur_index != index)) { page = ufs_get_locked_page(mapping, index); if (!page || IS_ERR(page)) /* it was truncated or EIO */ continue; } else page = locked_page; head = page_buffers(page); bh = head; pos = beg & mask; for (j = 0; j < pos; ++j) bh = bh->b_this_page; j = 0; do { if (buffer_mapped(bh)) { pos = bh->b_blocknr - oldb; if (pos < count) { UFSD(" change from %llu to %llu\n", (unsigned long long)pos + oldb, (unsigned long long)pos + newb); bh->b_blocknr = newb + pos; unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); mark_buffer_dirty(bh); ++j; } } bh = bh->b_this_page; } while (bh != head); if (j) set_page_dirty(page); if (likely(cur_index != index)) ufs_put_locked_page(page); } UFSD("EXIT\n"); }
/* * Read on-disk structures associated with cylinder groups */ static int ufs_read_cylinder_structures(struct super_block *sb) { struct ufs_sb_info *sbi = UFS_SB(sb); struct ufs_sb_private_info *uspi = sbi->s_uspi; unsigned flags = sbi->s_flags; struct ufs_buffer_head * ubh; unsigned char * base, * space; unsigned size, blks, i; struct ufs_super_block_third *usb3; UFSD("ENTER\n"); usb3 = ubh_get_usb_third(uspi); /* * Read cs structures from (usually) first data block * on the device. */ size = uspi->s_cssize; blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift; 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) ubh = ubh_bread(sb, fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_csaddr) + i, size); else ubh = ubh_bread(sb, uspi->s_csaddr + i, size); if (!ubh) goto failed; ubh_ubhcpymem (space, ubh, size); space += size; ubh_brelse (ubh); ubh = NULL; } /* * Read cylinder group (we read only first fragment from block * at this time) and prepare internal data structures for cg caching. */ if (!(sbi->s_ucg = kmalloc (sizeof(struct buffer_head *) * uspi->s_ncg, GFP_KERNEL))) goto failed; for (i = 0; i < uspi->s_ncg; i++) sbi->s_ucg[i] = NULL; for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) { sbi->s_ucpi[i] = NULL; sbi->s_cgno[i] = UFS_CGNO_EMPTY; } for (i = 0; i < uspi->s_ncg; i++) { UFSD("read cg %u\n", i); if (!(sbi->s_ucg[i] = sb_bread(sb, ufs_cgcmin(i)))) goto failed; if (!ufs_cg_chkmagic (sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data)) goto failed; ufs_print_cylinder_stuff(sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data); } for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) { if (!(sbi->s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL))) goto failed; sbi->s_cgno[i] = UFS_CGNO_EMPTY; } sbi->s_cg_loaded = 0; UFSD("EXIT\n"); return 1; failed: kfree (base); if (sbi->s_ucg) { for (i = 0; i < uspi->s_ncg; i++) if (sbi->s_ucg[i]) brelse (sbi->s_ucg[i]); kfree (sbi->s_ucg); for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) kfree (sbi->s_ucpi[i]); } UFSD("EXIT (FAILED)\n"); return 0; }
static int ufs_trunc_direct (struct inode * inode) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block * sb; struct ufs_sb_private_info * uspi; __fs32 * p; unsigned frag1, frag2, frag3, frag4, block1, block2; unsigned frag_to_free, free_count; unsigned i, tmp; int retry; UFSD("ENTER\n"); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; frag_to_free = 0; free_count = 0; retry = 0; frag1 = DIRECT_FRAGMENT; frag4 = min_t(u32, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag); frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1); frag3 = frag4 & ~uspi->s_fpbmask; block1 = block2 = 0; if (frag2 > frag3) { frag2 = frag4; frag3 = frag4 = 0; } else if (frag2 < frag3) { block1 = ufs_fragstoblks (frag2); block2 = ufs_fragstoblks (frag3); } UFSD("frag1 %u, frag2 %u, block1 %u, block2 %u, frag3 %u, frag4 %u\n", frag1, frag2, block1, block2, frag3, frag4); if (frag1 >= frag2) goto next1; /* * Free first free fragments */ p = ufsi->i_u1.i_data + ufs_fragstoblks (frag1); tmp = fs32_to_cpu(sb, *p); if (!tmp ) ufs_panic (sb, "ufs_trunc_direct", "internal error"); frag1 = ufs_fragnum (frag1); frag2 = ufs_fragnum (frag2); ufs_free_fragments (inode, tmp + frag1, frag2 - frag1); mark_inode_dirty(inode); frag_to_free = tmp + frag1; next1: /* * Free whole blocks */ for (i = block1 ; i < block2; i++) { p = ufsi->i_u1.i_data + i; tmp = fs32_to_cpu(sb, *p); if (!tmp) continue; *p = 0; if (free_count == 0) { frag_to_free = tmp; free_count = uspi->s_fpb; } else if (free_count > 0 && frag_to_free == tmp - free_count) free_count += uspi->s_fpb; else { ufs_free_blocks (inode, frag_to_free, free_count); frag_to_free = tmp; free_count = uspi->s_fpb; } mark_inode_dirty(inode); } if (free_count > 0) ufs_free_blocks (inode, frag_to_free, free_count); if (frag3 >= frag4) goto next3; /* * Free last free fragments */ p = ufsi->i_u1.i_data + ufs_fragstoblks (frag3); tmp = fs32_to_cpu(sb, *p); if (!tmp ) ufs_panic(sb, "ufs_truncate_direct", "internal error"); frag4 = ufs_fragnum (frag4); *p = 0; ufs_free_fragments (inode, tmp, frag4); mark_inode_dirty(inode); next3: UFSD("EXIT\n"); return retry; }
static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno, u64 goal, unsigned count, int *err) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_cg_private_info * ucpi; struct ufs_cylinder_group * ucg; unsigned oldcg, i, j, k, allocsize; u64 result; UFSD("ENTER, ino %lu, cgno %u, goal %llu, count %u\n", inode->i_ino, cgno, (unsigned long long)goal, count); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; oldcg = cgno; /* * 1. searching on preferred cylinder group */ UFS_TEST_FREE_SPACE_CG /* * 2. quadratic rehash */ for (j = 1; j < uspi->s_ncg; j *= 2) { cgno += j; if (cgno >= uspi->s_ncg) cgno -= uspi->s_ncg; UFS_TEST_FREE_SPACE_CG } /* * 3. brute force search * We start at i = 2 ( 0 is checked at 1.step, 1 at 2.step ) */ cgno = (oldcg + 1) % uspi->s_ncg; for (j = 2; j < uspi->s_ncg; j++) { cgno++; if (cgno >= uspi->s_ncg) cgno = 0; UFS_TEST_FREE_SPACE_CG } UFSD("EXIT (FAILED)\n"); return 0; cg_found: ucpi = ufs_load_cylinder (sb, cgno); if (!ucpi) return 0; ucg = ubh_get_ucg (UCPI_UBH(ucpi)); if (!ufs_cg_chkmagic(sb, ucg)) ufs_panic (sb, "ufs_alloc_fragments", "internal error, bad magic number on cg %u", cgno); ucg->cg_time = cpu_to_fs32(sb, get_seconds()); if (count == uspi->s_fpb) { result = ufs_alloccg_block (inode, ucpi, goal, err); if (result == INVBLOCK) return 0; goto succed; } for (allocsize = count; allocsize < uspi->s_fpb; allocsize++) if (fs32_to_cpu(sb, ucg->cg_frsum[allocsize]) != 0) break; if (allocsize == uspi->s_fpb) { result = ufs_alloccg_block (inode, ucpi, goal, err); if (result == INVBLOCK) return 0; goal = ufs_dtogd(uspi, result); for (i = count; i < uspi->s_fpb; i++) ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i); i = uspi->s_fpb - count; fs32_add(sb, &ucg->cg_cs.cs_nffree, i); uspi->cs_total.cs_nffree += i; fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i); fs32_add(sb, &ucg->cg_frsum[i], 1); goto succed; } result = ufs_bitmap_search (sb, ucpi, goal, allocsize); if (result == INVBLOCK) return 0; for (i = 0; i < count; i++) ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i); fs32_sub(sb, &ucg->cg_cs.cs_nffree, count); uspi->cs_total.cs_nffree -= count; fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count); fs32_sub(sb, &ucg->cg_frsum[allocsize], 1); if (count != allocsize) fs32_add(sb, &ucg->cg_frsum[allocsize - count], 1); succed: ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); if (sb->s_flags & MS_SYNCHRONOUS) ubh_sync_block(UCPI_UBH(ucpi)); ufs_mark_sb_dirty(sb); result += cgno * uspi->s_fpg; UFSD("EXIT3, result %llu\n", (unsigned long long)result); return result; }
static int ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_buffer_head * ind_ubh; void *ind; u64 tmp, indirect_block, i, frag_to_free; unsigned free_count; int retry; UFSD("ENTER: ino %lu, offset %llu, p: %p\n", inode->i_ino, (unsigned long long)offset, p); BUG_ON(!p); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; frag_to_free = 0; free_count = 0; retry = 0; tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp) return 0; ind_ubh = ubh_bread(sb, tmp, uspi->s_bsize); if (tmp != ufs_data_ptr_to_cpu(sb, p)) { ubh_brelse (ind_ubh); return 1; } if (!ind_ubh) { ufs_data_ptr_clear(uspi, p); return 0; } indirect_block = (DIRECT_BLOCK > offset) ? (DIRECT_BLOCK - offset) : 0; for (i = indirect_block; i < uspi->s_apb; i++) { ind = ubh_get_data_ptr(uspi, ind_ubh, i); tmp = ufs_data_ptr_to_cpu(sb, ind); if (!tmp) continue; ufs_data_ptr_clear(uspi, ind); ubh_mark_buffer_dirty(ind_ubh); if (free_count == 0) { frag_to_free = tmp; free_count = uspi->s_fpb; } else if (free_count > 0 && frag_to_free == tmp - free_count) free_count += uspi->s_fpb; else { ufs_free_blocks (inode, frag_to_free, free_count); frag_to_free = tmp; free_count = uspi->s_fpb; } mark_inode_dirty(inode); } if (free_count > 0) { ufs_free_blocks (inode, frag_to_free, free_count); } for (i = 0; i < uspi->s_apb; i++) if (!ufs_is_data_ptr_zero(uspi, ubh_get_data_ptr(uspi, ind_ubh, i))) break; if (i >= uspi->s_apb) { tmp = ufs_data_ptr_to_cpu(sb, p); ufs_data_ptr_clear(uspi, p); ufs_free_blocks (inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); ubh_bforget(ind_ubh); ind_ubh = NULL; } if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) ubh_sync_block(ind_ubh); ubh_brelse (ind_ubh); UFSD("EXIT: ino %lu\n", inode->i_ino); return retry; }
/* * Free 'count' fragments from fragment number 'fragment' (free whole blocks) */ void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_cg_private_info * ucpi; struct ufs_cylinder_group * ucg; unsigned overflow, cgno, bit, end_bit, i; u64 blkno; sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first(uspi); UFSD("ENTER, fragment %llu, count %u\n", (unsigned long long)fragment, count); if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) { ufs_error (sb, "ufs_free_blocks", "internal error, " "fragment %llu, count %u\n", (unsigned long long)fragment, count); goto failed; } lock_super(sb); do_more: overflow = 0; cgno = ufs_dtog(uspi, fragment); bit = ufs_dtogd(uspi, fragment); if (cgno >= uspi->s_ncg) { ufs_panic (sb, "ufs_free_blocks", "freeing blocks are outside device"); goto failed_unlock; } end_bit = bit + count; if (end_bit > uspi->s_fpg) { overflow = bit + count - uspi->s_fpg; count -= overflow; end_bit -= overflow; } ucpi = ufs_load_cylinder (sb, cgno); if (!ucpi) goto failed_unlock; ucg = ubh_get_ucg (UCPI_UBH(ucpi)); if (!ufs_cg_chkmagic(sb, ucg)) { ufs_panic (sb, "ufs_free_blocks", "internal error, bad magic number on cg %u", cgno); goto failed_unlock; } for (i = bit; i < end_bit; i += uspi->s_fpb) { blkno = ufs_fragstoblks(i); if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) { ufs_error(sb, "ufs_free_blocks", "freeing free fragment"); } ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno); if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD) ufs_clusteracct (sb, ucpi, blkno, 1); fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1); uspi->cs_total.cs_nbfree++; fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1); if (uspi->fs_magic != UFS2_MAGIC) { unsigned cylno = ufs_cbtocylno(i); fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(i)), 1); fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1); } } ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); if (sb->s_flags & MS_SYNCHRONOUS) { ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); ubh_wait_on_buffer (UCPI_UBH(ucpi)); } if (overflow) { fragment += count; count = overflow; goto do_more; } sb->s_dirt = 1; unlock_super (sb); UFSD("EXIT\n"); return; failed_unlock: unlock_super (sb); failed: UFSD("EXIT (FAILED)\n"); return; }
static int ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_buffer_head *dind_bh; u64 i, tmp, dindirect_block; void *dind; int retry = 0; UFSD("ENTER: ino %lu\n", inode->i_ino); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; dindirect_block = (DIRECT_BLOCK > offset) ? ((DIRECT_BLOCK - offset) >> uspi->s_apbshift) : 0; retry = 0; tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp) return 0; dind_bh = ubh_bread(sb, tmp, uspi->s_bsize); if (tmp != ufs_data_ptr_to_cpu(sb, p)) { ubh_brelse (dind_bh); return 1; } if (!dind_bh) { ufs_data_ptr_clear(uspi, p); return 0; } for (i = dindirect_block ; i < uspi->s_apb ; i++) { dind = ubh_get_data_ptr(uspi, dind_bh, i); tmp = ufs_data_ptr_to_cpu(sb, dind); if (!tmp) continue; retry |= ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind); ubh_mark_buffer_dirty(dind_bh); } for (i = 0; i < uspi->s_apb; i++) if (!ufs_is_data_ptr_zero(uspi, ubh_get_data_ptr(uspi, dind_bh, i))) break; if (i >= uspi->s_apb) { tmp = ufs_data_ptr_to_cpu(sb, p); ufs_data_ptr_clear(uspi, p); ufs_free_blocks(inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); ubh_bforget(dind_bh); dind_bh = NULL; } if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) ubh_sync_block(dind_bh); ubh_brelse (dind_bh); UFSD("EXIT: ino %lu\n", inode->i_ino); return retry; }
u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, u64 goal, unsigned count, int *err, struct page *locked_page) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; unsigned cgno, oldcount, newcount; u64 tmp, request, result; UFSD("ENTER, ino %lu, fragment %llu, goal %llu, count %u\n", inode->i_ino, (unsigned long long)fragment, (unsigned long long)goal, count); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first(uspi); *err = -ENOSPC; lock_super (sb); tmp = ufs_data_ptr_to_cpu(sb, p); if (count + ufs_fragnum(fragment) > uspi->s_fpb) { ufs_warning(sb, "ufs_new_fragments", "internal warning" " fragment %llu, count %u", (unsigned long long)fragment, count); count = uspi->s_fpb - ufs_fragnum(fragment); } oldcount = ufs_fragnum (fragment); newcount = oldcount + count; /* * Somebody else has just allocated our fragments */ if (oldcount) { if (!tmp) { ufs_error(sb, "ufs_new_fragments", "internal error, " "fragment %llu, tmp %llu\n", (unsigned long long)fragment, (unsigned long long)tmp); unlock_super(sb); return INVBLOCK; } if (fragment < UFS_I(inode)->i_lastfrag) { UFSD("EXIT (ALREADY ALLOCATED)\n"); unlock_super (sb); return 0; } } else { if (tmp) { UFSD("EXIT (ALREADY ALLOCATED)\n"); unlock_super(sb); return 0; } } /* * There is not enough space for user on the device */ if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(uspi, UFS_MINFREE) <= 0) { unlock_super (sb); UFSD("EXIT (FAILED)\n"); return 0; } if (goal >= uspi->s_size) goal = 0; if (goal == 0) cgno = ufs_inotocg (inode->i_ino); else cgno = ufs_dtog(uspi, goal); /* * allocate new fragment */ if (oldcount == 0) { result = ufs_alloc_fragments (inode, cgno, goal, count, err); if (result) { ufs_cpu_to_data_ptr(sb, p, result); *err = 0; UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count); ufs_clear_frags(inode, result + oldcount, newcount - oldcount, locked_page != NULL); } unlock_super(sb); UFSD("EXIT, result %llu\n", (unsigned long long)result); return result; } /* * resize block */ result = ufs_add_fragments (inode, tmp, oldcount, newcount, err); if (result) { *err = 0; UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count); ufs_clear_frags(inode, result + oldcount, newcount - oldcount, locked_page != NULL); unlock_super(sb); UFSD("EXIT, result %llu\n", (unsigned long long)result); return result; } /* * allocate new block and move data */ switch (fs32_to_cpu(sb, usb1->fs_optim)) { case UFS_OPTSPACE: request = newcount; if (uspi->s_minfree < 5 || uspi->cs_total.cs_nffree > uspi->s_dsize * uspi->s_minfree / (2 * 100)) break; usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME); break; default: usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME); case UFS_OPTTIME: request = uspi->s_fpb; if (uspi->cs_total.cs_nffree < uspi->s_dsize * (uspi->s_minfree - 2) / 100) break; usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME); break; } result = ufs_alloc_fragments (inode, cgno, goal, request, err); if (result) { ufs_clear_frags(inode, result + oldcount, newcount - oldcount, locked_page != NULL); ufs_change_blocknr(inode, fragment - oldcount, oldcount, uspi->s_sbbase + tmp, uspi->s_sbbase + result, locked_page); ufs_cpu_to_data_ptr(sb, p, result); *err = 0; UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count); unlock_super(sb); if (newcount < request) ufs_free_fragments (inode, result + newcount, request - newcount); ufs_free_fragments (inode, tmp, oldcount); UFSD("EXIT, result %llu\n", (unsigned long long)result); return result; } unlock_super(sb); UFSD("EXIT (FAILED)\n"); return 0; }
static int ufs_trunc_direct(struct inode *inode) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block * sb; struct ufs_sb_private_info * uspi; void *p; u64 frag1, frag2, frag3, frag4, block1, block2; unsigned frag_to_free, free_count; unsigned i, tmp; int retry; UFSD("ENTER: ino %lu\n", inode->i_ino); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; frag_to_free = 0; free_count = 0; retry = 0; frag1 = DIRECT_FRAGMENT; frag4 = min_t(u64, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag); frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1); frag3 = frag4 & ~uspi->s_fpbmask; block1 = block2 = 0; if (frag2 > frag3) { frag2 = frag4; frag3 = frag4 = 0; } else if (frag2 < frag3) { block1 = ufs_fragstoblks (frag2); block2 = ufs_fragstoblks (frag3); } UFSD("ino %lu, frag1 %llu, frag2 %llu, block1 %llu, block2 %llu," " frag3 %llu, frag4 %llu\n", inode->i_ino, (unsigned long long)frag1, (unsigned long long)frag2, (unsigned long long)block1, (unsigned long long)block2, (unsigned long long)frag3, (unsigned long long)frag4); if (frag1 >= frag2) goto next1; /* * Free first free fragments */ p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag1)); tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp ) ufs_panic (sb, "ufs_trunc_direct", "internal error"); frag2 -= frag1; frag1 = ufs_fragnum (frag1); ufs_free_fragments(inode, tmp + frag1, frag2); mark_inode_dirty(inode); frag_to_free = tmp + frag1; next1: /* * Free whole blocks */ for (i = block1 ; i < block2; i++) { p = ufs_get_direct_data_ptr(uspi, ufsi, i); tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp) continue; ufs_data_ptr_clear(uspi, p); if (free_count == 0) { frag_to_free = tmp; free_count = uspi->s_fpb; } else if (free_count > 0 && frag_to_free == tmp - free_count) free_count += uspi->s_fpb; else { ufs_free_blocks (inode, frag_to_free, free_count); frag_to_free = tmp; free_count = uspi->s_fpb; } mark_inode_dirty(inode); } if (free_count > 0) ufs_free_blocks (inode, frag_to_free, free_count); if (frag3 >= frag4) goto next3; /* * Free last free fragments */ p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag3)); tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp ) ufs_panic(sb, "ufs_truncate_direct", "internal error"); frag4 = ufs_fragnum (frag4); ufs_data_ptr_clear(uspi, p); ufs_free_fragments (inode, tmp, frag4); mark_inode_dirty(inode); next3: UFSD("EXIT: ino %lu\n", inode->i_ino); return retry; }
static u64 ufs_add_fragments(struct inode *inode, u64 fragment, unsigned oldcount, unsigned newcount, int *err) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_cg_private_info * ucpi; struct ufs_cylinder_group * ucg; unsigned cgno, fragno, fragoff, count, fragsize, i; UFSD("ENTER, fragment %llu, oldcount %u, newcount %u\n", (unsigned long long)fragment, oldcount, newcount); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first (uspi); count = newcount - oldcount; cgno = ufs_dtog(uspi, fragment); if (fs32_to_cpu(sb, UFS_SB(sb)->fs_cs(cgno).cs_nffree) < count) return 0; if ((ufs_fragnum (fragment) + newcount) > uspi->s_fpb) return 0; ucpi = ufs_load_cylinder (sb, cgno); if (!ucpi) return 0; ucg = ubh_get_ucg (UCPI_UBH(ucpi)); if (!ufs_cg_chkmagic(sb, ucg)) { ufs_panic (sb, "ufs_add_fragments", "internal error, bad magic number on cg %u", cgno); return 0; } fragno = ufs_dtogd(uspi, fragment); fragoff = ufs_fragnum (fragno); for (i = oldcount; i < newcount; i++) if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i)) return 0; /* * Block can be extended */ ucg->cg_time = cpu_to_fs32(sb, get_seconds()); for (i = newcount; i < (uspi->s_fpb - fragoff); i++) if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i)) break; fragsize = i - oldcount; if (!fs32_to_cpu(sb, ucg->cg_frsum[fragsize])) ufs_panic (sb, "ufs_add_fragments", "internal error or corrupted bitmap on cg %u", cgno); fs32_sub(sb, &ucg->cg_frsum[fragsize], 1); if (fragsize != count) fs32_add(sb, &ucg->cg_frsum[fragsize - count], 1); for (i = oldcount; i < newcount; i++) ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i); fs32_sub(sb, &ucg->cg_cs.cs_nffree, count); fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count); uspi->cs_total.cs_nffree -= count; ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); if (sb->s_flags & MS_SYNCHRONOUS) { ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); ubh_wait_on_buffer (UCPI_UBH(ucpi)); } sb->s_dirt = 1; UFSD("EXIT, fragment %llu\n", (unsigned long long)fragment); return fragment; }
static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_buffer_head * ind_ubh; __fs32 * ind; unsigned indirect_block, i, tmp; unsigned frag_to_free, free_count; int retry; UFSD("ENTER\n"); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; frag_to_free = 0; free_count = 0; retry = 0; tmp = fs32_to_cpu(sb, *p); if (!tmp) return 0; ind_ubh = ubh_bread(sb, tmp, uspi->s_bsize); if (tmp != fs32_to_cpu(sb, *p)) { ubh_brelse (ind_ubh); return 1; } if (!ind_ubh) { *p = 0; return 0; } indirect_block = (DIRECT_BLOCK > offset) ? (DIRECT_BLOCK - offset) : 0; for (i = indirect_block; i < uspi->s_apb; i++) { ind = ubh_get_addr32 (ind_ubh, i); tmp = fs32_to_cpu(sb, *ind); if (!tmp) continue; *ind = 0; ubh_mark_buffer_dirty(ind_ubh); if (free_count == 0) { frag_to_free = tmp; free_count = uspi->s_fpb; } else if (free_count > 0 && frag_to_free == tmp - free_count) free_count += uspi->s_fpb; else { ufs_free_blocks (inode, frag_to_free, free_count); frag_to_free = tmp; free_count = uspi->s_fpb; } mark_inode_dirty(inode); } if (free_count > 0) { ufs_free_blocks (inode, frag_to_free, free_count); } for (i = 0; i < uspi->s_apb; i++) if (*ubh_get_addr32(ind_ubh,i)) break; if (i >= uspi->s_apb) { tmp = fs32_to_cpu(sb, *p); *p = 0; ufs_free_blocks (inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); ubh_bforget(ind_ubh); ind_ubh = NULL; } if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) { ubh_ll_rw_block(SWRITE, ind_ubh); ubh_wait_on_buffer (ind_ubh); } ubh_brelse (ind_ubh); UFSD("EXIT\n"); return retry; }