Re: [f2fs-dev] [PATCH v4] f2fs: support dynamic reserve/release for device aliasing

Daeho Jeong <[email protected]> Tue, 21 Jul 2026 10:53:26 -0700
Newsgroups net.sourceforge.lists.linux-f2fs-devel,org.kernel.vger.linux-kernel
Message-ID <CACOAw_ydhbDQLUmkpB5-1P9_z5uEn1TZHcHuNmz0SKBfLFyR2g@mail.gmail.com>
On Sun, Jul 19, 2026 at 1:54 AM Chao Yu <[email protected]> wrote:
>
> On 7/14/26 00:05, Daeho Jeong wrote:
> > From: Daeho Jeong <[email protected]>
> >
> > This patch adds a dynamic management feature to the existing device
> > aliasing functionality. It allows users to dynamically reserve or
> > release specific devices from the filesystem's free pool at runtime
> > through new ioctls.
> >
> > To support this, three new ioctls are introduced:
> > - F2FS_IOC_RESERVE_DEV_ALIAS: This reclaims the space occupied by a
> >    device aliasing file. It first performs a capacity check, resets GC
> >    victim information for the target range, marks the segments as in-use
> >    to prevent new allocations, and then triggers GC to migrate existing
> >    valid data out of the range. Finally, it reserves these blocks in the
> >    SIT to effectively exclude the device from the usable capacity.
> >
> > - F2FS_IOC_RELEASE_DEV_ALIAS: This releases the reserved space of a
> >    previously reserved device aliasing file. It truncates the blocks
> >    associated with the file, which makes them available for general
> >    filesystem allocation again.
> >
> > - F2FS_IOC_GET_DEV_ALIAS_STATUS: This retrieves the current aliasing
> >    status of a device aliasing file, returning whether the file is
> >    released (inactive alias) or reserved (active alias, with blocks
> >    fully allocated on the device).
> >
> > Signed-off-by: Daeho Jeong <[email protected]>
> > ---
> > v4: renamed interfaces.
> >      fixed race conditions between checkpoint=disable mount and ioctls.
> >      refactored segment reservation part.
> >      modified lock usage.
> > v3: add CAP_SYS_ADMIN and checkpoint=disabled check.
> >      remove a f2fs specific flag exposed with getflags.
> > v2: prevent operations during checkpoint=disabled.
> > ---
> >   Documentation/filesystems/f2fs.rst |  35 ++++
> >   fs/f2fs/f2fs.h                     |   9 +-
> >   fs/f2fs/file.c                     | 289 ++++++++++++++++++++++++++++-
> >   fs/f2fs/gc.c                       |  30 +--
> >   fs/f2fs/namei.c                    |  14 ++
> >   fs/f2fs/segment.c                  | 180 +++++++++++++-----
> >   fs/f2fs/segment.h                  |  26 +++
> >   fs/f2fs/super.c                    |  34 ++++
> >   include/uapi/linux/f2fs.h          |   7 +
> >   9 files changed, 562 insertions(+), 62 deletions(-)
> >
> > diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst
> > index 8c4a14ae444f..1a5fd4afe609 100644
> > --- a/Documentation/filesystems/f2fs.rst
> > +++ b/Documentation/filesystems/f2fs.rst
> > @@ -1045,6 +1045,41 @@ So, the key idea is, user can do any file operations on /dev/vdc, and
> >   reclaim the space after the use, while the space is counted as /data.
> >   That doesn't require modifying partition size and filesystem format.
> >
> > +Dynamic Device Aliasing Management
> > +----------------------------------
> > +
> > +In addition to static device aliasing by deleting the aliasing file, F2FS
> > +supports dynamic management of device aliasing. This mechanism allows the system
> > +to dynamically transition partition ownership between F2FS userdata and external
> > +entities (e.g., zRAM, raw partition) based on system requirements without
> > +deleting the master aliasing file or requiring unmount/remount.
> > +
> > +The master aliasing file is created during the initial format of the file system
> > +and remains as a persistent control entity (ioctl gateway) in the root directory.
> > +
> > +- Partition Reservation (In-service to Aliased)
> > +  When a specific partition needs to be dedicated to external services (e.g., zRAM),
> > +  a user can reserve the device alias range via ioctl. The kernel resets GC victim
> > +  information for the target range, marks segments as in-use to prevent new
> > +  allocations, and triggers forced GC to migrate existing valid data out of the
> > +  range. Finally, it reserves these blocks in the SIT to effectively exclude the
> > +  device from the usable capacity.
> > +
> > +- Partition Release (Aliased to In-service)
> > +  When external usage concludes, the space is reclaimed not by deleting the file,
> > +  but through the release ioctl. The kernel truncates blocks associated with
> > +  the file, releasing them back to general filesystem allocation.
> > +
> > +.. code-block::
> > +
> > +   # f2fs_io dev_alias release /mnt/f2fs/vdc.file
> > +   # df -h
> > +   /dev/vdb                            64G  753M   64G   2% /mnt/f2fs
> > +
> > +   # f2fs_io dev_alias reserve /mnt/f2fs/vdc.file
> > +   # df -h
> > +   /dev/vdb                            64G   33G   32G  52% /mnt/f2fs
> > +
> >   Per-file Read-Only Large Folio Support
> >   --------------------------------------
> >
> > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> > index f1774d4e18d2..0f9b8b66cef9 100644
> > --- a/fs/f2fs/f2fs.h
> > +++ b/fs/f2fs/f2fs.h
> > @@ -1404,6 +1404,8 @@ struct f2fs_dev_info {
> >       unsigned int total_segments;
> >       block_t start_blk;
> >       block_t end_blk;
> > +     bool has_alias;
> > +     bool is_reserving;
> >   #ifdef CONFIG_BLK_DEV_ZONED
> >       unsigned int nr_blkz;           /* Total number of zones */
> >       unsigned long *blkz_seq;        /* Bitmap indicating sequential zones */
> > @@ -4009,7 +4011,10 @@ int f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi);
> >   int f2fs_flush_device_cache(struct f2fs_sb_info *sbi);
> >   void f2fs_destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free);
> >   void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr,
> > -                                             unsigned int len);
> > +                             unsigned int len);
> > +void f2fs_reserve_device_alias(struct f2fs_sb_info *sbi, block_t addr,
> > +                             unsigned int len);
> > +
> >   bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr);
> >   int f2fs_start_discard_thread(struct f2fs_sb_info *sbi);
> >   void f2fs_drop_discard_cmd(struct f2fs_sb_info *sbi);
> > @@ -4231,6 +4236,8 @@ void f2fs_build_gc_manager(struct f2fs_sb_info *sbi);
> >   int f2fs_gc_range(struct f2fs_sb_info *sbi,
> >               unsigned int start_seg, unsigned int end_seg,
> >               bool dry_run, unsigned int dry_run_sections);
> > +void f2fs_reset_gc_victim_resource(struct f2fs_sb_info *sbi,
> > +             unsigned int start, unsigned int end);
> >   int f2fs_resize_fs(struct file *filp, __u64 block_count);
> >   int __init f2fs_create_garbage_collection_cache(void);
> >   void f2fs_destroy_garbage_collection_cache(void);
> > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> > index 4b52c56d71f0..9077c091c2d6 100644
> > --- a/fs/f2fs/file.c
> > +++ b/fs/f2fs/file.c
> > @@ -813,13 +813,19 @@ int f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock)
> >
> >       if (IS_DEVICE_ALIASING(inode)) {
> >               struct extent_tree *et = F2FS_I(inode)->extent_tree[EX_READ];
> > -             struct extent_info ei = et->largest;
> > +             struct extent_info ei;
> > +
> > +             read_lock(&et->lock);
> > +             ei = et->largest;
> > +             read_unlock(&et->lock);
> >
> >               f2fs_invalidate_blocks(sbi, ei.blk, ei.len);
> >
> >               dec_valid_block_count(sbi, inode, ei.len);
> >               f2fs_update_time(sbi, REQ_TIME);
> >
> > +             f2fs_drop_extent_tree(inode);
> > +
> >               f2fs_folio_put(ifolio, true);
> >               goto out;
> >       }
> > @@ -1100,8 +1106,9 @@ int f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> >       if ((attr->ia_valid & ATTR_SIZE)) {
> >               if (mapping_large_folio_support(inode->i_mapping))
> >                       return -EOPNOTSUPP;
> > -             if (!f2fs_is_compress_backend_ready(inode) ||
> > -                             IS_DEVICE_ALIASING(inode))
> > +             if (IS_DEVICE_ALIASING(inode))
> > +                     return -EPERM;
> > +             if (!f2fs_is_compress_backend_ready(inode))
> >                       return -EOPNOTSUPP;
> >               if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED) &&
> >                       !IS_ALIGNED(attr->ia_size,
> > @@ -2130,6 +2137,9 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
> >       if (IS_NOQUOTA(inode))
> >               return -EPERM;
> >
> > +     if (IS_DEVICE_ALIASING(inode))
> > +             return -EPERM;
> > +
> >       if ((iflags ^ masked_flags) & F2FS_CASEFOLD_FL) {
> >               if (!f2fs_sb_has_casefold(F2FS_I_SB(inode)))
> >                       return -EOPNOTSUPP;
> > @@ -2678,6 +2688,17 @@ static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg)
> >       return fscrypt_ioctl_get_policy(filp, (void __user *)arg);
> >   }
> >
> > +static int f2fs_ioc_get_dev_alias_status(struct file *filp, unsigned long arg)
> > +{
> > +     struct inode *inode = file_inode(filp);
> > +
> > +     if (!IS_DEVICE_ALIASING(inode))
> > +             return -EINVAL;
> > +
> > +     return put_user(F2FS_HAS_BLOCKS(inode) ? F2FS_DEV_ALIAS_STATUS_RESERVED :
> > +                             F2FS_DEV_ALIAS_STATUS_RELEASED, (u32 __user *)arg);
> > +}
> > +
> >   static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg)
> >   {
> >       struct inode *inode = file_inode(filp);
> > @@ -3616,6 +3637,259 @@ static int f2fs_ioc_get_dev_alias_file(struct file *filp, unsigned long arg)
> >                       (u32 __user *)arg);
> >   }
> >
> > +static int f2fs_ioc_reserve_dev_alias(struct file *filp)
> > +{
> > +     struct inode *inode = file_inode(filp);
> > +     struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
> > +     struct extent_tree *et = F2FS_I(inode)->extent_tree[EX_READ];
> > +     struct extent_info ei;
> > +     struct cp_control cpc = { CP_SYNC, 0, 0, 0 };
> > +     struct f2fs_lock_context lc, glc;
> > +     blkcnt_t count;
> > +     unsigned int start, end, segno;
> > +     int type, i, err;
> > +
> > +     if (!capable(CAP_SYS_ADMIN))
> > +             return -EPERM;
> > +
> > +     if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
> > +             return -EINVAL;
> > +
> > +     err = mnt_want_write_file(filp);
> > +     if (err)
> > +             return err;
> > +
> > +     inode_lock(inode);
> > +
> > +     if (!IS_DEVICE_ALIASING(inode)) {
> > +             err = -EINVAL;
> > +             goto out_inode_unlock;
> > +     }
> > +
> > +     if (F2FS_HAS_BLOCKS(inode)) {
> > +             err = 0;
> > +             goto out_inode_unlock;
> > +     }
> > +
> > +     for (i = 1; i < sbi->s_ndevs; i++) {
> > +             char *name = strrchr(FDEV(i).path, '/');
> > +
> > +             name = name ? name + 1 : FDEV(i).path;
> > +             if (!strcmp(name, filp->f_path.dentry->d_name.name)) {
> > +                     ei.blk = FDEV(i).start_blk;
> > +                     ei.len = FDEV(i).total_segments << sbi->log_blocks_per_seg;
> > +                     ei.fofs = 0;
> > +                     break;
> > +             }
> > +     }
> > +
> > +     if (i == sbi->s_ndevs) {
> > +             f2fs_warn(sbi, "device alias file (%s, ino=%llu) has no matching device",
> > +                       filp->f_path.dentry->d_name.name, inode->i_ino);
> > +             set_sbi_flag(sbi, SBI_NEED_FSCK);
> > +             f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE);
> > +             err = -EFSCORRUPTED;
> > +             goto out_inode_unlock;
> > +     }
> > +
> > +     f2fs_down_write_trace(&sbi->gc_lock, &glc);
> > +     f2fs_lock_op(sbi, &lc);
> > +
> > +     if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
> > +             err = -EINVAL;
> > +     } else {
> > +             count = ei.len;
> > +             err = inc_valid_block_count(sbi, inode, &count, false);
> > +     }
> > +     if (err) {
> > +             f2fs_unlock_op(sbi, &lc);
> > +             f2fs_up_write_trace(&sbi->gc_lock, &glc);
> > +             goto out_inode_unlock;
> > +     }
> > +
> > +     spin_lock(&FREE_I(sbi)->segmap_lock);
> > +     FDEV(f2fs_target_device_index(sbi, ei.blk)).is_reserving = true;
> > +     spin_unlock(&FREE_I(sbi)->segmap_lock);
> > +
> > +     start = GET_SEGNO(sbi, ei.blk);
> > +     end = GET_SEGNO(sbi, ei.blk + ei.len - 1);
> > +
> > +     /* Reset the victim information to prevent GC from targeting the range */
> > +     f2fs_reset_gc_victim_resource(sbi, start, end);
> > +
> > +     /* Move out cursegs from the target range */
> > +     for (type = CURSEG_HOT_DATA; type < NR_CURSEG_PERSIST_TYPE; type++) {
> > +             err = f2fs_allocate_segment_for_resize(sbi, type, start, end);
> > +             if (err) {
> > +                     f2fs_unlock_op(sbi, &lc);
> > +                     goto out_gc_unlock;
> > +             }
> > +     }
> > +
> > +     f2fs_unlock_op(sbi, &lc);
> > +     f2fs_up_write_trace(&sbi->gc_lock, &glc);
> > +
> > +     /* Write checkpoint synchronously to flush all pending writes and free space */
> > +     err = f2fs_write_checkpoint(sbi, &cpc);
> > +     if (err) {
> > +             f2fs_down_write_trace(&sbi->gc_lock, &glc);
> > +             goto out_gc_unlock;
> > +     }
> > +
> > +     /* Re-acquire gc_lock and cp_rwsem read lock for the entire range GC */
> > +     f2fs_down_write_trace(&sbi->gc_lock, &glc);
> > +     f2fs_lock_op(sbi, &lc);
> > +
> > +     if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
> > +             err = -EINVAL;
> > +             f2fs_unlock_op(sbi, &lc);
> > +             goto out_gc_unlock;
> > +     }
> > +
> > +     /* do GC to move out valid blocks in the range all at once! */
> > +     err = f2fs_gc_range(sbi, start, end, false, 0);
> > +     if (err) {
> > +             f2fs_unlock_op(sbi, &lc);
> > +             goto out_gc_unlock;
> > +     }
> > +
> > +     if (et) {
> > +             write_lock(&et->lock);
> > +             et->largest = ei;
> > +             write_unlock(&et->lock);
> > +     }
> > +     clear_inode_flag(inode, FI_NO_EXTENT);
> > +
> > +     f2fs_reserve_device_alias(sbi, ei.blk, ei.len);
> > +
> > +     i_size_write(inode, (loff_t)ei.len << PAGE_SHIFT);
> > +     f2fs_update_inode_page(inode);
> > +
> > +     spin_lock(&FREE_I(sbi)->segmap_lock);
> > +     FDEV(f2fs_target_device_index(sbi, ei.blk)).is_reserving = false;
> > +     spin_unlock(&FREE_I(sbi)->segmap_lock);
> > +
> > +     f2fs_unlock_op(sbi, &lc);
> > +     f2fs_up_write_trace(&sbi->gc_lock, &glc);
> > +
> > +     inode_unlock(inode);
> > +     mnt_drop_write_file(filp);
> > +
> > +     err = f2fs_write_checkpoint(sbi, &cpc);
> > +     return err;
> > +
> > +out_gc_unlock:
> > +     spin_lock(&FREE_I(sbi)->segmap_lock);
> > +     FDEV(f2fs_target_device_index(sbi, ei.blk)).is_reserving = false;
> > +     spin_unlock(&FREE_I(sbi)->segmap_lock);
> > +     f2fs_up_write_trace(&sbi->gc_lock, &glc);
>
> Seems, once we have reserved blocks above, and then unlock cp_rwsem and
> gc_lock, a following CP and sudden power-cut recovery will make device alias
> file corrupted?


