mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	ext4: add shutdown bit and check for it
Add a shutdown bit that will cause ext4 processing to fail immediately with EIO. Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
		
							parent
							
								
									9549a168bd
								
							
						
					
					
						commit
						0db1ff222d
					
				
					 11 changed files with 103 additions and 3 deletions
				
			
		| 
						 | 
				
			
			@ -1836,6 +1836,12 @@ static inline bool ext4_has_incompat_features(struct super_block *sb)
 | 
			
		|||
 * Superblock flags
 | 
			
		||||
 */
 | 
			
		||||
#define EXT4_FLAGS_RESIZING	0
 | 
			
		||||
#define EXT4_FLAGS_SHUTDOWN	1
 | 
			
		||||
 | 
			
		||||
static inline int ext4_forced_shutdown(struct ext4_sb_info *sbi)
 | 
			
		||||
{
 | 
			
		||||
	return test_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,6 +43,10 @@ static int ext4_journal_check_start(struct super_block *sb)
 | 
			
		|||
	journal_t *journal;
 | 
			
		||||
 | 
			
		||||
	might_sleep();
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	if (sb->s_flags & MS_RDONLY)
 | 
			
		||||
		return -EROFS;
 | 
			
		||||
	WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE);
 | 
			
		||||
| 
						 | 
				
			
			@ -161,6 +165,13 @@ int __ext4_journal_get_write_access(const char *where, unsigned int line,
 | 
			
		|||
	might_sleep();
 | 
			
		||||
 | 
			
		||||
	if (ext4_handle_valid(handle)) {
 | 
			
		||||
		struct super_block *sb;
 | 
			
		||||
 | 
			
		||||
		sb = handle->h_transaction->t_journal->j_private;
 | 
			
		||||
		if (unlikely(ext4_forced_shutdown(EXT4_SB(sb)))) {
 | 
			
		||||
			jbd2_journal_abort_handle(handle);
 | 
			
		||||
			return -EIO;
 | 
			
		||||
		}
 | 
			
		||||
		err = jbd2_journal_get_write_access(handle, bh);
 | 
			
		||||
		if (err)
 | 
			
		||||
			ext4_journal_abort_handle(where, line, __func__, bh,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,6 +57,9 @@ static ssize_t ext4_dax_read_iter(struct kiocb *iocb, struct iov_iter *to)
 | 
			
		|||
 | 
			
		||||
static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 | 
			
		||||
{
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(file_inode(iocb->ki_filp)->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	if (!iov_iter_count(to))
 | 
			
		||||
		return 0; /* skip atime */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -213,6 +216,9 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 | 
			
		|||
	int overwrite = 0;
 | 
			
		||||
	ssize_t ret;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_FS_DAX
 | 
			
		||||
	if (IS_DAX(inode))
 | 
			
		||||
		return ext4_dax_write_iter(iocb, from);
 | 
			
		||||
| 
						 | 
				
			
			@ -348,6 +354,9 @@ static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)
 | 
			
		|||
{
 | 
			
		||||
	struct inode *inode = file->f_mapping->host;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	if (ext4_encrypted_inode(inode)) {
 | 
			
		||||
		int err = fscrypt_get_encryption_info(inode);
 | 
			
		||||
		if (err)
 | 
			
		||||
| 
						 | 
				
			
			@ -375,6 +384,9 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
 | 
			
		|||
	char buf[64], *cp;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(!(sbi->s_mount_flags & EXT4_MF_MNTDIR_SAMPLED) &&
 | 
			
		||||
		     !(sb->s_flags & MS_RDONLY))) {
 | 
			
		||||
		sbi->s_mount_flags |= EXT4_MF_MNTDIR_SAMPLED;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,6 +100,9 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 | 
			
		|||
	tid_t commit_tid;
 | 
			
		||||
	bool needs_barrier = false;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	J_ASSERT(ext4_journal_current_handle() == NULL);
 | 
			
		||||
 | 
			
		||||
	trace_ext4_sync_file_enter(file, datasync);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -764,6 +764,9 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
 | 
			
		|||
	if (!dir || !dir->i_nlink)
 | 
			
		||||
		return ERR_PTR(-EPERM);
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb))))
 | 
			
		||||
		return ERR_PTR(-EIO);
 | 
			
		||||
 | 
			
		||||
	if ((ext4_encrypted_inode(dir) ||
 | 
			
		||||
	     DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))) &&
 | 
			
		||||
	    (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -215,6 +215,9 @@ static void ext4_write_inline_data(struct inode *inode, struct ext4_iloc *iloc,
 | 
			
		|||
	struct ext4_inode *raw_inode;
 | 
			
		||||
	int cp_len = 0;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(!EXT4_I(inode)->i_inline_off);
 | 
			
		||||
	BUG_ON(pos + len > EXT4_I(inode)->i_inline_size);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1189,6 +1189,9 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
 | 
			
		|||
	pgoff_t index;
 | 
			
		||||
	unsigned from, to;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	trace_ext4_write_begin(inode, pos, len, flags);
 | 
			
		||||
	/*
 | 
			
		||||
	 * Reserve one block more for addition to orphan list in case
 | 
			
		||||
| 
						 | 
				
			
			@ -2047,6 +2050,12 @@ static int ext4_writepage(struct page *page,
 | 
			
		|||
	struct ext4_io_submit io_submit;
 | 
			
		||||
	bool keep_towrite = false;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) {
 | 
			
		||||
		ext4_invalidatepage(page, 0, PAGE_SIZE);
 | 
			
		||||
		unlock_page(page);
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	trace_ext4_writepage(page);
 | 
			
		||||
	size = i_size_read(inode);
 | 
			
		||||
	if (page->index == size >> PAGE_SHIFT)
 | 
			
		||||
| 
						 | 
				
			
			@ -2422,7 +2431,8 @@ static int mpage_map_and_submit_extent(handle_t *handle,
 | 
			
		|||
		if (err < 0) {
 | 
			
		||||
			struct super_block *sb = inode->i_sb;
 | 
			
		||||
 | 
			
		||||
			if (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
 | 
			
		||||
			if (ext4_forced_shutdown(EXT4_SB(sb)) ||
 | 
			
		||||
			    EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
 | 
			
		||||
				goto invalidate_dirty_pages;
 | 
			
		||||
			/*
 | 
			
		||||
			 * Let the uper layers retry transient errors.
 | 
			
		||||
| 
						 | 
				
			
			@ -2644,6 +2654,9 @@ static int ext4_writepages(struct address_space *mapping,
 | 
			
		|||
	struct blk_plug plug;
 | 
			
		||||
	bool give_up_on_write = false;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	percpu_down_read(&sbi->s_journal_flag_rwsem);
 | 
			
		||||
	trace_ext4_writepages(inode, wbc);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2680,7 +2693,8 @@ static int ext4_writepages(struct address_space *mapping,
 | 
			
		|||
	 * *never* be called, so if that ever happens, we would want
 | 
			
		||||
	 * the stack trace.
 | 
			
		||||
	 */
 | 
			
		||||
	if (unlikely(sbi->s_mount_flags & EXT4_MF_FS_ABORTED)) {
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(mapping->host->i_sb)) ||
 | 
			
		||||
		     sbi->s_mount_flags & EXT4_MF_FS_ABORTED)) {
 | 
			
		||||
		ret = -EROFS;
 | 
			
		||||
		goto out_writepages;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -2905,6 +2919,9 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
 | 
			
		|||
	struct inode *inode = mapping->host;
 | 
			
		||||
	handle_t *handle;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	index = pos >> PAGE_SHIFT;
 | 
			
		||||
 | 
			
		||||
	if (ext4_nonda_switch(inode->i_sb) ||
 | 
			
		||||
| 
						 | 
				
			
			@ -5212,6 +5229,9 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
 | 
			
		|||
	int orphan = 0;
 | 
			
		||||
	const unsigned int ia_valid = attr->ia_valid;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	error = setattr_prepare(dentry, attr);
 | 
			
		||||
	if (error)
 | 
			
		||||
		return error;
 | 
			
		||||
| 
						 | 
				
			
			@ -5498,6 +5518,9 @@ int ext4_mark_iloc_dirty(handle_t *handle,
 | 
			
		|||
{
 | 
			
		||||
	int err = 0;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	if (IS_I_VERSION(inode))
 | 
			
		||||
		inode_inc_iversion(inode);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5521,6 +5544,9 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
 | 
			
		|||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	err = ext4_get_inode_loc(inode, iloc);
 | 
			
		||||
	if (!err) {
 | 
			
		||||
		BUFFER_TRACE(iloc->bh, "get_write_access");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2939,6 +2939,9 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
 | 
			
		|||
	struct ext4_dir_entry_2 *de;
 | 
			
		||||
	handle_t *handle = NULL;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	/* Initialize quotas before so that eventual writes go in
 | 
			
		||||
	 * separate transaction */
 | 
			
		||||
	retval = dquot_initialize(dir);
 | 
			
		||||
| 
						 | 
				
			
			@ -3012,6 +3015,9 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 | 
			
		|||
	struct ext4_dir_entry_2 *de;
 | 
			
		||||
	handle_t *handle = NULL;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	trace_ext4_unlink_enter(dir, dentry);
 | 
			
		||||
	/* Initialize quotas before so that eventual writes go
 | 
			
		||||
	 * in separate transaction */
 | 
			
		||||
| 
						 | 
				
			
			@ -3082,6 +3088,9 @@ static int ext4_symlink(struct inode *dir,
 | 
			
		|||
	struct fscrypt_str disk_link;
 | 
			
		||||
	struct fscrypt_symlink_data *sd = NULL;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	disk_link.len = len + 1;
 | 
			
		||||
	disk_link.name = (char *) symname;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3874,6 +3883,9 @@ static int ext4_rename2(struct inode *old_dir, struct dentry *old_dentry,
 | 
			
		|||
			struct inode *new_dir, struct dentry *new_dentry,
 | 
			
		||||
			unsigned int flags)
 | 
			
		||||
{
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(old_dir->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -158,7 +158,7 @@ static int ext4_end_io(ext4_io_end_t *io)
 | 
			
		|||
 | 
			
		||||
	io->handle = NULL;	/* Following call will use up the handle */
 | 
			
		||||
	ret = ext4_convert_unwritten_extents(handle, inode, offset, size);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
	if (ret < 0 && !ext4_forced_shutdown(EXT4_SB(inode->i_sb))) {
 | 
			
		||||
		ext4_msg(inode->i_sb, KERN_EMERG,
 | 
			
		||||
			 "failed to convert unwritten extents to written "
 | 
			
		||||
			 "extents -- potential data loss!  "
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -438,6 +438,9 @@ void __ext4_error(struct super_block *sb, const char *function,
 | 
			
		|||
	struct va_format vaf;
 | 
			
		||||
	va_list args;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (ext4_error_ratelimit(sb)) {
 | 
			
		||||
		va_start(args, fmt);
 | 
			
		||||
		vaf.fmt = fmt;
 | 
			
		||||
| 
						 | 
				
			
			@ -459,6 +462,9 @@ void __ext4_error_inode(struct inode *inode, const char *function,
 | 
			
		|||
	struct va_format vaf;
 | 
			
		||||
	struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	es->s_last_error_ino = cpu_to_le32(inode->i_ino);
 | 
			
		||||
	es->s_last_error_block = cpu_to_le64(block);
 | 
			
		||||
	if (ext4_error_ratelimit(inode->i_sb)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -491,6 +497,9 @@ void __ext4_error_file(struct file *file, const char *function,
 | 
			
		|||
	struct inode *inode = file_inode(file);
 | 
			
		||||
	char pathname[80], *path;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	es = EXT4_SB(inode->i_sb)->s_es;
 | 
			
		||||
	es->s_last_error_ino = cpu_to_le32(inode->i_ino);
 | 
			
		||||
	if (ext4_error_ratelimit(inode->i_sb)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -567,6 +576,9 @@ void __ext4_std_error(struct super_block *sb, const char *function,
 | 
			
		|||
	char nbuf[16];
 | 
			
		||||
	const char *errstr;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* Special case: if the error is EROFS, and we're not already
 | 
			
		||||
	 * inside a transaction, then there's really no point in logging
 | 
			
		||||
	 * an error. */
 | 
			
		||||
| 
						 | 
				
			
			@ -600,6 +612,9 @@ void __ext4_abort(struct super_block *sb, const char *function,
 | 
			
		|||
	struct va_format vaf;
 | 
			
		||||
	va_list args;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	save_error_info(sb, function, line);
 | 
			
		||||
	va_start(args, fmt);
 | 
			
		||||
	vaf.fmt = fmt;
 | 
			
		||||
| 
						 | 
				
			
			@ -695,6 +710,9 @@ __acquires(bitlock)
 | 
			
		|||
	va_list args;
 | 
			
		||||
	struct ext4_super_block *es = EXT4_SB(sb)->s_es;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	es->s_last_error_ino = cpu_to_le32(ino);
 | 
			
		||||
	es->s_last_error_block = cpu_to_le64(block);
 | 
			
		||||
	__save_error_info(sb, function, line);
 | 
			
		||||
| 
						 | 
				
			
			@ -4717,6 +4735,9 @@ static int ext4_sync_fs(struct super_block *sb, int wait)
 | 
			
		|||
	bool needs_barrier = false;
 | 
			
		||||
	struct ext4_sb_info *sbi = EXT4_SB(sb);
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	trace_ext4_sync_fs(sb, wait);
 | 
			
		||||
	flush_workqueue(sbi->rsv_conversion_wq);
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -411,6 +411,9 @@ ext4_xattr_get(struct inode *inode, int name_index, const char *name,
 | 
			
		|||
{
 | 
			
		||||
	int error;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	if (strlen(name) > 255)
 | 
			
		||||
		return -ERANGE;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue