Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
Browse files Browse the repository at this point in the history
* 'for-linus' of git://oss.sgi.com/xfs/xfs:
  xfs: correctly decrement the extent buffer index in xfs_bmap_del_extent
  xfs: check for valid indices in xfs_iext_get_ext and xfs_iext_idx_to_irec
  xfs: fix up asserts in xfs_iflush_fork
  xfs: do not do pointer arithmetic on extent records
  xfs: do not use unchecked extent indices in xfs_bunmapi
  xfs: do not use unchecked extent indices in xfs_bmapi
  xfs: do not use unchecked extent indices in xfs_bmap_add_extent_*
  xfs: remove if_lastex
  xfs: remove the unused XFS_BMAPI_RSVBLOCKS flag
  xfs: do not discard alloc btree blocks
  xfs: add online discard support
  • Loading branch information
Linus Torvalds committed May 26, 2011
2 parents 35806b4 + 233eebb commit 8a0599d
Show file tree
Hide file tree
Showing 15 changed files with 366 additions and 318 deletions.
6 changes: 6 additions & 0 deletions Documentation/filesystems/xfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ When mounting an XFS filesystem, the following options are accepted.
drive level write caching to be enabled, for devices that
support write barriers.

discard
Issue command to let the block device reclaim space freed by the
filesystem. This is useful for SSD devices, thinly provisioned
LUNs and virtual machine images, but may have a performance
impact. This option is incompatible with the nodelaylog option.

dmapi
Enable the DMAPI (Data Management API) event callouts.
Use with the "mtpt" option.
Expand Down
29 changes: 29 additions & 0 deletions fs/xfs/linux-2.6/xfs_discard.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,32 @@ xfs_ioc_trim(
return -XFS_ERROR(EFAULT);
return 0;
}

int
xfs_discard_extents(
struct xfs_mount *mp,
struct list_head *list)
{
struct xfs_busy_extent *busyp;
int error = 0;

list_for_each_entry(busyp, list, list) {
trace_xfs_discard_extent(mp, busyp->agno, busyp->bno,
busyp->length);

error = -blkdev_issue_discard(mp->m_ddev_targp->bt_bdev,
XFS_AGB_TO_DADDR(mp, busyp->agno, busyp->bno),
XFS_FSB_TO_BB(mp, busyp->length),
GFP_NOFS, 0);
if (error && error != EOPNOTSUPP) {
xfs_info(mp,
"discard failed for extent [0x%llu,%u], error %d",
(unsigned long long)busyp->bno,
busyp->length,
error);
return error;
}
}

return 0;
}
2 changes: 2 additions & 0 deletions fs/xfs/linux-2.6/xfs_discard.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
#define XFS_DISCARD_H 1

struct fstrim_range;
struct list_head;

extern int xfs_ioc_trim(struct xfs_mount *, struct fstrim_range __user *);
extern int xfs_discard_extents(struct xfs_mount *, struct list_head *);

#endif /* XFS_DISCARD_H */
18 changes: 16 additions & 2 deletions fs/xfs/linux-2.6/xfs_super.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,10 @@ mempool_t *xfs_ioend_pool;
#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
#define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */
#define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */
#define MNTOPT_DELAYLOG "delaylog" /* Delayed loging enabled */
#define MNTOPT_NODELAYLOG "nodelaylog" /* Delayed loging disabled */
#define MNTOPT_DELAYLOG "delaylog" /* Delayed logging enabled */
#define MNTOPT_NODELAYLOG "nodelaylog" /* Delayed logging disabled */
#define MNTOPT_DISCARD "discard" /* Discard unused blocks */
#define MNTOPT_NODISCARD "nodiscard" /* Do not discard unused blocks */

/*
* Table driven mount option parser.
Expand Down Expand Up @@ -355,6 +357,10 @@ xfs_parseargs(
mp->m_flags |= XFS_MOUNT_DELAYLOG;
} else if (!strcmp(this_char, MNTOPT_NODELAYLOG)) {
mp->m_flags &= ~XFS_MOUNT_DELAYLOG;
} else if (!strcmp(this_char, MNTOPT_DISCARD)) {
mp->m_flags |= XFS_MOUNT_DISCARD;
} else if (!strcmp(this_char, MNTOPT_NODISCARD)) {
mp->m_flags &= ~XFS_MOUNT_DISCARD;
} else if (!strcmp(this_char, "ihashsize")) {
xfs_warn(mp,
"ihashsize no longer used, option is deprecated.");
Expand Down Expand Up @@ -388,6 +394,13 @@ xfs_parseargs(
return EINVAL;
}

if ((mp->m_flags & XFS_MOUNT_DISCARD) &&
!(mp->m_flags & XFS_MOUNT_DELAYLOG)) {
xfs_warn(mp,
"the discard option is incompatible with the nodelaylog option");
return EINVAL;
}

#ifndef CONFIG_XFS_QUOTA
if (XFS_IS_QUOTA_RUNNING(mp)) {
xfs_warn(mp, "quota support not available in this kernel.");
Expand Down Expand Up @@ -488,6 +501,7 @@ xfs_showargs(
{ XFS_MOUNT_FILESTREAMS, "," MNTOPT_FILESTREAM },
{ XFS_MOUNT_GRPID, "," MNTOPT_GRPID },
{ XFS_MOUNT_DELAYLOG, "," MNTOPT_DELAYLOG },
{ XFS_MOUNT_DISCARD, "," MNTOPT_DISCARD },
{ 0, NULL }
};
static struct proc_xfs_info xfs_info_unset[] = {
Expand Down
3 changes: 3 additions & 0 deletions fs/xfs/xfs_ag.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ struct xfs_busy_extent {
xfs_agnumber_t agno;
xfs_agblock_t bno;
xfs_extlen_t length;
unsigned int flags;
#define XFS_ALLOC_BUSY_DISCARDED 0x01 /* undergoing a discard op. */
#define XFS_ALLOC_BUSY_SKIP_DISCARD 0x02 /* do not discard */
};

