// SPDX-License-Identifier: GPL-2.0-only /* * linux/fs/ufs/super.c * * Copyright (C) 1998 * Daniel Pirkl <daniel.pirkl@email.cz> * Charles University, Faculty of Mathematics and Physics
*/
/* Derived from * * linux/fs/ext2/super.c * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) * Laboratoire MASI - Institut Blaise Pascal * Universite Pierre et Marie Curie (Paris VI) * * from * * linux/fs/minix/inode.c * * Copyright (C) 1991, 1992 Linus Torvalds * * Big-endian to little-endian byte-swapping/bitmaps by * David S. Miller (davem@caip.rutgers.edu), 1995
*/
/* * Inspired by * * linux/fs/ufs/super.c * * Copyright (C) 1996 * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * * Kernel module support added on 96/04/26 by * Stefan Reinauer <stepan@home.culture.mipt.ru> * * Module usage counts added on 96/04/29 by * Gertjan van Wingerde <gwingerde@gmail.com> * * Clean swab support on 19970406 by * Francois-Rene Rideau <fare@tunes.org> * * 4.4BSD (FreeBSD) support added on February 1st 1998 by * Niels Kristian Bech Jensen <nkbj@image.dk> partially based * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>. * * NeXTstep support added on February 5th 1998 by * Niels Kristian Bech Jensen <nkbj@image.dk>. * * write support Daniel Pirkl <daniel.pirkl@email.cz> 1998 * * HP/UX hfs filesystem support added by * Martin K. Petersen <mkp@mkp.net>, August 1999 * * UFS2 (of FreeBSD 5.x) support added by * Niraj Kumar <niraj17@iitbombay.org>, Jan 2004 * * UFS2 write support added by * Evgeniy Dushistov <dushistov@mail.ru>, 2007
*/
switch (opt) { case Opt_type: if (ctx->flavour == result.uint_32) /* no-op */ return 0; if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
pr_err("ufstype can't be changed during remount\n"); return -EINVAL;
} if (ctx->flavour) {
pr_err("conflicting ufstype options\n"); return -EINVAL;
}
ctx->flavour = result.uint_32; break; case Opt_onerror:
ctx->on_err = result.uint_32; break; default: return -EINVAL;
} return 0;
}
/* * Different types of UFS hold fs_cstotal in different * places, and use different data structure for it. * To make things simpler we just copy fs_cstotal to ufs_sb_private_info
*/ staticvoid ufs_setup_cstotal(struct super_block *sb)
{ struct ufs_sb_info *sbi = UFS_SB(sb); struct ufs_sb_private_info *uspi = sbi->s_uspi; struct ufs_super_block_first *usb1; struct ufs_super_block_second *usb2; struct ufs_super_block_third *usb3; unsigned mtype = sbi->s_flavour;
/* * 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_NOFS); if (!base) goto failed;
sbi->s_csp = (struct ufs_csum *)space; for (i = 0; i < blks; i++) { struct buffer_head *bh = sb_bread(sb, uspi->s_csaddr + i); if (!bh) goto failed;
memcpy(space, bh->b_data, uspi->s_fsize);
space += uspi->s_fsize;
brelse (bh);
}
/* * Read cylinder group (we read only first fragment from block * at this time) and prepare internal data structures for cg caching.
*/
sbi->s_ucg = kmalloc_array(uspi->s_ncg, sizeof(struct buffer_head *),
GFP_NOFS); if (!sbi->s_ucg) 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_NOFS))) 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;
}
if (mtype == UFS_MOUNT_UFSTYPE_UFS2) { /*we have statistic in different place, then usual*/
usb2->fs_un.fs_u2.cs_ndir =
cpu_to_fs64(sb, uspi->cs_total.cs_ndir);
usb2->fs_un.fs_u2.cs_nbfree =
cpu_to_fs64(sb, uspi->cs_total.cs_nbfree);
usb3->fs_un1.fs_u2.cs_nifree =
cpu_to_fs64(sb, uspi->cs_total.cs_nifree);
usb3->fs_un1.fs_u2.cs_nffree =
cpu_to_fs64(sb, uspi->cs_total.cs_nffree); goto out;
}
if (mtype == UFS_MOUNT_UFSTYPE_44BSD &&
(usb2->fs_un.fs_u2.fs_maxbsize == usb1->fs_bsize)) { /* store stats in both old and new places */
usb2->fs_un.fs_u2.cs_ndir =
cpu_to_fs64(sb, uspi->cs_total.cs_ndir);
usb2->fs_un.fs_u2.cs_nbfree =
cpu_to_fs64(sb, uspi->cs_total.cs_nbfree);
usb3->fs_un1.fs_u2.cs_nifree =
cpu_to_fs64(sb, uspi->cs_total.cs_nifree);
usb3->fs_un1.fs_u2.cs_nffree =
cpu_to_fs64(sb, uspi->cs_total.cs_nffree);
}
usb1->fs_cstotal.cs_ndir = cpu_to_fs32(sb, uspi->cs_total.cs_ndir);
usb1->fs_cstotal.cs_nbfree = cpu_to_fs32(sb, uspi->cs_total.cs_nbfree);
usb1->fs_cstotal.cs_nifree = cpu_to_fs32(sb, uspi->cs_total.cs_nifree);
usb1->fs_cstotal.cs_nffree = cpu_to_fs32(sb, uspi->cs_total.cs_nffree);
out:
ubh_mark_buffer_dirty(USPI_UBH(uspi));
ufs_print_super_stuff(sb, usb1, usb2, usb3);
UFSD("EXIT\n");
}
/** * ufs_put_super_internal() - put on-disk intrenal structures * @sb: pointer to super_block structure * Put on-disk structures associated with cylinder groups * and write them back to disk, also update cs_total on disk
*/ staticvoid ufs_put_super_internal(struct super_block *sb)
{ struct ufs_sb_info *sbi = UFS_SB(sb); struct ufs_sb_private_info *uspi = sbi->s_uspi; unsignedchar * base, * space; unsigned blks, size, i;
UFSD("ENTER\n");
ufs_put_cstotal(sb);
size = uspi->s_cssize;
blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift;
base = space = (char*) sbi->s_csp; for (i = 0; i < blks; i++, space += uspi->s_fsize) { struct buffer_head *bh = sb_bread(sb, uspi->s_csaddr + i);
if (unlikely(!bh)) { // better than an oops...
ufs_panic(sb, __func__, "can't write part of cylinder group summary"); continue;
}
memcpy(bh->b_data, space, uspi->s_fsize);
mark_buffer_dirty(bh);
brelse(bh);
} for (i = 0; i < sbi->s_cg_loaded; i++) {
ufs_put_cylinder (sb, i);
kfree (sbi->s_ucpi[i]);
} for (; i < UFS_MAX_GROUP_LOADED; i++)
kfree (sbi->s_ucpi[i]); for (i = 0; i < uspi->s_ncg; i++)
brelse (sbi->s_ucg[i]);
kfree (sbi->s_ucg);
kfree (base);
#ifndef CONFIG_UFS_FS_WRITE if (!sb_rdonly(sb)) {
pr_err("ufs was compiled with read-only support, can't be mounted as read-write\n"); return -EROFS;
} #endif
if (!sbi->s_flavour) { if (!silent)
pr_err("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");
sbi->s_flavour = UFS_MOUNT_UFSTYPE_OLD;
}
/* 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;
}
if ((flags & UFS_ST_MASK) == UFS_ST_44BSD &&
uspi->s_postblformat == UFS_42POSTBLFMT) { if (!silent)
pr_err("this is not a 44bsd filesystem"); goto failed;
}
/* * 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 (!is_power_of_2(uspi->s_fsize)) {
pr_err("%s(): fragment size %u is not a power of 2\n",
__func__, uspi->s_fsize); goto failed;
} if (uspi->s_fsize < 512) {
pr_err("%s(): fragment size %u is too small\n",
__func__, uspi->s_fsize); goto failed;
} if (uspi->s_fsize > 4096) {
pr_err("%s(): fragment size %u is too large\n",
__func__, uspi->s_fsize); goto failed;
} if (!is_power_of_2(uspi->s_bsize)) {
pr_err("%s(): block size %u is not a power of 2\n",
__func__, uspi->s_bsize); goto failed;
} if (uspi->s_bsize < 4096) {
pr_err("%s(): block size %u is too small\n",
__func__, uspi->s_bsize); goto failed;
} if (uspi->s_bsize / uspi->s_fsize > 8) {
pr_err("%s(): too many fragments per block (%u)\n",
__func__, 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:
pr_err("%s(): fs is active\n", __func__);
sb->s_flags |= SB_RDONLY; break; case UFS_FSBAD:
pr_err("%s(): fs is bad\n", __func__);
sb->s_flags |= SB_RDONLY; break; default:
pr_err("%s(): can't grok fs_clean 0x%x\n",
__func__, usb1->fs_clean);
sb->s_flags |= SB_RDONLY; break;
}
} else {
pr_err("%s(): fs needs fsck\n", __func__);
sb->s_flags |= SB_RDONLY;
}
/* * Read ufs_super_block into internal data structures
*/
sb->s_op = &ufs_super_ops;
sb->s_export_op = &ufs_export_ops;
staticvoid destroy_inodecache(void)
{ /* * Make sure all delayed rcu free inodes are flushed before we * destroy cache.
*/
rcu_barrier();
kmem_cache_destroy(ufs_inode_cachep);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.