162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/fs/jfs/ioctl.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2006 Herbert Poetzl
662306a36Sopenharmony_ci * adapted from Remy Card's ext2/ioctl.c
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/fs.h>
1062306a36Sopenharmony_ci#include <linux/ctype.h>
1162306a36Sopenharmony_ci#include <linux/capability.h>
1262306a36Sopenharmony_ci#include <linux/mount.h>
1362306a36Sopenharmony_ci#include <linux/time.h>
1462306a36Sopenharmony_ci#include <linux/sched.h>
1562306a36Sopenharmony_ci#include <linux/blkdev.h>
1662306a36Sopenharmony_ci#include <asm/current.h>
1762306a36Sopenharmony_ci#include <linux/uaccess.h>
1862306a36Sopenharmony_ci#include <linux/fileattr.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include "jfs_filsys.h"
2162306a36Sopenharmony_ci#include "jfs_debug.h"
2262306a36Sopenharmony_ci#include "jfs_incore.h"
2362306a36Sopenharmony_ci#include "jfs_dinode.h"
2462306a36Sopenharmony_ci#include "jfs_inode.h"
2562306a36Sopenharmony_ci#include "jfs_dmap.h"
2662306a36Sopenharmony_ci#include "jfs_discard.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic struct {
2962306a36Sopenharmony_ci	long jfs_flag;
3062306a36Sopenharmony_ci	long ext2_flag;
3162306a36Sopenharmony_ci} jfs_map[] = {
3262306a36Sopenharmony_ci	{JFS_NOATIME_FL,	FS_NOATIME_FL},
3362306a36Sopenharmony_ci	{JFS_DIRSYNC_FL,	FS_DIRSYNC_FL},
3462306a36Sopenharmony_ci	{JFS_SYNC_FL,		FS_SYNC_FL},
3562306a36Sopenharmony_ci	{JFS_SECRM_FL,		FS_SECRM_FL},
3662306a36Sopenharmony_ci	{JFS_UNRM_FL,		FS_UNRM_FL},
3762306a36Sopenharmony_ci	{JFS_APPEND_FL,		FS_APPEND_FL},
3862306a36Sopenharmony_ci	{JFS_IMMUTABLE_FL,	FS_IMMUTABLE_FL},
3962306a36Sopenharmony_ci	{0, 0},
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic long jfs_map_ext2(unsigned long flags, int from)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	int index=0;
4562306a36Sopenharmony_ci	long mapped=0;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	while (jfs_map[index].jfs_flag) {
4862306a36Sopenharmony_ci		if (from) {
4962306a36Sopenharmony_ci			if (jfs_map[index].ext2_flag & flags)
5062306a36Sopenharmony_ci				mapped |= jfs_map[index].jfs_flag;
5162306a36Sopenharmony_ci		} else {
5262306a36Sopenharmony_ci			if (jfs_map[index].jfs_flag & flags)
5362306a36Sopenharmony_ci				mapped |= jfs_map[index].ext2_flag;
5462306a36Sopenharmony_ci		}
5562306a36Sopenharmony_ci		index++;
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci	return mapped;
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ciint jfs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	struct jfs_inode_info *jfs_inode = JFS_IP(d_inode(dentry));
6362306a36Sopenharmony_ci	unsigned int flags = jfs_inode->mode2 & JFS_FL_USER_VISIBLE;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (d_is_special(dentry))
6662306a36Sopenharmony_ci		return -ENOTTY;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	fileattr_fill_flags(fa, jfs_map_ext2(flags, 0));
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	return 0;
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ciint jfs_fileattr_set(struct mnt_idmap *idmap,
7462306a36Sopenharmony_ci		     struct dentry *dentry, struct fileattr *fa)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct inode *inode = d_inode(dentry);
7762306a36Sopenharmony_ci	struct jfs_inode_info *jfs_inode = JFS_IP(inode);
7862306a36Sopenharmony_ci	unsigned int flags;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	if (d_is_special(dentry))
8162306a36Sopenharmony_ci		return -ENOTTY;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	if (fileattr_has_fsx(fa))
8462306a36Sopenharmony_ci		return -EOPNOTSUPP;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	flags = jfs_map_ext2(fa->flags, 1);
8762306a36Sopenharmony_ci	if (!S_ISDIR(inode->i_mode))
8862306a36Sopenharmony_ci		flags &= ~JFS_DIRSYNC_FL;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* Is it quota file? Do not allow user to mess with it */
9162306a36Sopenharmony_ci	if (IS_NOQUOTA(inode))
9262306a36Sopenharmony_ci		return -EPERM;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	flags = flags & JFS_FL_USER_MODIFIABLE;
9562306a36Sopenharmony_ci	flags |= jfs_inode->mode2 & ~JFS_FL_USER_MODIFIABLE;
9662306a36Sopenharmony_ci	jfs_inode->mode2 = flags;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	jfs_set_inode_flags(inode);
9962306a36Sopenharmony_ci	inode_set_ctime_current(inode);
10062306a36Sopenharmony_ci	mark_inode_dirty(inode);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	return 0;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cilong jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	struct inode *inode = file_inode(filp);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	switch (cmd) {
11062306a36Sopenharmony_ci	case FITRIM:
11162306a36Sopenharmony_ci	{
11262306a36Sopenharmony_ci		struct super_block *sb = inode->i_sb;
11362306a36Sopenharmony_ci		struct fstrim_range range;
11462306a36Sopenharmony_ci		s64 ret = 0;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci		if (!capable(CAP_SYS_ADMIN))
11762306a36Sopenharmony_ci			return -EPERM;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci		if (!bdev_max_discard_sectors(sb->s_bdev)) {
12062306a36Sopenharmony_ci			jfs_warn("FITRIM not supported on device");
12162306a36Sopenharmony_ci			return -EOPNOTSUPP;
12262306a36Sopenharmony_ci		}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci		if (copy_from_user(&range, (struct fstrim_range __user *)arg,
12562306a36Sopenharmony_ci		    sizeof(range)))
12662306a36Sopenharmony_ci			return -EFAULT;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		range.minlen = max_t(unsigned int, range.minlen,
12962306a36Sopenharmony_ci				     bdev_discard_granularity(sb->s_bdev));
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci		ret = jfs_ioc_trim(inode, &range);
13262306a36Sopenharmony_ci		if (ret < 0)
13362306a36Sopenharmony_ci			return ret;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci		if (copy_to_user((struct fstrim_range __user *)arg, &range,
13662306a36Sopenharmony_ci		    sizeof(range)))
13762306a36Sopenharmony_ci			return -EFAULT;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		return 0;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	default:
14362306a36Sopenharmony_ci		return -ENOTTY;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci}
146