/*
Expand Down
35 changes: 30 additions & 5 deletions fs/xfs/xfs_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2469,7 +2469,7 @@ xfs_free_extent(

error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0);
if (!error)
xfs_alloc_busy_insert(tp, args.agno, args.agbno, len);
xfs_alloc_busy_insert(tp, args.agno, args.agbno, len, 0);
error0:
xfs_perag_put(args.pag);
return error;
Expand All @@ -2480,7 +2480,8 @@ xfs_alloc_busy_insert(
struct xfs_trans *tp,
xfs_agnumber_t agno,
xfs_agblock_t bno,
xfs_extlen_t len)
xfs_extlen_t len,
unsigned int flags)
{
struct xfs_busy_extent *new;
struct xfs_busy_extent *busyp;
Expand All @@ -2504,6 +2505,7 @@ xfs_alloc_busy_insert(
new->bno = bno;
new->length = len;
INIT_LIST_HEAD(&new->list);
new->flags = flags;

/* trace before insert to be able to see failed inserts */
trace_xfs_alloc_busy(tp->t_mountp, agno, bno, len);
Expand Down Expand Up @@ -2608,6 +2610,18 @@ xfs_alloc_busy_update_extent(
xfs_agblock_t bbno = busyp->bno;
xfs_agblock_t bend = bbno + busyp->length;

/*
* This extent is currently being discarded. Give the thread
* performing the discard a chance to mark the extent unbusy
* and retry.
*/
if (busyp->flags & XFS_ALLOC_BUSY_DISCARDED) {
spin_unlock(&pag->pagb_lock);
delay(1);
spin_lock(&pag->pagb_lock);
return false;
}

/*
* If there is a busy extent overlapping a user allocation, we have
* no choice but to force the log and retry the search.
Expand Down Expand Up @@ -2813,7 +2827,8 @@ xfs_alloc_busy_trim(
* If this is a metadata allocation, try to reuse the busy
* extent instead of trimming the allocation.
*/
if (!args->userdata) {
if (!args->userdata &&
!(busyp->flags & XFS_ALLOC_BUSY_DISCARDED)) {
if (!xfs_alloc_busy_update_extent(args->mp, args->pag,
busyp, fbno, flen,
false))
Expand Down Expand Up @@ -2979,10 +2994,16 @@ xfs_alloc_busy_clear_one(
kmem_free(busyp);
}

/*
* Remove all extents on the passed in list from the busy extents tree.
* If do_discard is set skip extents that need to be discarded, and mark
* these as undergoing a discard operation instead.
*/
void
xfs_alloc_busy_clear(
struct xfs_mount *mp,
struct list_head *list)
struct list_head *list,
bool do_discard)
{
struct xfs_busy_extent *busyp, *n;
struct xfs_perag *pag = NULL;
Expand All @@ -2999,7 +3020,11 @@ xfs_alloc_busy_clear(
agno = busyp->agno;
}

xfs_alloc_busy_clear_one(mp, pag, busyp);
if (do_discard && busyp->length &&
!(busyp->flags & XFS_ALLOC_BUSY_SKIP_DISCARD))
busyp->flags = XFS_ALLOC_BUSY_DISCARDED;
else
xfs_alloc_busy_clear_one(mp, pag, busyp);
}

if (pag) {
Expand Down
5 changes: 3 additions & 2 deletions fs/xfs/xfs_alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,11 @@ xfs_alloc_longest_free_extent(struct xfs_mount *mp,
#ifdef __KERNEL__
void
xfs_alloc_busy_insert(struct xfs_trans *tp, xfs_agnumber_t agno,
xfs_agblock_t bno, xfs_extlen_t len);
xfs_agblock_t bno, xfs_extlen_t len, unsigned int flags);

void
xfs_alloc_busy_clear(struct xfs_mount *mp, struct list_head *list);
xfs_alloc_busy_clear(struct xfs_mount *mp, struct list_head *list,
bool do_discard);

int
xfs_alloc_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno,
Expand Down
3 changes: 2 additions & 1 deletion fs/xfs/xfs_alloc_btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ xfs_allocbt_free_block(
if (error)
return error;

xfs_alloc_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1);
xfs_alloc_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1,
XFS_ALLOC_BUSY_SKIP_DISCARD);
xfs_trans_agbtree_delta(cur->bc_tp, -1);
return 0;
}
Expand Down
Loading

0 comments on commit 8a0599d

Please sign in to comment.