// SPDX-License-Identifier: GPL-2.0
/*
* linux/fs/ext4/ioctl.c
*
* Copyright (C) 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*/
#include <linux/fs.h>
#include <linux/capability.h>
#include <linux/time.h>
#include <linux/compat.h>
#include <linux/mount.h>
#include <linux/file.h>
#include <linux/quotaops.h>
#include <linux/random.h>
#include <linux/uuid.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/iversion.h>
#include <linux/fileattr.h>
#include "ext4_jbd2.h"
#include "ext4.h"
#include <linux/fsmap.h>
#include "fsmap.h"
#include <trace/events/ext4.h>
typedef void ext4_update_sb_callback(struct ext4_super_block *es,
const void *arg);
/*
* Superblock modification callback function for changing file system
* label
*/
static void ext4_sb_setlabel(struct ext4_super_block *es, const void *arg)
{
/* Sanity check, this should never happen */
BUILD_BUG_ON(sizeof(es->s_volume_name) < EXT4_LABEL_MAX);
memcpy(es->s_volume_name, (char *)arg, EXT4_LABEL_MAX);
}
static
int ext4_update_primary_sb(struct super_block *sb, handle_t *handle,
ext4_update_sb_callback func,
const void *arg)
{
int err = 0;
struct ext4_sb_info *sbi = EXT4_SB(sb);
struct buffer_head *bh = sbi->s_sbh;
struct ext4_super_block *es = sbi->s_es;
trace_ext4_update_sb(sb, bh->b_blocknr, 1);
BUFFER_TRACE(bh, "get_write_access");
err = ext4_journal_get_write_access(handle, sb,
bh,
EXT4_JTR_NONE);
if (err)
goto out_err;
lock_buffer(bh);
func(es, arg);
ext4_superblock_csum_set(sb);
unlock_buffer(bh);
if (buffer_write_io_error(bh) || !buffer_uptodate(bh)) {
ext4_msg(sbi->s_sb, KERN_ERR, "previous I/O error to "
"superblock detected");
clear_buffer_write_io_error(bh);
set_buffer_uptodate(bh);
}
err = ext4_handle_dirty_metadata(handle, NULL, bh);
if (err)
goto out_err;
err = sync_dirty_buffer(bh);
out_err:
ext4_std_error(sb, err);
return err;
}
/*
* Update one backup superblock in the group 'grp' using the callback
* function 'func' and argument 'arg'. If the handle is NULL the
* modification is not journalled.
*
* Returns: 0 when no modification was done (no superblock in the group)
* 1 when the modification was successful
* <0 on error
*/
static int ext4_update_backup_sb(struct super_block *sb,
handle_t *handle, ext4_group_t grp,
ext4_update_sb_callback func, const void *arg)
{
int err = 0;
ext4_fsblk_t sb_block;
struct buffer_head *bh;
unsigned long offset = 0;
struct ext4_super_block *es;
if (!ext4_bg_has_super(sb, grp))
return 0;
/*
* For the group 0 there is always 1k padding, so we have
* either adjust offset, or sb_block depending on blocksize
*/
if (grp == 0) {
sb_block = 1 * EXT4_MIN_BLOCK_SIZE;
offset = do_div(sb_block, sb->s_blocksize);
} else {
sb_block = ext4_group_first_block_no(sb, grp);
offset = 0;
}
trace_ext4_update_sb(sb, sb_block, hand
|