Could you please elaborate on the specific scenario or race condition
you are concerned about?

In the current implementation:
 - Both the SIT entry updates (f2fs_reserve_device_alias) and the
inode page updates (f2fs_update_inode_page) are performed under
cp_rwsem (f2fs_lock_op).
 - Once cp_rwsem is unlocked, both dirty SIT entries and the dirty
inode page will be committed together atomically by any following
Checkpoint.
 - If a sudden power-cut happens before the final Checkpoint
completes, the filesystem safely recovers to the prior Checkpoint
(where the alias file remains in the released/unreserved state with
i_size = 0). If it happens after, it recovers to the new Checkpoint
(where the alias file is fully reserved).

Is there a specific edge case or inconsistency during recovery that I
might have missed?

>
>
> Maybe we can reserve blocks for device alias file w/ in-memory variable, something
> like reserve_root?
>
> > +
> > +     /*
> > +      * Put successfully GC'ed segments back into PRE list so checkpoint
> > +      * commits and frees them!
> > +      */
>
> I didn't get it, why do we need to set empty segment as prefree one? You mean
> f2fs_reserve_device_alias() has removed all prefreed segments? seems after
> f2fs_reserve_device_alias() there is no error path.

You are completely right.
f2fs_reserve_device_alias() is only called on the success path, so
prefreed segments are never removed from the PRE list on the error
path (out_gc_unlock).
Furthermore, f2fs_gc_range() already handles tracking invalidated
segments in the PRE list automatically through standard block
invalidation.
Therefore, this manual loop adding segments back to dirty_segmap[PRE]
in out_gc_unlock is redundant. I will remove this logic in the next
version.

