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(%p, %llu, %llu, GFP_NOFS, 0) = %d => failed!",
  53                        sb, (unsigned long long)blkno,
  54                        (unsigned long long)nblocks, r);
  55        }
  56
  57        jfs_info("JFS: sb_issue_discard(%p, %llu, %llu, GFP_NOFS, 0) = %d",
  58                sb, (unsigned long long)blkno,
  59                (unsigned long long)nblocks, r);
  60
  61        return;
  62}
  63
  64/*
  65 * NAME:        jfs_ioc_trim()
  66 *
  67 * FUNCTION:    attempt to discard (TRIM) all free blocks from the
  68 *              filesystem.
  69 *
  70 * PARAMETERS:
  71 *      ip      - pointer to in-core inode;
  72 *      range   - the range, given by user space
  73 *
  74 * RETURN VALUES:
  75 *      0       - success
  76 *      -EIO    - i/o error
  77 */
  78int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range)
  79{
  80        struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
  81        struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
  82        struct super_block *sb = ipbmap->i_sb;
  83        int agno, agno_end;
  84        u64 start, end, minlen;
  85        u64 trimmed = 0;
  86
  87        /**
  88         * convert byte values to block size of filesystem:
  89         * start:       First Byte to trim
  90         * len:         number of Bytes to trim from start
  91         * minlen:      minimum extent length in Bytes
  92         */
  93        start = range->start >> sb->s_blocksize_bits;
  94        end = start + (range->len >> sb->s_blocksize_bits) - 1;
  95        minlen = range->minlen >> sb->s_blocksize_bits;
  96        if (minlen == 0)
  97                minlen = 1;
  98
  99        if (minlen > bmp->db_agsize ||
 100            start >= bmp->db_mapsize ||
 101            range->len < sb->s_blocksize)
 102                return -EINVAL;
 103
 104        if (end >= bmp->db_mapsize)
 105                end = bmp->db_mapsize - 1;
 106
 107        /**
 108         * we trim all ag's within the range
 109         */
 110        agno = BLKTOAG(start, JFS_SBI(ip->i_sb));
 111        agno_end = BLKTOAG(end, JFS_SBI(ip->i_sb));
 112        while (agno <= agno_end) {
 113                trimmed += dbDiscardAG(ip, agno, minlen);
 114                agno++;
 115        }
 116        range->len = trimmed << sb->s_blocksize_bits;
 117
 118        return 0;
 119}
 120