7641 lines · 212.3 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* *  linux/fs/ext4/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 */ #include <linux/module.h>#include <linux/string.h>#include <linux/fs.h>#include <linux/time.h>#include <linux/vmalloc.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/blkdev.h>#include <linux/backing-dev.h>#include <linux/parser.h>#include <linux/buffer_head.h>#include <linux/exportfs.h>#include <linux/vfs.h>#include <linux/random.h>#include <linux/mount.h>#include <linux/namei.h>#include <linux/quotaops.h>#include <linux/seq_file.h>#include <linux/ctype.h>#include <linux/log2.h>#include <linux/crc16.h>#include <linux/dax.h>#include <linux/uaccess.h>#include <linux/iversion.h>#include <linux/unicode.h>#include <linux/part_stat.h>#include <linux/kthread.h>#include <linux/freezer.h>#include <linux/fsnotify.h>#include <linux/fs_context.h>#include <linux/fs_parser.h>#include <linux/fserror.h> #include "ext4.h"#include "ext4_extents.h"	/* Needed for trace points definition */#include "ext4_jbd2.h"#include "xattr.h"#include "acl.h"#include "mballoc.h"#include "fsmap.h" #define CREATE_TRACE_POINTS#include <trace/events/ext4.h> static struct ext4_lazy_init *ext4_li_info;static DEFINE_MUTEX(ext4_li_mtx);static struct ratelimit_state ext4_mount_msg_ratelimit; static int ext4_load_journal(struct super_block *, struct ext4_super_block *,			     unsigned long journal_devnum);static int ext4_show_options(struct seq_file *seq, struct dentry *root);static void ext4_update_super(struct super_block *sb);static int ext4_commit_super(struct super_block *sb);static int ext4_mark_recovery_complete(struct super_block *sb,					struct ext4_super_block *es);static int ext4_clear_journal_err(struct super_block *sb,				  struct ext4_super_block *es);static int ext4_sync_fs(struct super_block *sb, int wait);static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf);static int ext4_unfreeze(struct super_block *sb);static int ext4_freeze(struct super_block *sb);static inline int ext2_feature_set_ok(struct super_block *sb);static inline int ext3_feature_set_ok(struct super_block *sb);static void ext4_unregister_li_request(struct super_block *sb);static void ext4_clear_request_list(void);static struct inode *ext4_get_journal_inode(struct super_block *sb,					    unsigned int journal_inum);static int ext4_validate_options(struct fs_context *fc);static int ext4_check_opt_consistency(struct fs_context *fc,				      struct super_block *sb);static void ext4_apply_options(struct fs_context *fc, struct super_block *sb);static int ext4_parse_param(struct fs_context *fc, struct fs_parameter *param);static int ext4_get_tree(struct fs_context *fc);static int ext4_reconfigure(struct fs_context *fc);static void ext4_fc_free(struct fs_context *fc);static int ext4_init_fs_context(struct fs_context *fc);static void ext4_kill_sb(struct super_block *sb);static const struct fs_parameter_spec ext4_param_specs[]; /* * Lock ordering * * page fault path: * mmap_lock -> sb_start_pagefault -> invalidate_lock (r) -> transaction start *   -> page lock -> i_data_sem (rw) * * buffered write path: * sb_start_write -> i_mutex -> mmap_lock * sb_start_write -> i_mutex -> transaction start -> page lock -> *   i_data_sem (rw) * * truncate: * sb_start_write -> i_mutex -> invalidate_lock (w) -> i_mmap_rwsem (w) -> *   page lock * sb_start_write -> i_mutex -> invalidate_lock (w) -> transaction start -> *   i_data_sem (rw) * * direct IO: * sb_start_write -> i_mutex -> mmap_lock * sb_start_write -> i_mutex -> transaction start -> i_data_sem (rw) * * writepages: * transaction start -> page lock(s) -> i_data_sem (rw) */ static const struct fs_context_operations ext4_context_ops = {	.parse_param	= ext4_parse_param,	.get_tree	= ext4_get_tree,	.reconfigure	= ext4_reconfigure,	.free		= ext4_fc_free,};  #if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT2)static struct file_system_type ext2_fs_type = {	.owner			= THIS_MODULE,	.name			= "ext2",	.init_fs_context	= ext4_init_fs_context,	.parameters		= ext4_param_specs,	.kill_sb		= ext4_kill_sb,	.fs_flags		= FS_REQUIRES_DEV,};MODULE_ALIAS_FS("ext2");MODULE_ALIAS("ext2");#define IS_EXT2_SB(sb) ((sb)->s_type == &ext2_fs_type)#else#define IS_EXT2_SB(sb) (0)#endif  static struct file_system_type ext3_fs_type = {	.owner			= THIS_MODULE,	.name			= "ext3",	.init_fs_context	= ext4_init_fs_context,	.parameters		= ext4_param_specs,	.kill_sb		= ext4_kill_sb,	.fs_flags		= FS_REQUIRES_DEV,};MODULE_ALIAS_FS("ext3");MODULE_ALIAS("ext3");#define IS_EXT3_SB(sb) ((sb)->s_type == &ext3_fs_type)  static inline void __ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,				  bio_end_io_t end_io, bool simu_fail){	if (simu_fail) {		clear_buffer_uptodate(bh);		unlock_buffer(bh);		return;	} 	/*	 * buffer's verified bit is no longer valid after reading from	 * disk again due to write out error, clear it to make sure we	 * recheck the buffer contents.	 */	clear_buffer_verified(bh); 	if (!end_io)		end_io = bh_end_read;	bh_submit(bh, REQ_OP_READ | op_flags, end_io);} void ext4_read_bh_nowait(struct buffer_head *bh, blk_opf_t op_flags,			 bio_end_io_t end_io, bool simu_fail){	BUG_ON(!buffer_locked(bh)); 	if (ext4_buffer_uptodate(bh)) {		unlock_buffer(bh);		return;	}	__ext4_read_bh(bh, op_flags, end_io, simu_fail);} int ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,		 bio_end_io_t end_io, bool simu_fail){	BUG_ON(!buffer_locked(bh)); 	if (ext4_buffer_uptodate(bh)) {		unlock_buffer(bh);		return 0;	} 	__ext4_read_bh(bh, op_flags, end_io, simu_fail); 	wait_on_buffer(bh);	if (buffer_uptodate(bh))		return 0;	return -EIO;} int ext4_read_bh_lock(struct buffer_head *bh, blk_opf_t op_flags, bool wait){	lock_buffer(bh);	if (!wait) {		ext4_read_bh_nowait(bh, op_flags, NULL, false);		return 0;	}	return ext4_read_bh(bh, op_flags, NULL, false);} /* * This works like __bread_gfp() except it uses ERR_PTR for error * returns.  Currently with sb_bread it's impossible to distinguish * between ENOMEM and EIO situations (since both result in a NULL * return. */static struct buffer_head *__ext4_sb_bread_gfp(struct super_block *sb,					       sector_t block,					       blk_opf_t op_flags, gfp_t gfp){	struct buffer_head *bh;	int ret; 	bh = sb_getblk_gfp(sb, block, gfp);	if (bh == NULL)		return ERR_PTR(-ENOMEM);	if (ext4_buffer_uptodate(bh))		return bh; 	ret = ext4_read_bh_lock(bh, REQ_META | op_flags, true);	if (ret) {		put_bh(bh);		return ERR_PTR(ret);	}	return bh;} struct buffer_head *ext4_sb_bread(struct super_block *sb, sector_t block,				   blk_opf_t op_flags){	gfp_t gfp = mapping_gfp_constraint(sb->s_bdev->bd_mapping,			~__GFP_FS) | __GFP_MOVABLE; 	return __ext4_sb_bread_gfp(sb, block, op_flags, gfp);} struct buffer_head *ext4_sb_bread_unmovable(struct super_block *sb,					    sector_t block){	gfp_t gfp = mapping_gfp_constraint(sb->s_bdev->bd_mapping,			~__GFP_FS); 	return __ext4_sb_bread_gfp(sb, block, 0, gfp);} struct buffer_head *ext4_sb_bread_nofail(struct super_block *sb,					 sector_t block){	gfp_t gfp = mapping_gfp_constraint(sb->s_bdev->bd_mapping,			~__GFP_FS) | __GFP_MOVABLE | __GFP_NOFAIL; 	return __ext4_sb_bread_gfp(sb, block, 0, gfp);} void ext4_sb_breadahead_unmovable(struct super_block *sb, sector_t block){	struct buffer_head *bh = bdev_getblk(sb->s_bdev, block,			sb->s_blocksize, GFP_NOWAIT); 	if (likely(bh)) {		if (trylock_buffer(bh))			ext4_read_bh_nowait(bh, REQ_RAHEAD, NULL, false);		brelse(bh);	}} static int ext4_verify_csum_type(struct super_block *sb,				 struct ext4_super_block *es){	if (!ext4_has_feature_metadata_csum(sb))		return 1; 	return es->s_checksum_type == EXT4_CRC32C_CHKSUM;} __le32 ext4_superblock_csum(struct ext4_super_block *es){	int offset = offsetof(struct ext4_super_block, s_checksum);	__u32 csum; 	csum = ext4_chksum(~0, (char *)es, offset); 	return cpu_to_le32(csum);} static int ext4_superblock_csum_verify(struct super_block *sb,				       struct ext4_super_block *es){	if (!ext4_has_feature_metadata_csum(sb))		return 1; 	return es->s_checksum == ext4_superblock_csum(es);} void ext4_superblock_csum_set(struct super_block *sb){	struct ext4_super_block *es = EXT4_SB(sb)->s_es; 	if (!ext4_has_feature_metadata_csum(sb))		return; 	es->s_checksum = ext4_superblock_csum(es);} ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,			       struct ext4_group_desc *bg){	return le32_to_cpu(bg->bg_block_bitmap_lo) |		(EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?		 (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0);} ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,			       struct ext4_group_desc *bg){	return le32_to_cpu(bg->bg_inode_bitmap_lo) |		(EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?		 (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0);} ext4_fsblk_t ext4_inode_table(struct super_block *sb,			      struct ext4_group_desc *bg){	return le32_to_cpu(bg->bg_inode_table_lo) |		(EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?		 (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0);} __u32 ext4_free_group_clusters(struct super_block *sb,			       struct ext4_group_desc *bg){	return le16_to_cpu(bg->bg_free_blocks_count_lo) |		(EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?		 (__u32)le16_to_cpu(bg->bg_free_blocks_count_hi) << 16 : 0);} __u32 ext4_free_inodes_count(struct super_block *sb,			      struct ext4_group_desc *bg){	return le16_to_cpu(READ_ONCE(bg->bg_free_inodes_count_lo)) |		(EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?		 (__u32)le16_to_cpu(READ_ONCE(bg->bg_free_inodes_count_hi)) << 16 : 0);} __u32 ext4_used_dirs_count(struct super_block *sb,			      struct ext4_group_desc *bg){	return le16_to_cpu(bg->bg_used_dirs_count_lo) |		(EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?		 (__u32)le16_to_cpu(bg->bg_used_dirs_count_hi) << 16 : 0);} __u32 ext4_itable_unused_count(struct super_block *sb,			      struct ext4_group_desc *bg){	return le16_to_cpu(bg->bg_itable_unused_lo) |		(EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?		 (__u32)le16_to_cpu(bg->bg_itable_unused_hi) << 16 : 0);} void ext4_block_bitmap_set(struct super_block *sb,			   struct ext4_group_desc *bg, ext4_fsblk_t blk){	bg->bg_block_bitmap_lo = cpu_to_le32((u32)blk);	if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)		bg->bg_block_bitmap_hi = cpu_to_le32(blk >> 32);} void ext4_inode_bitmap_set(struct super_block *sb,			   struct ext4_group_desc *bg, ext4_fsblk_t blk){	bg->bg_inode_bitmap_lo  = cpu_to_le32((u32)blk);	if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)		bg->bg_inode_bitmap_hi = cpu_to_le32(blk >> 32);} void ext4_inode_table_set(struct super_block *sb,			  struct ext4_group_desc *bg, ext4_fsblk_t blk){	bg->bg_inode_table_lo = cpu_to_le32((u32)blk);	if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)		bg->bg_inode_table_hi = cpu_to_le32(blk >> 32);} void ext4_free_group_clusters_set(struct super_block *sb,				  struct ext4_group_desc *bg, __u32 count){	bg->bg_free_blocks_count_lo = cpu_to_le16((__u16)count);	if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)		bg->bg_free_blocks_count_hi = cpu_to_le16(count >> 16);} void ext4_free_inodes_set(struct super_block *sb,			  struct ext4_group_desc *bg, __u32 count){	WRITE_ONCE(bg->bg_free_inodes_count_lo, cpu_to_le16((__u16)count));	if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)		WRITE_ONCE(bg->bg_free_inodes_count_hi, cpu_to_le16(count >> 16));} void ext4_used_dirs_set(struct super_block *sb,			  struct ext4_group_desc *bg, __u32 count){	bg->bg_used_dirs_count_lo = cpu_to_le16((__u16)count);	if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)		bg->bg_used_dirs_count_hi = cpu_to_le16(count >> 16);} void ext4_itable_unused_set(struct super_block *sb,			  struct ext4_group_desc *bg, __u32 count){	bg->bg_itable_unused_lo = cpu_to_le16((__u16)count);	if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)		bg->bg_itable_unused_hi = cpu_to_le16(count >> 16);} static void __ext4_update_tstamp(__le32 *lo, __u8 *hi, time64_t now){	now = clamp_val(now, 0, (1ull << 40) - 1); 	*lo = cpu_to_le32(lower_32_bits(now));	*hi = upper_32_bits(now);} static time64_t __ext4_get_tstamp(__le32 *lo, __u8 *hi){	return ((time64_t)(*hi) << 32) + le32_to_cpu(*lo);}#define ext4_update_tstamp(es, tstamp) \	__ext4_update_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi, \			     ktime_get_real_seconds())#define ext4_get_tstamp(es, tstamp) \	__ext4_get_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi) /* * The ext4_maybe_update_superblock() function checks and updates the * superblock if needed. * * This function is designed to update the on-disk superblock only under * certain conditions to prevent excessive disk writes and unnecessary * waking of the disk from sleep. The superblock will be updated if: * 1. More than sbi->s_sb_update_sec (def: 1 hour) has passed since the last *    superblock update * 2. More than sbi->s_sb_update_kb (def: 16MB) kbs have been written since the *    last superblock update. * * @sb: The superblock */static void ext4_maybe_update_superblock(struct super_block *sb){	struct ext4_sb_info *sbi = EXT4_SB(sb);	struct ext4_super_block *es = sbi->s_es;	journal_t *journal = sbi->s_journal;	time64_t now;	__u64 last_update;	__u64 lifetime_write_kbytes;	__u64 diff_size; 	if (ext4_emergency_state(sb) || sb_rdonly(sb) ||	    !(sb->s_flags & SB_ACTIVE) || !journal ||	    journal->j_flags & JBD2_UNMOUNT)		return; 	now = ktime_get_real_seconds();	last_update = ext4_get_tstamp(es, s_wtime); 	if (likely(now - last_update < sbi->s_sb_update_sec))		return; 	lifetime_write_kbytes = sbi->s_kbytes_written +		((part_stat_read(sb->s_bdev, sectors[STAT_WRITE]) -		  sbi->s_sectors_written_start) >> 1); 	/* Get the number of kilobytes not written to disk to account	 * for statistics and compare with a multiple of 16 MB. This	 * is used to determine when the next superblock commit should	 * occur (i.e. not more often than once per 16MB if there was

Lines 1–500 of 7641.