linux/fs/jfs/jfs_discard.c
<<
>>
Prefs
   1/*
   2 *   Copyright (C) Tino Reichardt, 2012
   3 *
   4 *   This program is free software;  you can redistribute it and/or modify
   5 *   it under the terms of the GNU General Public License as published by
   6 *   the Free Software Foundation; either version 2 of the License, or
   7 *   (at your option) any later version.
   8 *
   9 *   This program is distributed in the hope that it will be useful,
  10 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
  11 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  12 *   the GNU General Public License for more details.
  13 *
  14 *   You should have received a copy of the GNU General Public License
  15 *   along with this program;  if not, write to the Free Software
  16 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17 */
  18
  19#include <linux/fs.h>
  20#include <linux/slab.h>
  21#include <linux/blkdev.h>
  22
  23#include "jfs_incore.h"
  24#include "jfs_superblock.h"
  25#include "jfs_discard.h"
  26#include "jfs_dmap.h"
  27#include "jfs_debug.h"
  28
  29
  30/*
  31 * NAME:        jfs_issue_discard()
  32 *
  33 * FUNCTION:    TRIM the specified block range on device, if supported
  34 *
  35 * PARAMETERS:
  36 *      ip      - pointer to in-core inode
  37 *      blkno   - starting block number to be trimmed (0..N)
  38 *      nblocks - number of blocks to be trimmed
  39 *
  40 * RETURN VALUES:
  41 *      none
  42 *
  43 * serialization: IREAD_LOCK(ipbmap) held on entry/exit;
  44 */
  45void jfs_issue_discard(struct inode *ip, u64 blkno, u64 nblocks)
  46{
  47        struct super_block *sb = ip->i_sb;
  48        int r = 0;
  49
  50        r = sb_issue_discard(sb, blkno, nblocks, GFP_NOFS, 0);
  51        if (unlikely(r != 0)) {
  52                jfs_err("JFS: sb_issue_discard" \
  53                        "(%p, %llu, %llu, GFP_NOFS, 0) = %d => failed!\n",
  54                        sb, (unsigned long long)blkno,
  55                        (unsigned long long)nblocks, r);
  56        }
  57
  58        jfs_info("JFS: sb_issue_discard" \
  59                "(%p, %llu, %llu, GFP_NOFS, 0) = %d\n",
  60                sb, (unsigned long long)blkno,
  61                (unsigned long long)nblocks, r);
  62
  63        return;
  64}
  65
  66/*
  67 * NAME:        jfs_ioc_trim()
  68 *
  69 * FUNCTION:    attempt to discard (TRIM) all free blocks from the
  70 *              filesystem.
  71 *
  72 * PARAMETERS:
  73 *      ip      - pointer to in-core inode;
  74 *      range   - the range, given by user space
  75 *
  76 * RETURN VALUES:
  77 *      0       - success
  78 *      -EIO    - i/o error
  79 */
  80int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range)
  81{
  82        struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
  83        struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
  84        struct super_block *sb = ipbmap->i_sb;
  85        int agno, agno_end;
  86        u64 start, end, minlen;
  87        u64 trimmed = 0;
  88
  89        /**
  90         * convert byte values to block size of filesystem:
  91         * start:       First Byte to trim
  92         * len:         number of Bytes to trim from start
  93         * minlen:      minimum extent length in Bytes
  94         */
  95        start = range->start >> sb->s_blocksize_bits;
  96        end = start + (range->len >> sb->s_blocksize_bits) - 1;
  97        minlen = range->minlen >> sb->s_blocksize_bits;
  98        if (minlen == 0)
  99                minlen = 1;
 100
 101        if (minlen > bmp->db_agsize ||
 102            start >= bmp->db_mapsize ||
 103            range->len < sb->s_blocksize)
 104                return -EINVAL;
 105
 106        if (end >= bmp->db_mapsize)
 107                end = bmp->db_mapsize - 1;
 108
 109        /**
 110         * we trim all ag's within the range
 111         */
 112        agno = BLKTOAG(start, JFS_SBI(ip->i_sb));
 113        agno_end = BLKTOAG(end, JFS_SBI(ip->i_sb));
 114        while (agno <= agno_end) {
 115                trimmed += dbDiscardAG(ip, agno, minlen);
 116                agno++;
 117        }
 118        range->len = trimmed << sb->s_blocksize_bits;
 119
 120        return 0;
 121}
 122