Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2010 Red Hat, Inc.
0004  * All Rights Reserved.
0005  */
0006 #include "xfs.h"
0007 #include "xfs_shared.h"
0008 #include "xfs_format.h"
0009 #include "xfs_log_format.h"
0010 #include "xfs_trans_resv.h"
0011 #include "xfs_mount.h"
0012 #include "xfs_btree.h"
0013 #include "xfs_alloc_btree.h"
0014 #include "xfs_alloc.h"
0015 #include "xfs_discard.h"
0016 #include "xfs_error.h"
0017 #include "xfs_extent_busy.h"
0018 #include "xfs_trace.h"
0019 #include "xfs_log.h"
0020 #include "xfs_ag.h"
0021 
0022 STATIC int
0023 xfs_trim_extents(
0024     struct xfs_mount    *mp,
0025     xfs_agnumber_t      agno,
0026     xfs_daddr_t     start,
0027     xfs_daddr_t     end,
0028     xfs_daddr_t     minlen,
0029     uint64_t        *blocks_trimmed)
0030 {
0031     struct block_device *bdev = mp->m_ddev_targp->bt_bdev;
0032     struct xfs_btree_cur    *cur;
0033     struct xfs_buf      *agbp;
0034     struct xfs_agf      *agf;
0035     struct xfs_perag    *pag;
0036     int         error;
0037     int         i;
0038 
0039     pag = xfs_perag_get(mp, agno);
0040 
0041     /*
0042      * Force out the log.  This means any transactions that might have freed
0043      * space before we take the AGF buffer lock are now on disk, and the
0044      * volatile disk cache is flushed.
0045      */
0046     xfs_log_force(mp, XFS_LOG_SYNC);
0047 
0048     error = xfs_alloc_read_agf(pag, NULL, 0, &agbp);
0049     if (error)
0050         goto out_put_perag;
0051     agf = agbp->b_addr;
0052 
0053     cur = xfs_allocbt_init_cursor(mp, NULL, agbp, pag, XFS_BTNUM_CNT);
0054 
0055     /*
0056      * Look up the longest btree in the AGF and start with it.
0057      */
0058     error = xfs_alloc_lookup_ge(cur, 0, be32_to_cpu(agf->agf_longest), &i);
0059     if (error)
0060         goto out_del_cursor;
0061 
0062     /*
0063      * Loop until we are done with all extents that are large
0064      * enough to be worth discarding.
0065      */
0066     while (i) {
0067         xfs_agblock_t   fbno;
0068         xfs_extlen_t    flen;
0069         xfs_daddr_t dbno;
0070         xfs_extlen_t    dlen;
0071 
0072         error = xfs_alloc_get_rec(cur, &fbno, &flen, &i);
0073         if (error)
0074             goto out_del_cursor;
0075         if (XFS_IS_CORRUPT(mp, i != 1)) {
0076             error = -EFSCORRUPTED;
0077             goto out_del_cursor;
0078         }
0079         ASSERT(flen <= be32_to_cpu(agf->agf_longest));
0080 
0081         /*
0082          * use daddr format for all range/len calculations as that is
0083          * the format the range/len variables are supplied in by
0084          * userspace.
0085          */
0086         dbno = XFS_AGB_TO_DADDR(mp, agno, fbno);
0087         dlen = XFS_FSB_TO_BB(mp, flen);
0088 
0089         /*
0090          * Too small?  Give up.
0091          */
0092         if (dlen < minlen) {
0093             trace_xfs_discard_toosmall(mp, agno, fbno, flen);
0094             goto out_del_cursor;
0095         }
0096 
0097         /*
0098          * If the extent is entirely outside of the range we are
0099          * supposed to discard skip it.  Do not bother to trim
0100          * down partially overlapping ranges for now.
0101          */
0102         if (dbno + dlen < start || dbno > end) {
0103             trace_xfs_discard_exclude(mp, agno, fbno, flen);
0104             goto next_extent;
0105         }
0106 
0107         /*
0108          * If any blocks in the range are still busy, skip the
0109          * discard and try again the next time.
0110          */
0111         if (xfs_extent_busy_search(mp, pag, fbno, flen)) {
0112             trace_xfs_discard_busy(mp, agno, fbno, flen);
0113             goto next_extent;
0114         }
0115 
0116         trace_xfs_discard_extent(mp, agno, fbno, flen);
0117         error = blkdev_issue_discard(bdev, dbno, dlen, GFP_NOFS);
0118         if (error)
0119             goto out_del_cursor;
0120         *blocks_trimmed += flen;
0121 
0122 next_extent:
0123         error = xfs_btree_decrement(cur, 0, &i);
0124         if (error)
0125             goto out_del_cursor;
0126 
0127         if (fatal_signal_pending(current)) {
0128             error = -ERESTARTSYS;
0129             goto out_del_cursor;
0130         }
0131     }
0132 
0133 out_del_cursor:
0134     xfs_btree_del_cursor(cur, error);
0135     xfs_buf_relse(agbp);
0136 out_put_perag:
0137     xfs_perag_put(pag);
0138     return error;
0139 }
0140 
0141 /*
0142  * trim a range of the filesystem.
0143  *
0144  * Note: the parameters passed from userspace are byte ranges into the
0145  * filesystem which does not match to the format we use for filesystem block
0146  * addressing. FSB addressing is sparse (AGNO|AGBNO), while the incoming format
0147  * is a linear address range. Hence we need to use DADDR based conversions and
0148  * comparisons for determining the correct offset and regions to trim.
0149  */
0150 int
0151 xfs_ioc_trim(
0152     struct xfs_mount        *mp,
0153     struct fstrim_range __user  *urange)
0154 {
0155     unsigned int        granularity =
0156         bdev_discard_granularity(mp->m_ddev_targp->bt_bdev);
0157     struct fstrim_range range;
0158     xfs_daddr_t     start, end, minlen;
0159     xfs_agnumber_t      start_agno, end_agno, agno;
0160     uint64_t        blocks_trimmed = 0;
0161     int         error, last_error = 0;
0162 
0163     if (!capable(CAP_SYS_ADMIN))
0164         return -EPERM;
0165     if (!bdev_max_discard_sectors(mp->m_ddev_targp->bt_bdev))
0166         return -EOPNOTSUPP;
0167 
0168     /*
0169      * We haven't recovered the log, so we cannot use our bnobt-guided
0170      * storage zapping commands.
0171      */
0172     if (xfs_has_norecovery(mp))
0173         return -EROFS;
0174 
0175     if (copy_from_user(&range, urange, sizeof(range)))
0176         return -EFAULT;
0177 
0178     range.minlen = max_t(u64, granularity, range.minlen);
0179     minlen = BTOBB(range.minlen);
0180     /*
0181      * Truncating down the len isn't actually quite correct, but using
0182      * BBTOB would mean we trivially get overflows for values
0183      * of ULLONG_MAX or slightly lower.  And ULLONG_MAX is the default
0184      * used by the fstrim application.  In the end it really doesn't
0185      * matter as trimming blocks is an advisory interface.
0186      */
0187     if (range.start >= XFS_FSB_TO_B(mp, mp->m_sb.sb_dblocks) ||
0188         range.minlen > XFS_FSB_TO_B(mp, mp->m_ag_max_usable) ||
0189         range.len < mp->m_sb.sb_blocksize)
0190         return -EINVAL;
0191 
0192     start = BTOBB(range.start);
0193     end = start + BTOBBT(range.len) - 1;
0194 
0195     if (end > XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks) - 1)
0196         end = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)- 1;
0197 
0198     start_agno = xfs_daddr_to_agno(mp, start);
0199     end_agno = xfs_daddr_to_agno(mp, end);
0200 
0201     for (agno = start_agno; agno <= end_agno; agno++) {
0202         error = xfs_trim_extents(mp, agno, start, end, minlen,
0203                       &blocks_trimmed);
0204         if (error) {
0205             last_error = error;
0206             if (error == -ERESTARTSYS)
0207                 break;
0208         }
0209     }
0210 
0211     if (last_error)
0212         return last_error;
0213 
0214     range.len = XFS_FSB_TO_B(mp, blocks_trimmed);
0215     if (copy_to_user(urange, &range, sizeof(range)))
0216         return -EFAULT;
0217     return 0;
0218 }