jfs_discard.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) Tino Reichardt, 2012
  4. */
  5. #include <linux/fs.h>
  6. #include <linux/slab.h>
  7. #include <linux/blkdev.h>
  8. #include "jfs_incore.h"
  9. #include "jfs_superblock.h"
  10. #include "jfs_discard.h"
  11. #include "jfs_dmap.h"
  12. #include "jfs_debug.h"
  13. /*
  14. * NAME: jfs_issue_discard()
  15. *
  16. * FUNCTION: TRIM the specified block range on device, if supported
  17. *
  18. * PARAMETERS:
  19. * ip - pointer to in-core inode
  20. * blkno - starting block number to be trimmed (0..N)
  21. * nblocks - number of blocks to be trimmed
  22. *
  23. * RETURN VALUES:
  24. * none
  25. *
  26. * serialization: IREAD_LOCK(ipbmap) held on entry/exit;
  27. */
  28. void jfs_issue_discard(struct inode *ip, u64 blkno, u64 nblocks)
  29. {
  30. struct super_block *sb = ip->i_sb;
  31. int r = 0;
  32. r = sb_issue_discard(sb, blkno, nblocks, GFP_NOFS, 0);
  33. if (unlikely(r != 0)) {
  34. jfs_err("JFS: sb_issue_discard(%p, %llu, %llu, GFP_NOFS, 0) = %d => failed!",
  35. sb, (unsigned long long)blkno,
  36. (unsigned long long)nblocks, r);
  37. }
  38. jfs_info("JFS: sb_issue_discard(%p, %llu, %llu, GFP_NOFS, 0) = %d",
  39. sb, (unsigned long long)blkno,
  40. (unsigned long long)nblocks, r);
  41. return;
  42. }
  43. /*
  44. * NAME: jfs_ioc_trim()
  45. *
  46. * FUNCTION: attempt to discard (TRIM) all free blocks from the
  47. * filesystem.
  48. *
  49. * PARAMETERS:
  50. * ip - pointer to in-core inode;
  51. * range - the range, given by user space
  52. *
  53. * RETURN VALUES:
  54. * 0 - success
  55. * -EIO - i/o error
  56. */
  57. int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range)
  58. {
  59. struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
  60. struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
  61. struct super_block *sb = ipbmap->i_sb;
  62. int agno, agno_end;
  63. u64 start, end, minlen;
  64. u64 trimmed = 0;
  65. /**
  66. * convert byte values to block size of filesystem:
  67. * start: First Byte to trim
  68. * len: number of Bytes to trim from start
  69. * minlen: minimum extent length in Bytes
  70. */
  71. start = range->start >> sb->s_blocksize_bits;
  72. end = start + (range->len >> sb->s_blocksize_bits) - 1;
  73. minlen = range->minlen >> sb->s_blocksize_bits;
  74. if (minlen == 0)
  75. minlen = 1;
  76. if (minlen > bmp->db_agsize ||
  77. start >= bmp->db_mapsize ||
  78. range->len < sb->s_blocksize)
  79. return -EINVAL;
  80. if (end >= bmp->db_mapsize)
  81. end = bmp->db_mapsize - 1;
  82. /**
  83. * we trim all ag's within the range
  84. */
  85. agno = BLKTOAG(start, JFS_SBI(ip->i_sb));
  86. agno_end = BLKTOAG(end, JFS_SBI(ip->i_sb));
  87. while (agno <= agno_end) {
  88. trimmed += dbDiscardAG(ip, agno, minlen);
  89. agno++;
  90. }
  91. range->len = trimmed << sb->s_blocksize_bits;
  92. return 0;
  93. }