mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
* google/upstream-f2fs-stable-linux-4.14.y: f2fs: fix to do sanity check on .cp_pack_total_block_count f2fs: make gc_urgent and gc_segment_mode sysfs node readable f2fs: use aggressive GC policy during f2fs_disable_checkpoint() f2fs: fix compressed file start atomic write may cause data corruption f2fs: initialize sbi->gc_mode explicitly f2fs: introduce gc_urgent_mid mode f2fs: compress: fix to print raw data size in error path of lz4 decompression f2fs: remove redundant parameter judgment f2fs: use spin_lock to avoid hang f2fs: don't get FREEZE lock in f2fs_evict_inode in frozen fs f2fs: remove unnecessary read for F2FS_FITS_IN_INODE f2fs: fix to do sanity check on curseg->alloc_type f2fs: fix to avoid potential deadlock f2fs: quota: fix loop condition at f2fs_quota_sync() f2fs: Restore rwsem lockdep support f2fs: fix missing free nid in f2fs_handle_failed_inode f2fs: add a way to limit roll forward recovery time f2fs: introduce F2FS_IPU_HONOR_OPU_WRITE ipu policy f2fs: adjust readahead block number during recovery f2fs: fix to unlock page correctly in error path of is_alive() f2fs: expose discard related parameters in sysfs f2fs: move discard parameters into discard_cmd_control f2fs: fix to enable ATGC correctly via gc_idle sysfs interface f2fs: move f2fs to use reader-unfair rwsems f2fs: do not allow partial truncation on pinned file f2fs: remove redunant invalidate compress pages f2fs: Simplify bool conversion f2fs: don't drop compressed page cache in .{invalidate,release}page f2fs: fix to reserve space for IO align feature f2fs: fix to check available space of CP area correctly in update_ckpt_flags() f2fs: support fault injection to f2fs_trylock_op() f2fs: clean up __find_inline_xattr() with __find_xattr() f2fs: fix to do sanity check on last xattr entry in __f2fs_setxattr() f2fs: do not bother checkpoint by f2fs_get_node_info f2fs: avoid down_write on nat_tree_lock during checkpoint f2fs: compress: fix potential deadlock of compress file f2fs: avoid EINVAL by SBI_NEED_FSCK when pinning a file f2fs: add gc_urgent_high_remaining sysfs node f2fs: fix to do sanity check in is_alive() f2fs: fix to avoid panic in is_alive() if metadata is inconsistent f2fs: fix to do sanity check on inode type during garbage collection f2fs: avoid duplicate call of mark_inode_dirty f2fs: fix remove page failed in invalidate compress pages f2fs: fix the f2fs_file_write_iter tracepoint f2fs: do not expose unwritten blocks to user by DIO f2fs: reduce indentation in f2fs_file_write_iter() f2fs: rework write preallocations f2fs: compress: reduce one page array alloc and free when write compressed page f2fs: show number of pending discard commands f2fs: check nr_pages for readahead f2fs: fix UAF in f2fs_available_free_memory f2fs: invalidate META_MAPPING before IPU/DIO write f2fs: support fault injection for dquot_initialize() f2fs: fix incorrect return value in f2fs_sanity_check_ckpt() f2fs: compress: disallow disabling compress on non-empty compressed file f2fs: compress: fix overwrite may reduce compress ratio unproperly f2fs: multidevice: support direct IO f2fs: introduce fragment allocation mode mount option f2fs: include non-compressed blocks in compr_written_block f2fs: fix wrong condition to trigger background checkpoint correctly f2fs: fix to use WHINT_MODE f2fs: fix up f2fs_lookup tracepoints f2fs: set SBI_NEED_FSCK flag when inconsistent node block found f2fs: introduce excess_dirty_threshold() f2fs: avoid attaching SB_ACTIVE flag during mount f2fs: quota: fix potential deadlock f2fs: should use GFP_NOFS for directory inodes f2fs: should put a page beyond EOF when preparing a write f2fs: deallocate compressed pages when error happens f2fs: enable realtime discard iff device supports discard f2fs: guarantee to write dirty data when enabling checkpoint back f2fs: fix to unmap pages from userspace process in punch_hole() f2fs: fix unexpected ENOENT comes from f2fs_map_blocks() f2fs: fix to account missing .skipped_gc_rwsem f2fs: adjust unlock order for cleanup f2fs: Don't create discard thread when device doesn't support realtime discard f2fs: rebuild nat_bits during umount f2fs: introduce periodic iostat io latency traces f2fs: separate out iostat feature f2fs: compress: do sanity check on cluster f2fs: fix description about main_blkaddr node f2fs: convert S_IRUGO to 0444 f2fs: fix to keep compatibility of fault injection interface f2fs: support fault injection for f2fs_kmem_cache_alloc() f2fs: compress: allow write compress released file after truncate to zero f2fs: correct comment in segment.h f2fs: improve sbi status info in debugfs/f2fs/status f2fs: compress: avoid duplicate counting of valid blocks when read compressed file f2fs: fix to do sanity check for sb/cp fields correctly f2fs: avoid unneeded memory allocation in __add_ino_entry() f2fs: extent cache: support unaligned extent f2fs: Kconfig: clean up config options about compression f2fs: reduce the scope of setting fsck tag when de->name_len is zero f2fs: fix to stop filesystem update once CP failed f2fs: introduce discard_unit mount option f2fs: fix min_seq_blocks can not make sense in some scenes. f2fs: fix to force keeping write barrier for strict fsync mode f2fs: fix wrong checkpoint_changed value in f2fs_remount() f2fs: show sbi status in debugfs/f2fs/status f2fs: turn back remapped address in compressed page endio f2fs: change fiemap way in printing compression chunk f2fs: do not submit NEW_ADDR to read node block f2fs: compress: remove unneeded read when rewrite whole cluster f2fs: don't sleep while grabing nat_tree_lock f2fs: remove allow_outplace_dio() f2fs: make f2fs_write_failed() take struct inode f2fs: quota: fix potential deadlock f2fs: let's keep writing IOs on SBI_NEED_FSCK f2fs: Revert "f2fs: Fix indefinite loop in f2fs_gc() v1" f2fs: avoid to create an empty string as the extension_list f2fs: compress: fix to set zstd compress level correctly f2fs: add sysfs nodes to get GC info for each GC mode f2fs: drop dirty node pages when cp is in error status f2fs: initialize page->private when using for our internal use f2fs: compress: add nocompress extensions support Revert "f2fs: avoid attaching SB_ACTIVE flag during mount/remount" f2fs: remove false alarm on iget failure during GC f2fs: enable extent cache for compression files in read-only f2fs: fix to avoid adding tab before doc section f2fs: introduce f2fs_casefolded_name slab cache f2fs: swap: support migrating swapfile in aligned write mode f2fs: swap: remove dead codes f2fs: compress: add compress_inode to cache compressed blocks f2fs: clean up /sys/fs/f2fs/<disk>/features f2fs: add pin_file in feature list f2fs: Advertise encrypted casefolding in sysfs f2fs: Show casefolding support only when supported f2fs: support RO feature f2fs: logging neatening f2fs: restructure f2fs page.private layout f2fs: introduce FI_COMPRESS_RELEASED instead of using IMMUTABLE bit f2fs: compress: remove unneeded preallocation f2fs: avoid attaching SB_ACTIVE flag during mount/remount f2fs: atgc: export entries for better tunability via sysfs f2fs: compress: fix to disallow temp extension f2fs: let's allow compression for mmap files f2fs: add MODULE_SOFTDEP to ensure crc32 is included in the initramfs f2fs: return success if there is no work to do f2fs: compress: clean up parameter of __f2fs_cluster_blocks() f2fs: compress: remove unneeded f2fs_put_dnode() f2fs: atgc: fix to set default age threshold f2fs: Prevent swap file in LFS mode f2fs: fix to avoid racing on fsync_entry_slab by multi filesystem instances f2fs: add cp_error check in f2fs_write_compressed_pages f2fs: compress: rename __cluster_may_compress f2fs: return EINVAL for hole cases in swap file f2fs: avoid swapon failure by giving a warning first f2fs: compress: fix to assign cc.cluster_idx correctly f2fs: compress: fix race condition of overwrite vs truncate f2fs: compress: fix to free compress page correctly f2fs: support iflag change given the mask f2fs: avoid null pointer access when handling IPU error f2fs: drop inplace IO if fs status is abnormal f2fs: compress: remove unneed check condition f2fs: clean up left deprecated IO trace codes f2fs: avoid using native allocate_segment_by_default() f2fs: remove unnecessary struct declaration f2fs: fix to avoid NULL pointer dereference f2fs: avoid duplicated codes for cleanup f2fs: document: add description about compressed space handling f2fs: clean up build warnings f2fs: fix the periodic wakeups of discard thread f2fs: fix to avoid accessing invalid fio in f2fs_allocate_data_block() f2fs: fix to avoid GC/mmap race with f2fs_truncate() f2fs: set checkpoint_merge by default f2fs: Fix a hungtask problem in atomic write f2fs: fix to restrict mount condition on readonly block device f2fs: introduce gc_merge mount option f2fs: fix to cover __allocate_new_section() with curseg_lock f2fs: fix wrong alloc_type in f2fs_do_replace_block f2fs: delete empty compress.h f2fs: fix a typo in inode.c f2fs: allow to change discard policy based on cached discard cmds f2fs: fix to avoid touching checkpointed data in get_victim() f2fs: fix to update last i_size if fallocate partially succeeds f2fs: fix error path of f2fs_remount() f2fs: fix wrong comment of nat_tree_lock f2fs: fix to avoid out-of-bounds memory access f2fs: don't start checkpoint thread in readonly mountpoint f2fs: do not use AT_SSR mode in FG_GC & high urgent BG_GC f2fs: add sysfs nodes to get runtime compression stat f2fs: fix to use per-inode maxbytes in f2fs_fiemap f2fs: fix to align to section for fallocate() on pinned file f2fs: expose # of overprivision segments f2fs: fix error handling in f2fs_end_enable_verity() f2fs: fix a redundant call to f2fs_balance_fs if an error occurs f2fs: remove unused file_clear_encrypt() f2fs: check if swapfile is section-alligned f2fs: fix last_lblock check in check_swap_activate_fast f2fs: remove unnecessary IS_SWAPFILE check f2fs: Replace one-element array with flexible-array member f2fs: compress: Allow modular (de)compression algorithms f2fs: check discard command number before traversing discard pending list f2fs: update comments for explicit memory barrier f2fs: remove unused FORCE_FG_GC macro f2fs: avoid unused f2fs_show_compress_options() f2fs: fix panic during f2fs_resize_fs() f2fs: fix to allow migrating fully valid segment f2fs: fix a spelling error f2fs: fix a spacing coding style fs: Enable bmap() function to properly return errors f2fs: remove obsolete f2fs.txt fs-verity: support reading signature with ioctl fs-verity: support reading descriptor with ioctl fs-verity: support reading Merkle tree with ioctl fs-verity: add FS_IOC_READ_VERITY_METADATA ioctl fs-verity: don't pass whole descriptor to fsverity_verify_signature() fs-verity: factor out fsverity_get_descriptor() fs-verity: move structs needed for file signing to UAPI header fs-verity: rename "file measurement" to "file digest" fs-verity: rename fsverity_signed_digest to fsverity_formatted_digest fs-verity: remove filenames from file comments fs-verity: use smp_load_acquire() for ->i_verity_info f2fs: remove FAULT_ALLOC_BIO f2fs: use blkdev_issue_flush in __submit_flush_wait f2fs: remove a few bd_part checks quota: Cleanup list iteration in dqcache_shrink_scan() quota: reclaim least recently used dquots fs: quota: Replace GFP_ATOMIC with GFP_KERNEL in dquot_init quota: Check for register_shrinker() failure. quota: propagate error from __dquot_initialize quota: be aware of error from dquot_initialize Documentation: f2fs: fix typo s/automaic/automatic f2fs: give a warning only for readonly partition f2fs: don't grab superblock freeze for flush/ckpt thread f2fs: add ckpt_thread_ioprio sysfs node f2fs: introduce checkpoint_merge mount option f2fs: relocate inline conversion from mmap() to mkwrite() f2fs: fix a wrong condition in __submit_bio f2fs: remove unnecessary initialization in xattr.c f2fs: fix to avoid inconsistent quota data f2fs: flush data when enabling checkpoint back f2fs: deprecate f2fs_trace_io f2fs: remove unused stat_{inc, dec}_atomic_write f2fs: introduce sb_status sysfs node f2fs: fix to use per-inode maxbytes f2fs: compress: fix potential deadlock libfs: unexport generic_ci_d_compare() and generic_ci_d_hash() f2fs: fix to set/clear I_LINKABLE under i_lock f2fs: fix null page reference in redirty_blocks f2fs: clean up post-read processing f2fs: trival cleanup in move_data_block() f2fs: fix out-of-repair __setattr_copy() f2fs: fix to tag FIEMAP_EXTENT_MERGED in f2fs_fiemap() f2fs: introduce a new per-sb directory in sysfs f2fs: compress: support compress level f2fs: compress: deny setting unsupported compress algorithm f2fs: relocate f2fs_precache_extents() f2fs: enforce the immutable flag on open files f2fs: enhance to update i_mode and acl atomically in f2fs_setattr() f2fs: fix to set inode->i_mode correctly for posix_acl_update_mode f2fs: Replace expression with offsetof() f2fs: handle unallocated section and zone on pinned/atgc f2fs: compress: fix compression chksum f2fs: fix shift-out-of-bounds in sanity_check_raw_super() f2fs: fix race of pending_pages in decompression f2fs: fix to account inline xattr correctly during recovery f2fs: inline: fix wrong inline inode stat f2fs: inline: correct comment in f2fs_recover_inline_data f2fs: don't check PAGE_SIZE again in sanity_check_raw_super() f2fs: convert to F2FS_*_INO macro f2fs: introduce max_io_bytes, a sysfs entry, to limit bio size f2fs: don't allow any writes on readonly mount f2fs: avoid race condition for shrinker count f2fs: add F2FS_IOC_DECOMPRESS_FILE and F2FS_IOC_COMPRESS_FILE f2fs: add compress_mode mount option f2fs: Remove unnecessary unlikely() f2fs: init dirty_secmap incorrectly f2fs: remove buffer_head which has 32bits limit f2fs: fix wrong block count instead of bytes f2fs: use new conversion functions between blks and bytes f2fs: rename logical_to_blk and blk_to_logical f2fs: fix kbytes written stat for multi-device case f2fs: compress: support chksum f2fs: fix to avoid REQ_TIME and CP_TIME collision f2fs: change to use rwsem for cp_mutex f2fs: Handle casefolding with Encryption fscrypt: Have filesystems handle their d_ops libfs: Add generic function for setting dentry_ops f2fs: Remove the redundancy initialization f2fs: remove writeback_inodes_sb in f2fs_remount f2fs: fix double free of unicode map f2fs: fix compat F2FS_IOC_{MOVE,GARBAGE_COLLECT}_RANGE f2fs: avoid unneeded data copy in f2fs_ioc_move_range() f2fs: add F2FS_IOC_SET_COMPRESS_OPTION ioctl f2fs: add F2FS_IOC_GET_COMPRESS_OPTION ioctl f2fs: move ioctl interface definitions to separated file f2fs: fix to seek incorrect data offset in inline data file f2fs: check fiemap parameters f2fs: call f2fs_get_meta_page_retry for nat page fscrypt: rename DCACHE_ENCRYPTED_NAME to DCACHE_NOKEY_NAME fscrypt: don't call no-key names "ciphertext names" fscrypt: export fscrypt_d_revalidate() f2fs: code cleanup by removing unnecessary check f2fs: wait for sysfs kobject removal before freeing f2fs_sb_info f2fs: fix writecount false positive in releasing compress blocks f2fs: introduce check_swap_activate_fast() f2fs: don't issue flush in f2fs_flush_device_cache() for nobarrier case f2fs: handle errors of f2fs_get_meta_page_nofail f2fs: fix to set SBI_NEED_FSCK flag for inconsistent inode f2fs: reject CASEFOLD inode flag without casefold feature f2fs: fix memory alignment to support 32bit f2fs: fix slab leak of rpages pointer f2fs: compress: fix to disallow enabling compress on non-empty file f2fs: compress: introduce cic/dic slab cache f2fs: compress: introduce page array slab cache f2fs: fix to do sanity check on segment/section count f2fs: fix to check segment boundary during SIT page readahead f2fs: fix uninit-value in f2fs_lookup fs/buffer.c: record blockdev write errors in super_block that it backs vfs: track per-sb writeback errors and report them to syncfs f2fs: remove unneeded parameter in find_in_block() f2fs: fix wrong total_sections check and fsmeta check f2fs: remove duplicated code in sanity_check_area_boundary f2fs: remove unused check on version_bitmap f2fs: relocate blkzoned feature check f2fs: do sanity check on zoned block device path f2fs: add trace exit in exception path f2fs: change return value of reserved_segments to unsigned int f2fs: clean up kvfree f2fs: change virtual mapping way for compression pages f2fs: change return value of f2fs_disable_compressed_file to bool f2fs: change i_compr_blocks of inode to atomic value f2fs: ignore compress mount option on image w/o compression feature f2fs: allocate proper size memory for zstd decompress f2fs: change compr_blocks of superblock info to 64bit f2fs: add block address limit check to compressed file f2fs: check position in move range ioctl f2fs: correct statistic of APP_DIRECT_IO/APP_DIRECT_READ_IO f2fs: support age threshold based garbage collection f2fs: Use generic casefolding support fs: Add standard casefolding support unicode: Add utf8_casefold_hash f2fs: compress: use more readable atomic_t type for {cic,dic}.ref f2fs: fix compile warning f2fs: support 64-bits key in f2fs rb-tree node entry f2fs: inherit mtime of original block during GC f2fs: record average update time of segment f2fs: introduce inmem curseg f2fs: compress: remove unneeded code f2fs: remove duplicated type casting f2fs: support zone capacity less than zone size f2fs: update changes in upstream on GC_URGENT_HIGH f2fs: Return EOF on unaligned end of file DIO read f2fs: fix indefinite loop scanning for free nid f2fs: Fix type of section block count variables f2fs: prepare a waiter before entering io_schedule f2fs: update_sit_entry: Make the judgment condition of f2fs_bug_on more intuitive f2fs: replace test_and_set/clear_bit() with set/clear_bit() f2fs: make file immutable even if releasing zero compression block f2fs: compress: disable compression mount option if compression is off f2fs: compress: add sanity check during compressed cluster read f2fs: use macro instead of f2fs verity version f2fs: fix deadlock between quota writes and checkpoint f2fs: correct comment of f2fs_exist_written_data f2fs: compress: delay temp page allocation f2fs: compress: fix to update isize when overwriting compressed file f2fs: space related cleanup f2fs: fix use-after-free issue f2fs: Change the type of f2fs_flush_inline_data() to void f2fs: add F2FS_IOC_SEC_TRIM_FILE ioctl f2fs: segment.h: delete a duplicated word f2fs: compress: fix to avoid memory leak on cc->cpages f2fs: use generic names for generic ioctls f2fs: don't keep meta inode pages used for compressed block migration f2fs: fix error path in do_recover_data() f2fs: fix to wait GCed compressed page writeback f2fs: remove write attribute of main_blkaddr sysfs node f2fs: add GC_URGENT_LOW mode in gc_urgent f2fs: avoid readahead race condition f2fs: fix return value of move_data_block() f2fs: add parameter op_flag in f2fs_submit_page_read() f2fs: split f2fs_allocate_new_segments() f2fs: lost matching-pair of trace in f2fs_truncate_inode_blocks f2fs: fix an oops in f2fs_is_compressed_page f2fs: make trace enter and end in pairs for unlink f2fs: fix to check page dirty status before writeback f2fs: remove the unused compr parameter f2fs: support to trace f2fs_fiemap() f2fs: support to trace f2fs_bmap() f2fs: fix wrong return value of f2fs_bmap_compress() f2fs: remove useless parameter of __insert_free_nid() f2fs: fix typo in comment of f2fs_do_add_link f2fs: fix to wait page writeback before update f2fs: show more debug info for per-temperature log f2fs: add f2fs_gc exception handle in f2fs_ioc_gc_range f2fs: clean up parameter of f2fs_allocate_data_block() f2fs: shrink node_write lock coverage f2fs: add prefix for exported symbols f2fs: use kfree() to free variables allocated by match_strdup() f2fs: get the right gc victim section when section has several segments f2fs: fix a race condition between f2fs_write_end_io and f2fs_del_fsync_node_entry f2fs: remove useless truncate in f2fs_collapse_range() f2fs: use kfree() instead of kvfree() to free superblock data f2fs: avoid checkpatch error f2fs: should avoid inode eviction in synchronous path
733 lines
18 KiB
C
733 lines
18 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* linux/fs/ioctl.c
|
|
*
|
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
|
*/
|
|
|
|
#include <linux/syscalls.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/capability.h>
|
|
#include <linux/file.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/security.h>
|
|
#include <linux/export.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/writeback.h>
|
|
#include <linux/buffer_head.h>
|
|
#include <linux/falloc.h>
|
|
#include <linux/sched/signal.h>
|
|
|
|
#include "internal.h"
|
|
|
|
#include <asm/ioctls.h>
|
|
|
|
/* So that the fiemap access checks can't overflow on 32 bit machines. */
|
|
#define FIEMAP_MAX_EXTENTS (UINT_MAX / sizeof(struct fiemap_extent))
|
|
|
|
/**
|
|
* vfs_ioctl - call filesystem specific ioctl methods
|
|
* @filp: open file to invoke ioctl method on
|
|
* @cmd: ioctl command to execute
|
|
* @arg: command-specific argument for ioctl
|
|
*
|
|
* Invokes filesystem specific ->unlocked_ioctl, if one exists; otherwise
|
|
* returns -ENOTTY.
|
|
*
|
|
* Returns 0 on success, -errno on error.
|
|
*/
|
|
long vfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
{
|
|
int error = -ENOTTY;
|
|
|
|
if (!filp->f_op->unlocked_ioctl)
|
|
goto out;
|
|
|
|
error = filp->f_op->unlocked_ioctl(filp, cmd, arg);
|
|
if (error == -ENOIOCTLCMD)
|
|
error = -ENOTTY;
|
|
out:
|
|
return error;
|
|
}
|
|
|
|
static int ioctl_fibmap(struct file *filp, int __user *p)
|
|
{
|
|
struct address_space *mapping = filp->f_mapping;
|
|
int res, block;
|
|
|
|
/* do we support this mess? */
|
|
if (!mapping->a_ops->bmap)
|
|
return -EINVAL;
|
|
if (!capable(CAP_SYS_RAWIO))
|
|
return -EPERM;
|
|
res = get_user(block, p);
|
|
if (res)
|
|
return res;
|
|
res = mapping->a_ops->bmap(mapping, block);
|
|
return put_user(res, p);
|
|
}
|
|
|
|
/**
|
|
* fiemap_fill_next_extent - Fiemap helper function
|
|
* @fieinfo: Fiemap context passed into ->fiemap
|
|
* @logical: Extent logical start offset, in bytes
|
|
* @phys: Extent physical start offset, in bytes
|
|
* @len: Extent length, in bytes
|
|
* @flags: FIEMAP_EXTENT flags that describe this extent
|
|
*
|
|
* Called from file system ->fiemap callback. Will populate extent
|
|
* info as passed in via arguments and copy to user memory. On
|
|
* success, extent count on fieinfo is incremented.
|
|
*
|
|
* Returns 0 on success, -errno on error, 1 if this was the last
|
|
* extent that will fit in user array.
|
|
*/
|
|
#define SET_UNKNOWN_FLAGS (FIEMAP_EXTENT_DELALLOC)
|
|
#define SET_NO_UNMOUNTED_IO_FLAGS (FIEMAP_EXTENT_DATA_ENCRYPTED)
|
|
#define SET_NOT_ALIGNED_FLAGS (FIEMAP_EXTENT_DATA_TAIL|FIEMAP_EXTENT_DATA_INLINE)
|
|
int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical,
|
|
u64 phys, u64 len, u32 flags)
|
|
{
|
|
struct fiemap_extent extent;
|
|
struct fiemap_extent __user *dest = fieinfo->fi_extents_start;
|
|
|
|
/* only count the extents */
|
|
if (fieinfo->fi_extents_max == 0) {
|
|
fieinfo->fi_extents_mapped++;
|
|
return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0;
|
|
}
|
|
|
|
if (fieinfo->fi_extents_mapped >= fieinfo->fi_extents_max)
|
|
return 1;
|
|
|
|
if (flags & SET_UNKNOWN_FLAGS)
|
|
flags |= FIEMAP_EXTENT_UNKNOWN;
|
|
if (flags & SET_NO_UNMOUNTED_IO_FLAGS)
|
|
flags |= FIEMAP_EXTENT_ENCODED;
|
|
if (flags & SET_NOT_ALIGNED_FLAGS)
|
|
flags |= FIEMAP_EXTENT_NOT_ALIGNED;
|
|
|
|
memset(&extent, 0, sizeof(extent));
|
|
extent.fe_logical = logical;
|
|
extent.fe_physical = phys;
|
|
extent.fe_length = len;
|
|
extent.fe_flags = flags;
|
|
|
|
dest += fieinfo->fi_extents_mapped;
|
|
if (copy_to_user(dest, &extent, sizeof(extent)))
|
|
return -EFAULT;
|
|
|
|
fieinfo->fi_extents_mapped++;
|
|
if (fieinfo->fi_extents_mapped == fieinfo->fi_extents_max)
|
|
return 1;
|
|
return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0;
|
|
}
|
|
EXPORT_SYMBOL(fiemap_fill_next_extent);
|
|
|
|
/**
|
|
* fiemap_check_flags - check validity of requested flags for fiemap
|
|
* @fieinfo: Fiemap context passed into ->fiemap
|
|
* @fs_flags: Set of fiemap flags that the file system understands
|
|
*
|
|
* Called from file system ->fiemap callback. This will compute the
|
|
* intersection of valid fiemap flags and those that the fs supports. That
|
|
* value is then compared against the user supplied flags. In case of bad user
|
|
* flags, the invalid values will be written into the fieinfo structure, and
|
|
* -EBADR is returned, which tells ioctl_fiemap() to return those values to
|
|
* userspace. For this reason, a return code of -EBADR should be preserved.
|
|
*
|
|
* Returns 0 on success, -EBADR on bad flags.
|
|
*/
|
|
int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags)
|
|
{
|
|
u32 incompat_flags;
|
|
|
|
incompat_flags = fieinfo->fi_flags & ~(FIEMAP_FLAGS_COMPAT & fs_flags);
|
|
if (incompat_flags) {
|
|
fieinfo->fi_flags = incompat_flags;
|
|
return -EBADR;
|
|
}
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(fiemap_check_flags);
|
|
|
|
static int fiemap_check_ranges(struct super_block *sb,
|
|
u64 start, u64 len, u64 *new_len)
|
|
{
|
|
u64 maxbytes = (u64) sb->s_maxbytes;
|
|
|
|
*new_len = len;
|
|
|
|
if (len == 0)
|
|
return -EINVAL;
|
|
|
|
if (start > maxbytes)
|
|
return -EFBIG;
|
|
|
|
/*
|
|
* Shrink request scope to what the fs can actually handle.
|
|
*/
|
|
if (len > maxbytes || (maxbytes - len) < start)
|
|
*new_len = maxbytes - start;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
|
u64 start, u64 *len, u32 supported_flags)
|
|
{
|
|
u64 maxbytes = inode->i_sb->s_maxbytes;
|
|
u32 incompat_flags;
|
|
|
|
if (*len == 0)
|
|
return -EINVAL;
|
|
|
|
if (start > maxbytes)
|
|
return -EFBIG;
|
|
|
|
/*
|
|
* Shrink request scope to what the fs can actually handle.
|
|
*/
|
|
if (*len > maxbytes || (maxbytes - *len) < start)
|
|
*len = maxbytes - start;
|
|
|
|
supported_flags &= FIEMAP_FLAGS_COMPAT;
|
|
incompat_flags = fieinfo->fi_flags & ~supported_flags;
|
|
if (incompat_flags) {
|
|
fieinfo->fi_flags = incompat_flags;
|
|
return -EBADR;
|
|
}
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(fiemap_prep);
|
|
|
|
static int ioctl_fiemap(struct file *filp, unsigned long arg)
|
|
{
|
|
struct fiemap fiemap;
|
|
struct fiemap __user *ufiemap = (struct fiemap __user *) arg;
|
|
struct fiemap_extent_info fieinfo = { 0, };
|
|
struct inode *inode = file_inode(filp);
|
|
struct super_block *sb = inode->i_sb;
|
|
u64 len;
|
|
int error;
|
|
|
|
if (!inode->i_op->fiemap)
|
|
return -EOPNOTSUPP;
|
|
|
|
if (copy_from_user(&fiemap, ufiemap, sizeof(fiemap)))
|
|
return -EFAULT;
|
|
|
|
if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS)
|
|
return -EINVAL;
|
|
|
|
error = fiemap_check_ranges(sb, fiemap.fm_start, fiemap.fm_length,
|
|
&len);
|
|
if (error)
|
|
return error;
|
|
|
|
fieinfo.fi_flags = fiemap.fm_flags;
|
|
fieinfo.fi_extents_max = fiemap.fm_extent_count;
|
|
fieinfo.fi_extents_start = ufiemap->fm_extents;
|
|
|
|
if (fiemap.fm_extent_count != 0 &&
|
|
!access_ok(VERIFY_WRITE, fieinfo.fi_extents_start,
|
|
fieinfo.fi_extents_max * sizeof(struct fiemap_extent)))
|
|
return -EFAULT;
|
|
|
|
if (fieinfo.fi_flags & FIEMAP_FLAG_SYNC)
|
|
filemap_write_and_wait(inode->i_mapping);
|
|
|
|
error = inode->i_op->fiemap(inode, &fieinfo, fiemap.fm_start, len);
|
|
fiemap.fm_flags = fieinfo.fi_flags;
|
|
fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped;
|
|
if (copy_to_user(ufiemap, &fiemap, sizeof(fiemap)))
|
|
error = -EFAULT;
|
|
|
|
return error;
|
|
}
|
|
|
|
static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd,
|
|
u64 off, u64 olen, u64 destoff)
|
|
{
|
|
struct fd src_file = fdget(srcfd);
|
|
int ret;
|
|
|
|
if (!src_file.file)
|
|
return -EBADF;
|
|
ret = -EXDEV;
|
|
if (src_file.file->f_path.mnt != dst_file->f_path.mnt)
|
|
goto fdput;
|
|
ret = vfs_clone_file_range(src_file.file, off, dst_file, destoff, olen);
|
|
fdput:
|
|
fdput(src_file);
|
|
return ret;
|
|
}
|
|
|
|
static long ioctl_file_clone_range(struct file *file, void __user *argp)
|
|
{
|
|
struct file_clone_range args;
|
|
|
|
if (copy_from_user(&args, argp, sizeof(args)))
|
|
return -EFAULT;
|
|
return ioctl_file_clone(file, args.src_fd, args.src_offset,
|
|
args.src_length, args.dest_offset);
|
|
}
|
|
|
|
#ifdef CONFIG_BLOCK
|
|
|
|
static inline sector_t logical_to_blk(struct inode *inode, loff_t offset)
|
|
{
|
|
return (offset >> inode->i_blkbits);
|
|
}
|
|
|
|
static inline loff_t blk_to_logical(struct inode *inode, sector_t blk)
|
|
{
|
|
return (blk << inode->i_blkbits);
|
|
}
|
|
|
|
/**
|
|
* __generic_block_fiemap - FIEMAP for block based inodes (no locking)
|
|
* @inode: the inode to map
|
|
* @fieinfo: the fiemap info struct that will be passed back to userspace
|
|
* @start: where to start mapping in the inode
|
|
* @len: how much space to map
|
|
* @get_block: the fs's get_block function
|
|
*
|
|
* This does FIEMAP for block based inodes. Basically it will just loop
|
|
* through get_block until we hit the number of extents we want to map, or we
|
|
* go past the end of the file and hit a hole.
|
|
*
|
|
* If it is possible to have data blocks beyond a hole past @inode->i_size, then
|
|
* please do not use this function, it will stop at the first unmapped block
|
|
* beyond i_size.
|
|
*
|
|
* If you use this function directly, you need to do your own locking. Use
|
|
* generic_block_fiemap if you want the locking done for you.
|
|
*/
|
|
|
|
int __generic_block_fiemap(struct inode *inode,
|
|
struct fiemap_extent_info *fieinfo, loff_t start,
|
|
loff_t len, get_block_t *get_block)
|
|
{
|
|
struct buffer_head map_bh;
|
|
sector_t start_blk, last_blk;
|
|
loff_t isize = i_size_read(inode);
|
|
u64 logical = 0, phys = 0, size = 0;
|
|
u32 flags = FIEMAP_EXTENT_MERGED;
|
|
bool past_eof = false, whole_file = false;
|
|
int ret = 0;
|
|
|
|
ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/*
|
|
* Either the i_mutex or other appropriate locking needs to be held
|
|
* since we expect isize to not change at all through the duration of
|
|
* this call.
|
|
*/
|
|
if (len >= isize) {
|
|
whole_file = true;
|
|
len = isize;
|
|
}
|
|
|
|
/*
|
|
* Some filesystems can't deal with being asked to map less than
|
|
* blocksize, so make sure our len is at least block length.
|
|
*/
|
|
if (logical_to_blk(inode, len) == 0)
|
|
len = blk_to_logical(inode, 1);
|
|
|
|
start_blk = logical_to_blk(inode, start);
|
|
last_blk = logical_to_blk(inode, start + len - 1);
|
|
|
|
do {
|
|
/*
|
|
* we set b_size to the total size we want so it will map as
|
|
* many contiguous blocks as possible at once
|
|
*/
|
|
memset(&map_bh, 0, sizeof(struct buffer_head));
|
|
map_bh.b_size = len;
|
|
|
|
ret = get_block(inode, start_blk, &map_bh, 0);
|
|
if (ret)
|
|
break;
|
|
|
|
/* HOLE */
|
|
if (!buffer_mapped(&map_bh)) {
|
|
start_blk++;
|
|
|
|
/*
|
|
* We want to handle the case where there is an
|
|
* allocated block at the front of the file, and then
|
|
* nothing but holes up to the end of the file properly,
|
|
* to make sure that extent at the front gets properly
|
|
* marked with FIEMAP_EXTENT_LAST
|
|
*/
|
|
if (!past_eof &&
|
|
blk_to_logical(inode, start_blk) >= isize)
|
|
past_eof = 1;
|
|
|
|
/*
|
|
* First hole after going past the EOF, this is our
|
|
* last extent
|
|
*/
|
|
if (past_eof && size) {
|
|
flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST;
|
|
ret = fiemap_fill_next_extent(fieinfo, logical,
|
|
phys, size,
|
|
flags);
|
|
} else if (size) {
|
|
ret = fiemap_fill_next_extent(fieinfo, logical,
|
|
phys, size, flags);
|
|
size = 0;
|
|
}
|
|
|
|
/* if we have holes up to/past EOF then we're done */
|
|
if (start_blk > last_blk || past_eof || ret)
|
|
break;
|
|
} else {
|
|
/*
|
|
* We have gone over the length of what we wanted to
|
|
* map, and it wasn't the entire file, so add the extent
|
|
* we got last time and exit.
|
|
*
|
|
* This is for the case where say we want to map all the
|
|
* way up to the second to the last block in a file, but
|
|
* the last block is a hole, making the second to last
|
|
* block FIEMAP_EXTENT_LAST. In this case we want to
|
|
* see if there is a hole after the second to last block
|
|
* so we can mark it properly. If we found data after
|
|
* we exceeded the length we were requesting, then we
|
|
* are good to go, just add the extent to the fieinfo
|
|
* and break
|
|
*/
|
|
if (start_blk > last_blk && !whole_file) {
|
|
ret = fiemap_fill_next_extent(fieinfo, logical,
|
|
phys, size,
|
|
flags);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* if size != 0 then we know we already have an extent
|
|
* to add, so add it.
|
|
*/
|
|
if (size) {
|
|
ret = fiemap_fill_next_extent(fieinfo, logical,
|
|
phys, size,
|
|
flags);
|
|
if (ret)
|
|
break;
|
|
}
|
|
|
|
logical = blk_to_logical(inode, start_blk);
|
|
phys = blk_to_logical(inode, map_bh.b_blocknr);
|
|
size = map_bh.b_size;
|
|
flags = FIEMAP_EXTENT_MERGED;
|
|
|
|
start_blk += logical_to_blk(inode, size);
|
|
|
|
/*
|
|
* If we are past the EOF, then we need to make sure as
|
|
* soon as we find a hole that the last extent we found
|
|
* is marked with FIEMAP_EXTENT_LAST
|
|
*/
|
|
if (!past_eof && logical + size >= isize)
|
|
past_eof = true;
|
|
}
|
|
cond_resched();
|
|
if (fatal_signal_pending(current)) {
|
|
ret = -EINTR;
|
|
break;
|
|
}
|
|
|
|
} while (1);
|
|
|
|
/* If ret is 1 then we just hit the end of the extent array */
|
|
if (ret == 1)
|
|
ret = 0;
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(__generic_block_fiemap);
|
|
|
|
/**
|
|
* generic_block_fiemap - FIEMAP for block based inodes
|
|
* @inode: The inode to map
|
|
* @fieinfo: The mapping information
|
|
* @start: The initial block to map
|
|
* @len: The length of the extect to attempt to map
|
|
* @get_block: The block mapping function for the fs
|
|
*
|
|
* Calls __generic_block_fiemap to map the inode, after taking
|
|
* the inode's mutex lock.
|
|
*/
|
|
|
|
int generic_block_fiemap(struct inode *inode,
|
|
struct fiemap_extent_info *fieinfo, u64 start,
|
|
u64 len, get_block_t *get_block)
|
|
{
|
|
int ret;
|
|
inode_lock(inode);
|
|
ret = __generic_block_fiemap(inode, fieinfo, start, len, get_block);
|
|
inode_unlock(inode);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(generic_block_fiemap);
|
|
|
|
#endif /* CONFIG_BLOCK */
|
|
|
|
/*
|
|
* This provides compatibility with legacy XFS pre-allocation ioctls
|
|
* which predate the fallocate syscall.
|
|
*
|
|
* Only the l_start, l_len and l_whence fields of the 'struct space_resv'
|
|
* are used here, rest are ignored.
|
|
*/
|
|
int ioctl_preallocate(struct file *filp, void __user *argp)
|
|
{
|
|
struct inode *inode = file_inode(filp);
|
|
struct space_resv sr;
|
|
|
|
if (copy_from_user(&sr, argp, sizeof(sr)))
|
|
return -EFAULT;
|
|
|
|
switch (sr.l_whence) {
|
|
case SEEK_SET:
|
|
break;
|
|
case SEEK_CUR:
|
|
sr.l_start += filp->f_pos;
|
|
break;
|
|
case SEEK_END:
|
|
sr.l_start += i_size_read(inode);
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return vfs_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
|
|
}
|
|
|
|
static int file_ioctl(struct file *filp, unsigned int cmd,
|
|
unsigned long arg)
|
|
{
|
|
struct inode *inode = file_inode(filp);
|
|
int __user *p = (int __user *)arg;
|
|
|
|
switch (cmd) {
|
|
case FIBMAP:
|
|
return ioctl_fibmap(filp, p);
|
|
case FIONREAD:
|
|
return put_user(i_size_read(inode) - filp->f_pos, p);
|
|
case FS_IOC_RESVSP:
|
|
case FS_IOC_RESVSP64:
|
|
return ioctl_preallocate(filp, p);
|
|
}
|
|
|
|
return vfs_ioctl(filp, cmd, arg);
|
|
}
|
|
|
|
static int ioctl_fionbio(struct file *filp, int __user *argp)
|
|
{
|
|
unsigned int flag;
|
|
int on, error;
|
|
|
|
error = get_user(on, argp);
|
|
if (error)
|
|
return error;
|
|
flag = O_NONBLOCK;
|
|
#ifdef __sparc__
|
|
/* SunOS compatibility item. */
|
|
if (O_NONBLOCK != O_NDELAY)
|
|
flag |= O_NDELAY;
|
|
#endif
|
|
spin_lock(&filp->f_lock);
|
|
if (on)
|
|
filp->f_flags |= flag;
|
|
else
|
|
filp->f_flags &= ~flag;
|
|
spin_unlock(&filp->f_lock);
|
|
return error;
|
|
}
|
|
|
|
static int ioctl_fioasync(unsigned int fd, struct file *filp,
|
|
int __user *argp)
|
|
{
|
|
unsigned int flag;
|
|
int on, error;
|
|
|
|
error = get_user(on, argp);
|
|
if (error)
|
|
return error;
|
|
flag = on ? FASYNC : 0;
|
|
|
|
/* Did FASYNC state change ? */
|
|
if ((flag ^ filp->f_flags) & FASYNC) {
|
|
if (filp->f_op->fasync)
|
|
/* fasync() adjusts filp->f_flags */
|
|
error = filp->f_op->fasync(fd, filp, on);
|
|
else
|
|
error = -ENOTTY;
|
|
}
|
|
return error < 0 ? error : 0;
|
|
}
|
|
|
|
static int ioctl_fsfreeze(struct file *filp)
|
|
{
|
|
struct super_block *sb = file_inode(filp)->i_sb;
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
return -EPERM;
|
|
|
|
/* If filesystem doesn't support freeze feature, return. */
|
|
if (sb->s_op->freeze_fs == NULL && sb->s_op->freeze_super == NULL)
|
|
return -EOPNOTSUPP;
|
|
|
|
/* Freeze */
|
|
if (sb->s_op->freeze_super)
|
|
return sb->s_op->freeze_super(sb);
|
|
return freeze_super(sb);
|
|
}
|
|
|
|
static int ioctl_fsthaw(struct file *filp)
|
|
{
|
|
struct super_block *sb = file_inode(filp)->i_sb;
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
return -EPERM;
|
|
|
|
/* Thaw */
|
|
if (sb->s_op->thaw_super)
|
|
return sb->s_op->thaw_super(sb);
|
|
return thaw_super(sb);
|
|
}
|
|
|
|
static int ioctl_file_dedupe_range(struct file *file, void __user *arg)
|
|
{
|
|
struct file_dedupe_range __user *argp = arg;
|
|
struct file_dedupe_range *same = NULL;
|
|
int ret;
|
|
unsigned long size;
|
|
u16 count;
|
|
|
|
if (get_user(count, &argp->dest_count)) {
|
|
ret = -EFAULT;
|
|
goto out;
|
|
}
|
|
|
|
size = offsetof(struct file_dedupe_range __user, info[count]);
|
|
if (size > PAGE_SIZE) {
|
|
ret = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
same = memdup_user(argp, size);
|
|
if (IS_ERR(same)) {
|
|
ret = PTR_ERR(same);
|
|
same = NULL;
|
|
goto out;
|
|
}
|
|
|
|
same->dest_count = count;
|
|
ret = vfs_dedupe_file_range(file, same);
|
|
if (ret)
|
|
goto out;
|
|
|
|
ret = copy_to_user(argp, same, size);
|
|
if (ret)
|
|
ret = -EFAULT;
|
|
|
|
out:
|
|
kfree(same);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* When you add any new common ioctls to the switches above and below
|
|
* please update compat_sys_ioctl() too.
|
|
*
|
|
* do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d.
|
|
* It's just a simple helper for sys_ioctl and compat_sys_ioctl.
|
|
*/
|
|
int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
|
|
unsigned long arg)
|
|
{
|
|
int error = 0;
|
|
int __user *argp = (int __user *)arg;
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
switch (cmd) {
|
|
case FIOCLEX:
|
|
set_close_on_exec(fd, 1);
|
|
break;
|
|
|
|
case FIONCLEX:
|
|
set_close_on_exec(fd, 0);
|
|
break;
|
|
|
|
case FIONBIO:
|
|
error = ioctl_fionbio(filp, argp);
|
|
break;
|
|
|
|
case FIOASYNC:
|
|
error = ioctl_fioasync(fd, filp, argp);
|
|
break;
|
|
|
|
case FIOQSIZE:
|
|
if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode) ||
|
|
S_ISLNK(inode->i_mode)) {
|
|
loff_t res = inode_get_bytes(inode);
|
|
error = copy_to_user(argp, &res, sizeof(res)) ?
|
|
-EFAULT : 0;
|
|
} else
|
|
error = -ENOTTY;
|
|
break;
|
|
|
|
case FIFREEZE:
|
|
error = ioctl_fsfreeze(filp);
|
|
break;
|
|
|
|
case FITHAW:
|
|
error = ioctl_fsthaw(filp);
|
|
break;
|
|
|
|
case FS_IOC_FIEMAP:
|
|
return ioctl_fiemap(filp, arg);
|
|
|
|
case FIGETBSZ:
|
|
return put_user(inode->i_sb->s_blocksize, argp);
|
|
|
|
case FICLONE:
|
|
return ioctl_file_clone(filp, arg, 0, 0, 0);
|
|
|
|
case FICLONERANGE:
|
|
return ioctl_file_clone_range(filp, argp);
|
|
|
|
case FIDEDUPERANGE:
|
|
return ioctl_file_dedupe_range(filp, argp);
|
|
|
|
default:
|
|
if (S_ISREG(inode->i_mode))
|
|
error = file_ioctl(filp, cmd, arg);
|
|
else
|
|
error = vfs_ioctl(filp, cmd, arg);
|
|
break;
|
|
}
|
|
return error;
|
|
}
|
|
|
|
SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
|
|
{
|
|
int error;
|
|
struct fd f = fdget(fd);
|
|
|
|
if (!f.file)
|
|
return -EBADF;
|
|
error = security_file_ioctl(f.file, cmd, arg);
|
|
if (!error)
|
|
error = do_vfs_ioctl(f.file, fd, cmd, arg);
|
|
fdput(f);
|
|
return error;
|
|
}
|