Thank you for catching this!

>
> > +     f2fs_lock_op(sbi, &lc);
> > +     for (segno = start; segno <= end; segno++) {
> > +             if (get_valid_blocks(sbi, segno, false) == 0) {
> > +                     mutex_lock(&DIRTY_I(sbi)->seglist_lock);
> > +                     if (!test_and_set_bit(segno, DIRTY_I(sbi)->dirty_segmap[PRE]))
> > +                             DIRTY_I(sbi)->nr_dirty[PRE]++;
> > +                     mutex_unlock(&DIRTY_I(sbi)->seglist_lock);
> > +             }
> > +     }
> > +     count = ei.len;
> > +     dec_valid_block_count(sbi, inode, count);
> > +     f2fs_unlock_op(sbi, &lc);
> > +
> > +     inode_unlock(inode);
> > +     mnt_drop_write_file(filp);
> > +
> > +     f2fs_write_checkpoint(sbi, &cpc);
> > +     return err;
> > +
> > +out_inode_unlock:
> > +     inode_unlock(inode);
> > +     mnt_drop_write_file(filp);
> > +     return err;
> > +}
> > +
> > +static int f2fs_ioc_release_dev_alias(struct file *filp)
> > +{
> > +     struct inode *inode = file_inode(filp);
> > +     struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
> > +     struct extent_tree *et = F2FS_I(inode)->extent_tree[EX_READ];
> > +     struct extent_info ei = {0, };
> > +     struct cp_control cpc = { CP_SYNC, 0, 0, 0 };
> > +     struct f2fs_lock_context lc, glc;
> > +     int err;
> > +
> > +     if (!capable(CAP_SYS_ADMIN))
> > +             return -EPERM;
> > +
> > +     if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
> > +             return -EINVAL;
> > +
> > +     err = mnt_want_write_file(filp);
> > +     if (err)
> > +             return err;
> > +
> > +     inode_lock(inode);
> > +
> > +     if (!IS_DEVICE_ALIASING(inode)) {
> > +             err = -EINVAL;
> > +             goto out_inode_unlock;
> > +     }
> > +
> > +     if (!F2FS_HAS_BLOCKS(inode)) {
> > +             err = 0;
> > +             goto out_inode_unlock;
> > +     }
> > +
> > +     err = filemap_write_and_wait(inode->i_mapping);
> > +     if (err)
> > +             goto out_inode_unlock;
> > +
> > +     read_lock(&et->lock);
> > +     ei = et->largest;
> > +     read_unlock(&et->lock);
> > +
> > +     f2fs_down_write_trace(&sbi->gc_lock, &glc);
> > +     f2fs_lock_op(sbi, &lc);
> > +
> > +     if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
> > +             err = -EINVAL;
> > +             f2fs_unlock_op(sbi, &lc);
> > +             f2fs_up_write_trace(&sbi->gc_lock, &glc);
> > +             goto out_inode_unlock;
> > +     }
> > +
> > +     truncate_setsize(inode, 0);
> > +
> > +     err = f2fs_truncate_blocks(inode, 0, false);
> > +     if (err) {
> > +             i_size_write(inode, (loff_t)ei.len << PAGE_SHIFT);
>
> If f2fs_truncate_blocks() partially truncated blocks of device alias file,
> it will be corrupted, since a pinned file may has partial valid blocks in
> section?
>
> Can fsck detect such status of device alias for repair?
>

That's a great question, but for device alias files, block truncation
is strictly an all-or-nothing operation.

As implemented in f2fs_truncate_blocks() (file.c:814):

For IS_DEVICE_ALIASING(inode), we do not iterate over dnodes or
truncate blocks partially. Instead, all ei.len blocks are invalidated
at once in a single call via f2fs_invalidate_blocks(sbi, ei.blk,
ei.len).
The only error paths in f2fs_truncate_blocks() occur before
f2fs_invalidate_blocks() is called, when zero blocks have been
invalidated.
Once f2fs_invalidate_blocks() is reached, all blocks are invalidated
together and the function succeeds.

Therefore, partial block truncation never happens for device alias files:

If f2fs_truncate_blocks() fails, 0 blocks have been freed, so
restoring i_size safely preserves the fully-reserved file without any
holes.
If it succeeds, 100% of the blocks are freed.

> Thanks,
>
> > +             f2fs_unlock_op(sbi, &lc);
> > +             f2fs_up_write_trace(&sbi->gc_lock, &glc);
> > +             goto out_inode_unlock;
> > +     }
> > +
> > +     f2fs_update_inode_page(inode);
> > +
> > +     f2fs_unlock_op(sbi, &lc);
> > +     f2fs_up_write_trace(&sbi->gc_lock, &glc);
> > +
> > +     inode_unlock(inode);
> > +     mnt_drop_write_file(filp);
> > +
> > +     err = f2fs_write_checkpoint(sbi, &cpc);
> > +     return err;
> > +
> > +out_inode_unlock:
> > +     inode_unlock(inode);
> > +     mnt_drop_write_file(filp);
> > +     return err;
> > +}
> > +
> >   static int f2fs_ioc_io_prio(struct file *filp, unsigned long arg)
> >   {
> >       struct inode *inode = file_inode(filp);
> > @@ -4742,8 +5016,14 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> >               return f2fs_ioc_compress_file(filp);
> >       case F2FS_IOC_GET_DEV_ALIAS_FILE:
> >               return f2fs_ioc_get_dev_alias_file(filp, arg);
> > +     case F2FS_IOC_GET_DEV_ALIAS_STATUS:
> > +             return f2fs_ioc_get_dev_alias_status(filp, arg);
> >       case F2FS_IOC_IO_PRIO:
> >               return f2fs_ioc_io_prio(filp, arg);
> > +     case F2FS_IOC_RESERVE_DEV_ALIAS:
> > +             return f2fs_ioc_reserve_dev_alias(filp);
> > +     case F2FS_IOC_RELEASE_DEV_ALIAS:
> > +             return f2fs_ioc_release_dev_alias(filp);
> >       default:
> >               return -ENOTTY;
> >       }
> > @@ -5530,7 +5810,10 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> >       case F2FS_IOC_DECOMPRESS_FILE:
> >       case F2FS_IOC_COMPRESS_FILE:
> >       case F2FS_IOC_GET_DEV_ALIAS_FILE:
> > +     case F2FS_IOC_GET_DEV_ALIAS_STATUS:
> >       case F2FS_IOC_IO_PRIO:
> > +     case F2FS_IOC_RESERVE_DEV_ALIAS:
> > +     case F2FS_IOC_RELEASE_DEV_ALIAS:
> >               break;
> >       default:
> >               return -ENOIOCTLCMD;
> > diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
> > index ffaa7ba76a1b..93bcb35a5b5d 100644
> > --- a/fs/f2fs/gc.c
> > +++ b/fs/f2fs/gc.c
> > @@ -2197,29 +2197,37 @@ int f2fs_gc_range(struct f2fs_sb_info *sbi,
> >       return 0;
> >   }
> >
> > +void f2fs_reset_gc_victim_resource(struct f2fs_sb_info *sbi,
> > +                     unsigned int start, unsigned int end)
> > +{
> > +     int i;
> > +
> > +     mutex_lock(&DIRTY_I(sbi)->seglist_lock);
> > +     for (i = 0; i < MAX_GC_POLICY; i++)
> > +             if (SIT_I(sbi)->last_victim[i] >= start &&
> > +                     SIT_I(sbi)->last_victim[i] <= end)
> > +                     SIT_I(sbi)->last_victim[i] = 0;
> > +
> > +     for (i = BG_GC; i <= FG_GC; i++)
> > +             if (sbi->next_victim_seg[i] >= start &&
> > +                     sbi->next_victim_seg[i] <= end)
> > +                     sbi->next_victim_seg[i] = NULL_SEGNO;
> > +     mutex_unlock(&DIRTY_I(sbi)->seglist_lock);
> > +}
> > +
> >   static int free_segment_range(struct f2fs_sb_info *sbi,
> >                               unsigned int secs, bool dry_run)
> >   {
> >       unsigned int next_inuse, start, end;
> >       struct cp_control cpc = { CP_RESIZE, 0, 0, 0 };
> > -     int gc_mode, gc_type;
> >       int err = 0;
> >       int type;
> >
> > -     /* Force block allocation for GC */
> >       MAIN_SECS(sbi) -= secs;
> >       start = MAIN_SECS(sbi) * SEGS_PER_SEC(sbi);
> >       end = MAIN_SEGS(sbi) - 1;
> >
> > -     mutex_lock(&DIRTY_I(sbi)->seglist_lock);
> > -     for (gc_mode = 0; gc_mode < MAX_GC_POLICY; gc_mode++)
> > -             if (SIT_I(sbi)->last_victim[gc_mode] >= start)
> > -                     SIT_I(sbi)->last_victim[gc_mode] = 0;
> > -
> > -     for (gc_type = BG_GC; gc_type <= FG_GC; gc_type++)
> > -             if (sbi->next_victim_seg[gc_type] >= start)
> > -                     sbi->next_victim_seg[gc_type] = NULL_SEGNO;
> > -     mutex_unlock(&DIRTY_I(sbi)->seglist_lock);
> > +     f2fs_reset_gc_victim_resource(sbi, start, end);
> >
> >       /* Move out cursegs from the target range */
> >       for (type = CURSEG_HOT_DATA; type < NR_CURSEG_PERSIST_TYPE; type++) {
> > diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
> > index cac03b8e91a1..8c3b57987f6c 100644
> > --- a/fs/f2fs/namei.c
> > +++ b/fs/f2fs/namei.c
> > @@ -425,6 +425,9 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
> >       if (!f2fs_is_checkpoint_ready(sbi))
> >               return -ENOSPC;
> >
> > +     if (IS_DEVICE_ALIASING(inode))
> > +             return -EPERM;
> > +
> >       err = fscrypt_prepare_link(old_dentry, dir, dentry);
> >       if (err)
> >               return err;
> > @@ -568,6 +571,9 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
> >
> >       trace_f2fs_unlink_enter(dir, dentry);
> >
> > +     if (IS_DEVICE_ALIASING(inode))
> > +             return -EPERM;
> > +
> >       if (unlikely(f2fs_cp_error(sbi))) {
> >               err = -EIO;
> >               goto out;
> > @@ -946,6 +952,9 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
> >       bool old_is_dir = S_ISDIR(old_inode->i_mode);
> >       int err;
> >
> > +     if (IS_DEVICE_ALIASING(old_inode))
> > +             return -EPERM;
> > +
> >       if (unlikely(f2fs_cp_error(sbi)))
> >               return -EIO;
> >       if (!f2fs_is_checkpoint_ready(sbi))
> > @@ -1016,6 +1025,8 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
> >       }
> >
> >       if (new_inode) {
> > +             if (IS_DEVICE_ALIASING(new_inode))
> > +                     return -EPERM;
> >
> >               err = -ENOTEMPTY;
> >               if (old_is_dir && !f2fs_empty_dir(new_inode))
> > @@ -1143,6 +1154,9 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
> >       int old_nlink = 0, new_nlink = 0;
> >       int err;
> >
> > +     if (IS_DEVICE_ALIASING(old_inode) || IS_DEVICE_ALIASING(new_inode))
> > +             return -EPERM;
> > +
> >       if (unlikely(f2fs_cp_error(sbi)))
> >               return -EIO;
> >       if (!f2fs_is_checkpoint_ready(sbi))
> > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
> > index d71ddb3ee918..1a986f1884f2 100644
> > --- a/fs/f2fs/segment.c
> > +++ b/fs/f2fs/segment.c
> > @@ -2502,35 +2502,42 @@ static int update_sit_entry_for_alloc(struct f2fs_sb_info *sbi, struct seg_entry
> >                               unsigned int segno, block_t blkaddr, unsigned int offset, int del)
> >   {
> >       bool exist;
> > +     int del_count = del;
> > +     int i;
> >
> > -     exist = f2fs_test_and_set_bit(offset, se->cur_valid_map);
> > -     if (unlikely(exist)) {
> > -             f2fs_err(sbi, "Bitmap was wrongly set, blk:%u", blkaddr);
> > -             f2fs_bug_on(sbi, 1);
> > -             se->valid_blocks--;
> > -             del = 0;
> > -     }
> > +     f2fs_bug_on(sbi, GET_SEGNO(sbi, blkaddr) != GET_SEGNO(sbi, blkaddr + del_count - 1));
> >
> > -     if (f2fs_block_unit_discard(sbi) &&
> > -                     !f2fs_test_and_set_bit(offset, se->discard_map))
> > -             sbi->discard_blks--;
> > +     for (i = 0; i < del_count; i++) {
> > +             exist = f2fs_test_and_set_bit(offset + i, se->cur_valid_map);
> > +             if (unlikely(exist)) {
> > +                     f2fs_err(sbi, "Bitmap was wrongly set, blk:%u", blkaddr + i);
> > +                     f2fs_bug_on(sbi, 1);
> > +                     se->valid_blocks--;
> > +                     del -= 1;
> > +                     continue;
> > +             }
> >
> > -     /*
> > -      * SSR should never reuse block which is checkpointed
> > -      * or newly invalidated.
> > -      */
> > -     if (!is_sbi_flag_set(sbi, SBI_CP_DISABLED)) {
> > -             if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map)) {
> > -                     se->ckpt_valid_blocks++;
> > -                     if (__is_large_section(sbi))
> > -                             get_sec_entry(sbi, segno)->ckpt_valid_blocks++;
> > +             if (f2fs_block_unit_discard(sbi) &&
> > +                             !f2fs_test_and_set_bit(offset + i, se->discard_map))
> > +                     sbi->discard_blks--;
> > +
> > +             /*
> > +              * SSR should never reuse block which is checkpointed
> > +              * or newly invalidated.
> > +              */
> > +             if (!is_sbi_flag_set(sbi, SBI_CP_DISABLED)) {
> > +                     if (!f2fs_test_and_set_bit(offset + i, se->ckpt_valid_map)) {
> > +                             se->ckpt_valid_blocks++;
> > +                             if (__is_large_section(sbi))
> > +                                     get_sec_entry(sbi, segno)->ckpt_valid_blocks++;
> > +                     }
> >               }
> > -     }
> >
> > -     if (!f2fs_test_bit(offset, se->ckpt_valid_map)) {
> > -             se->ckpt_valid_blocks += del;
> > -             if (__is_large_section(sbi))
> > -                     get_sec_entry(sbi, segno)->ckpt_valid_blocks += del;
> > +             if (!f2fs_test_bit(offset + i, se->ckpt_valid_map)) {
> > +                     se->ckpt_valid_blocks += 1;
> > +                     if (__is_large_section(sbi))
> > +                             get_sec_entry(sbi, segno)->ckpt_valid_blocks += 1;
> > +             }
> >       }
> >
> >       if (__is_large_section(sbi))
> > @@ -2585,9 +2592,14 @@ void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr,
> >       unsigned int segno = GET_SEGNO(sbi, addr);
> >       struct sit_info *sit_i = SIT_I(sbi);
> >       block_t addr_start = addr, addr_end = addr + len - 1;
> > -     unsigned int seg_num = GET_SEGNO(sbi, addr_end) - segno + 1;
> > +     unsigned int seg_num;
> >       unsigned int i = 1, max_blocks = sbi->blocks_per_seg, cnt;
> >
> > +     if (len == 0)
> > +             return;
> > +
> > +     seg_num = GET_SEGNO(sbi, addr_end) - segno + 1;
> > +
> >       f2fs_bug_on(sbi, addr == NULL_ADDR);
> >       if (addr == NEW_ADDR || addr == COMPRESS_ADDR)
> >               return;
> > @@ -2620,6 +2632,52 @@ void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr,
> >       up_write(&sit_i->sentry_lock);
> >   }
> >
> > +void f2fs_reserve_device_alias(struct f2fs_sb_info *sbi, block_t addr,
> > +                             unsigned int len)
> > +{
> > +     unsigned int segno = GET_SEGNO(sbi, addr);
> > +     struct sit_info *sit_i = SIT_I(sbi);
> > +     block_t addr_start = addr, addr_end = addr + len - 1;
> > +     unsigned int seg_num;
> > +     unsigned int i = 1, max_blocks = sbi->blocks_per_seg, cnt;
> > +
> > +     if (len == 0)
> > +             return;
> > +
> > +     seg_num = GET_SEGNO(sbi, addr_end) - segno + 1;
> > +
> > +     down_write(&sit_i->sentry_lock);
> > +
> > +     if (seg_num == 1)
> > +             cnt = len;
> > +     else
> > +             cnt = max_blocks - GET_BLKOFF_FROM_SEG0(sbi, addr);
> > +
> > +     do {
> > +             update_segment_mtime(sbi, addr_start, 0);
> > +             update_sit_entry(sbi, addr_start, cnt);
> > +             __set_test_and_inuse(sbi, segno);
> > +
> > +             /* Remove the segment from PRE (prefree) to prevent checkpoint from freeing it! */
> > +             mutex_lock(&DIRTY_I(sbi)->seglist_lock);
> > +             if (test_and_clear_bit(segno, DIRTY_I(sbi)->dirty_segmap[PRE]))
> > +                     DIRTY_I(sbi)->nr_dirty[PRE]--;
> > +             mutex_unlock(&DIRTY_I(sbi)->seglist_lock);
> > +
> > +             /* add it into dirty seglist */
> > +             locate_dirty_segment(sbi, segno);
> > +
> > +             /* update @addr_start and @cnt and @segno */
> > +             addr_start = START_BLOCK(sbi, ++segno);
> > +             if (++i == seg_num)
> > +                     cnt = GET_BLKOFF_FROM_SEG0(sbi, addr_end) + 1;
> > +             else
> > +                     cnt = max_blocks;
> > +     } while (i <= seg_num);
> > +
> > +     up_write(&sit_i->sentry_lock);
> > +}
> > +
> >   bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr)
> >   {
> >       struct sit_info *sit_i = SIT_I(sbi);
> > @@ -2758,8 +2816,13 @@ static int is_next_segment_free(struct f2fs_sb_info *sbi,
> >       unsigned int segno = curseg->segno + 1;
> >       struct free_segmap_info *free_i = FREE_I(sbi);
> >
> > -     if (segno < MAIN_SEGS(sbi) && segno % SEGS_PER_SEC(sbi))
> > +     if (segno < MAIN_SEGS(sbi) && segno % SEGS_PER_SEC(sbi)) {
> > +             int devi = f2fs_target_device_index(sbi, START_BLOCK(sbi, segno));
> > +
> > +             if (f2fs_dev_is_reserving(sbi, devi))
> > +                     return 0;
> >               return !test_bit(segno, free_i->free_segmap);
> > +     }
> >       return 0;
> >   }
> >
> > @@ -2778,6 +2841,7 @@ static int get_new_segment(struct f2fs_sb_info *sbi,
> >       unsigned int alloc_policy = sbi->allocate_section_policy;
> >       unsigned int alloc_hint = sbi->allocate_section_hint;
> >       bool init = true;
> > +     bool looped = false;
> >       int i;
> >       int ret = 0;
> >
> > @@ -2791,8 +2855,13 @@ static int get_new_segment(struct f2fs_sb_info *sbi,
> >       if (!new_sec && ((*newseg + 1) % SEGS_PER_SEC(sbi))) {
> >               segno = find_next_zero_bit(free_i->free_segmap,
> >                       GET_SEG_FROM_SEC(sbi, hint + 1), *newseg + 1);
> > -             if (segno < GET_SEG_FROM_SEC(sbi, hint + 1))
> > +             if (segno < GET_SEG_FROM_SEC(sbi, hint + 1)) {
> > +                     int devi = f2fs_target_device_index(sbi, START_BLOCK(sbi, segno));
> > +
> > +                     if (f2fs_dev_is_alloc_blocked(sbi, devi, pinning))
> > +                             goto find_other_zone;
> >                       goto got_it;
> > +             }
> >       }
> >
> >   #ifdef CONFIG_BLK_DEV_ZONED
> > @@ -2828,33 +2897,50 @@ static int get_new_segment(struct f2fs_sb_info *sbi,
> >   find_other_zone:
> >       secno = find_next_zero_bit(free_i->free_secmap, MAIN_SECS(sbi), hint);
> >
> > -#ifdef CONFIG_BLK_DEV_ZONED
> > -     if (secno >= MAIN_SECS(sbi) && f2fs_sb_has_blkzoned(sbi)) {
> > -             /* Write only to sequential zones */
> > -             if (sbi->blkzone_alloc_policy == BLKZONE_ALLOC_ONLY_SEQ) {
> > -                     hint = GET_SEC_FROM_SEG(sbi, sbi->first_seq_zone_segno);
> > -                     secno = find_next_zero_bit(free_i->free_secmap, MAIN_SECS(sbi), hint);
> > -             } else
> > -                     secno = find_first_zero_bit(free_i->free_secmap,
> > -                                                             MAIN_SECS(sbi));
> > -             if (secno >= MAIN_SECS(sbi)) {
> > -                     ret = -ENOSPC;
> > -                     f2fs_bug_on(sbi, 1);
> > -                     goto out_unlock;
> > -             }
> > -     }
> > -#endif
> > -
> >       if (secno >= MAIN_SECS(sbi)) {
> > -             secno = find_first_zero_bit(free_i->free_secmap,
> > -                                                     MAIN_SECS(sbi));
> > -             if (secno >= MAIN_SECS(sbi)) {
> > +             if (looped) {
> >                       ret = -ENOSPC;
> >                       f2fs_bug_on(sbi, !pinning);
> >                       goto out_unlock;
> >               }
> > +#ifdef CONFIG_BLK_DEV_ZONED
> > +             /* Write only to sequential zones */
> > +             if (f2fs_sb_has_blkzoned(sbi) &&
> > +                     sbi->blkzone_alloc_policy == BLKZONE_ALLOC_ONLY_SEQ)
> > +                     hint = GET_SEC_FROM_SEG(sbi, sbi->first_seq_zone_segno);
> > +             else
> > +#endif
> > +                     hint = 0;
> > +             looped = true;
> > +             goto find_other_zone;
> >       }
> > +
> >       segno = GET_SEG_FROM_SEC(sbi, secno);
> > +
> > +     if (f2fs_sb_has_device_alias(sbi) && f2fs_is_multi_device(sbi)) {
> > +             int devi = f2fs_target_device_index(sbi, START_BLOCK(sbi, segno));
> > +
> > +             if (f2fs_dev_is_alloc_blocked(sbi, devi, pinning)) {
> > +                     unsigned int end_segno;
> > +
> > +                     while (devi < sbi->s_ndevs &&
> > +                             f2fs_dev_is_alloc_blocked(sbi, devi, pinning)) {
> > +                             block_t next_blk;
> > +
> > +                             end_segno = GET_SEGNO(sbi, FDEV(devi).end_blk);
> > +                             hint = GET_SEC_FROM_SEG(sbi, end_segno) + 1;
> > +
> > +                             if (hint >= MAIN_SECS(sbi) || ++devi >= sbi->s_ndevs)
> > +                                     break;
> > +
> > +                             next_blk = START_BLOCK(sbi, GET_SEG_FROM_SEC(sbi, hint));
> > +                             if (next_blk < FDEV(devi).start_blk ||
> > +                                     next_blk > FDEV(devi).end_blk)
> > +                                     break;
> > +                     }
> > +                     goto find_other_zone;
> > +             }
> > +     }
> >       zoneno = GET_ZONE_FROM_SEC(sbi, secno);
> >
> >       /* give up on finding another zone */
> > diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
> > index b0c06b3580b4..259e4a29b494 100644
> > --- a/fs/f2fs/segment.h
> > +++ b/fs/f2fs/segment.h
> > @@ -954,10 +954,36 @@ static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type)
> >                               - (base + 1) + type;
> >   }
> >
> > +static inline bool f2fs_dev_is_reserving(struct f2fs_sb_info *sbi, int devi)
> > +{
> > +     if (!f2fs_sb_has_device_alias(sbi) || !f2fs_is_multi_device(sbi))
> > +             return false;
> > +     return FDEV(devi).is_reserving;
> > +}
> > +
> > +static inline bool f2fs_dev_is_alloc_blocked(struct f2fs_sb_info *sbi,
> > +                                     int devi, bool pinning)
> > +{
> > +     if (!f2fs_sb_has_device_alias(sbi) || !f2fs_is_multi_device(sbi))
> > +             return false;
> > +     return (pinning && FDEV(devi).has_alias) || FDEV(devi).is_reserving;
> > +}
> > +
> >   static inline bool sec_usage_check(struct f2fs_sb_info *sbi, unsigned int secno)
> >   {
> >       if (is_cursec(sbi, secno) || (sbi->cur_victim_sec == secno))
> >               return true;
> > +     if (f2fs_sb_has_device_alias(sbi) && f2fs_is_multi_device(sbi)) {
> > +             int i;
> > +             block_t start_blk = START_BLOCK(sbi, GET_SEG_FROM_SEC(sbi, secno));
> > +
> > +             for (i = 0; i < sbi->s_ndevs; i++) {
> > +                     if (f2fs_dev_is_reserving(sbi, i) &&
> > +                             start_blk >= FDEV(i).start_blk &&
> > +                             start_blk <= FDEV(i).end_blk)
> > +                             return true;
> > +             }
> > +     }
> >       return false;
> >   }
> >
> > diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> > index c448d992ff2a..8359eed903be 100644
> > --- a/fs/f2fs/super.c
> > +++ b/fs/f2fs/super.c
> > @@ -5001,6 +5001,38 @@ static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi)
> >       sbi->readdir_ra = true;
> >   }
> >
> > +static void f2fs_restore_device_alias(struct f2fs_sb_info *sbi)
> > +{
> > +     struct inode *root = d_inode(sbi->sb->s_root);
> > +     struct f2fs_dir_entry *de;
> > +     struct folio *folio;
> > +     int i;
> > +
> > +     if (!f2fs_sb_has_device_alias(sbi))
> > +             return;
> > +
> > +     for (i = 1; i < sbi->s_ndevs; i++) {
> > +             char *name = strrchr(FDEV(i).path, '/');
> > +             struct qstr qstr;
> > +
> > +             name = name ? name + 1 : FDEV(i).path;
> > +             qstr.name = name;
> > +             qstr.len = strlen(name);
> > +
> > +             de = f2fs_find_entry(root, &qstr, &folio);
> > +             if (de) {
> > +                     struct inode *inode = f2fs_iget(sbi->sb, le32_to_cpu(de->ino));
> > +
> > +                     if (!IS_ERR(inode)) {
> > +                             if (IS_DEVICE_ALIASING(inode))
> > +                                     FDEV(i).has_alias = true;
> > +                             iput(inode);
> > +                     }
> > +                     f2fs_folio_put(folio, 0);
> > +             }
> > +     }
> > +}
> > +
> >   static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
> >   {
> >       struct f2fs_fs_context *ctx = fc->fs_private;
> > @@ -5436,6 +5468,8 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
> >       f2fs_update_time(sbi, REQ_TIME);
> >       clear_sbi_flag(sbi, SBI_CP_DISABLED_QUICK);
> >
> > +     f2fs_restore_device_alias(sbi);
> > +
> >       sbi->umount_lock_holder = NULL;
> >       return 0;
> >
> > diff --git a/include/uapi/linux/f2fs.h b/include/uapi/linux/f2fs.h
> > index 795e26258355..4409ada2fecb 100644
> > --- a/include/uapi/linux/f2fs.h
> > +++ b/include/uapi/linux/f2fs.h
> > @@ -45,6 +45,9 @@
> >   #define F2FS_IOC_START_ATOMIC_REPLACE       _IO(F2FS_IOCTL_MAGIC, 25)
> >   #define F2FS_IOC_GET_DEV_ALIAS_FILE _IOR(F2FS_IOCTL_MAGIC, 26, __u32)
> >   #define F2FS_IOC_IO_PRIO            _IOW(F2FS_IOCTL_MAGIC, 27, __u32)
> > +#define F2FS_IOC_RESERVE_DEV_ALIAS   _IO(F2FS_IOCTL_MAGIC, 28)
> > +#define F2FS_IOC_RELEASE_DEV_ALIAS   _IO(F2FS_IOCTL_MAGIC, 29)
> > +#define F2FS_IOC_GET_DEV_ALIAS_STATUS        _IOR(F2FS_IOCTL_MAGIC, 30, __u32)
> >
> >   /*
> >    * should be same as XFS_IOC_GOINGDOWN.
> > @@ -70,6 +73,10 @@ enum {
> >       F2FS_IOPRIO_MAX,
> >   };
> >
> > +/* for F2FS_IOC_GET_DEV_ALIAS_STATUS */
> > +#define F2FS_DEV_ALIAS_STATUS_RELEASED       0
> > +#define F2FS_DEV_ALIAS_STATUS_RESERVED       1
> > +
> >   struct f2fs_gc_range {
> >       __u32 sync;
> >       __u64 start;
>


_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel