162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) Tino Reichardt, 2012 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/fs.h> 762306a36Sopenharmony_ci#include <linux/slab.h> 862306a36Sopenharmony_ci#include <linux/blkdev.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "jfs_incore.h" 1162306a36Sopenharmony_ci#include "jfs_superblock.h" 1262306a36Sopenharmony_ci#include "jfs_discard.h" 1362306a36Sopenharmony_ci#include "jfs_dmap.h" 1462306a36Sopenharmony_ci#include "jfs_debug.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* 1862306a36Sopenharmony_ci * NAME: jfs_issue_discard() 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * FUNCTION: TRIM the specified block range on device, if supported 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * PARAMETERS: 2362306a36Sopenharmony_ci * ip - pointer to in-core inode 2462306a36Sopenharmony_ci * blkno - starting block number to be trimmed (0..N) 2562306a36Sopenharmony_ci * nblocks - number of blocks to be trimmed 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * RETURN VALUES: 2862306a36Sopenharmony_ci * none 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * serialization: IREAD_LOCK(ipbmap) held on entry/exit; 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_civoid jfs_issue_discard(struct inode *ip, u64 blkno, u64 nblocks) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct super_block *sb = ip->i_sb; 3562306a36Sopenharmony_ci int r = 0; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci r = sb_issue_discard(sb, blkno, nblocks, GFP_NOFS, 0); 3862306a36Sopenharmony_ci if (unlikely(r != 0)) { 3962306a36Sopenharmony_ci jfs_err("JFS: sb_issue_discard(%p, %llu, %llu, GFP_NOFS, 0) = %d => failed!", 4062306a36Sopenharmony_ci sb, (unsigned long long)blkno, 4162306a36Sopenharmony_ci (unsigned long long)nblocks, r); 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci jfs_info("JFS: sb_issue_discard(%p, %llu, %llu, GFP_NOFS, 0) = %d", 4562306a36Sopenharmony_ci sb, (unsigned long long)blkno, 4662306a36Sopenharmony_ci (unsigned long long)nblocks, r); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci return; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* 5262306a36Sopenharmony_ci * NAME: jfs_ioc_trim() 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * FUNCTION: attempt to discard (TRIM) all free blocks from the 5562306a36Sopenharmony_ci * filesystem. 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * PARAMETERS: 5862306a36Sopenharmony_ci * ip - pointer to in-core inode; 5962306a36Sopenharmony_ci * range - the range, given by user space 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * RETURN VALUES: 6262306a36Sopenharmony_ci * 0 - success 6362306a36Sopenharmony_ci * -EIO - i/o error 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ciint jfs_ioc_trim(struct inode *ip, struct fstrim_range *range) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; 6862306a36Sopenharmony_ci struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap; 6962306a36Sopenharmony_ci struct super_block *sb = ipbmap->i_sb; 7062306a36Sopenharmony_ci int agno, agno_end; 7162306a36Sopenharmony_ci u64 start, end, minlen; 7262306a36Sopenharmony_ci u64 trimmed = 0; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /** 7562306a36Sopenharmony_ci * convert byte values to block size of filesystem: 7662306a36Sopenharmony_ci * start: First Byte to trim 7762306a36Sopenharmony_ci * len: number of Bytes to trim from start 7862306a36Sopenharmony_ci * minlen: minimum extent length in Bytes 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci start = range->start >> sb->s_blocksize_bits; 8162306a36Sopenharmony_ci end = start + (range->len >> sb->s_blocksize_bits) - 1; 8262306a36Sopenharmony_ci minlen = range->minlen >> sb->s_blocksize_bits; 8362306a36Sopenharmony_ci if (minlen == 0) 8462306a36Sopenharmony_ci minlen = 1; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (minlen > bmp->db_agsize || 8762306a36Sopenharmony_ci start >= bmp->db_mapsize || 8862306a36Sopenharmony_ci range->len < sb->s_blocksize) 8962306a36Sopenharmony_ci return -EINVAL; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (end >= bmp->db_mapsize) 9262306a36Sopenharmony_ci end = bmp->db_mapsize - 1; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /** 9562306a36Sopenharmony_ci * we trim all ag's within the range 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci agno = BLKTOAG(start, JFS_SBI(ip->i_sb)); 9862306a36Sopenharmony_ci agno_end = BLKTOAG(end, JFS_SBI(ip->i_sb)); 9962306a36Sopenharmony_ci while (agno <= agno_end) { 10062306a36Sopenharmony_ci trimmed += dbDiscardAG(ip, agno, minlen); 10162306a36Sopenharmony_ci agno++; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci range->len = trimmed << sb->s_blocksize_bits; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci} 107