Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b41dae06 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'xfs-5.4-merge-7' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull xfs updates from Darrick Wong:
 "For this cycle we have the usual pile of cleanups and bug fixes, some
  performance improvements for online metadata scrubbing, massive
  speedups in the directory entry creation code, some performance
  improvement in the file ACL lookup code, a fix for a logging stall
  during mount, and fixes for concurrency problems.

  It has survived a couple of weeks of xfstests runs and merges cleanly.

  Summary:

   - Remove KM_SLEEP/KM_NOSLEEP.

   - Ensure that memory buffers for IO are properly sector-aligned to
     avoid problems that the block layer doesn't check.

   - Make the bmap scrubber more efficient in its record checking.

   - Don't crash xfs_db when superblock inode geometry is corrupt.

   - Fix btree key helper functions.

   - Remove unneeded error returns for things that can't fail.

   - Fix buffer logging bugs in repair.

   - Clean up iterator return values.

   - Speed up directory entry creation.

   - Enable allocation of xattr value memory buffer during lookup.

   - Fix readahead racing with truncate/punch hole.

   - Other minor cleanups.

   - Fix one AGI/AGF deadlock with RENAME_WHITEOUT.

   - More BUG -> WARN whackamole.

   - Fix various problems with the log failing to advance under certain
     circumstances, which results in stalls during mount"

* tag 'xfs-5.4-merge-7' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: (45 commits)
  xfs: push the grant head when the log head moves forward
  xfs: push iclog state cleaning into xlog_state_clean_log
  xfs: factor iclog state processing out of xlog_state_do_callback()
  xfs: factor callbacks out of xlog_state_do_callback()
  xfs: factor debug code out of xlog_state_do_callback()
  xfs: prevent CIL push holdoff in log recovery
  xfs: fix missed wakeup on l_flush_wait
  xfs: push the AIL in xlog_grant_head_wake
  xfs: Use WARN_ON_ONCE for bailout mount-operation
  xfs: Fix deadlock between AGI and AGF with RENAME_WHITEOUT
  xfs: define a flags field for the AG geometry ioctl structure
  xfs: add a xfs_valid_startblock helper
  xfs: remove the unused XFS_ALLOC_USERDATA flag
  xfs: cleanup xfs_fsb_to_db
  xfs: fix the dax supported check in xfs_ioctl_setattr_dax_invalidate
  xfs: Fix stale data exposure when readahead races with hole punch
  fs: Export generic_fadvise()
  mm: Handle MADV_WILLNEED through vfs_fadvise()
  xfs: allocate xattr buffer on demand
  xfs: consolidate attribute value copying
  ...
parents e6bc9de7 14e15f1b
Loading
Loading
Loading
Loading
+59 −20
Original line number Diff line number Diff line
@@ -3,10 +3,10 @@
 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
 * All Rights Reserved.
 */
#include <linux/sched/mm.h>
#include "xfs.h"
#include <linux/backing-dev.h>
#include "kmem.h"
#include "xfs_message.h"
#include "xfs_trace.h"

void *
kmem_alloc(size_t size, xfs_km_flags_t flags)
@@ -15,9 +15,11 @@ kmem_alloc(size_t size, xfs_km_flags_t flags)
	gfp_t	lflags = kmem_flags_convert(flags);
	void	*ptr;

	trace_kmem_alloc(size, flags, _RET_IP_);

	do {
		ptr = kmalloc(size, lflags);
		if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP)))
		if (ptr || (flags & KM_MAYFAIL))
			return ptr;
		if (!(++retries % 100))
			xfs_err(NULL,
@@ -28,28 +30,24 @@ kmem_alloc(size_t size, xfs_km_flags_t flags)
	} while (1);
}

void *
kmem_alloc_large(size_t size, xfs_km_flags_t flags)
{
	unsigned nofs_flag = 0;
	void	*ptr;
	gfp_t	lflags;

	ptr = kmem_alloc(size, flags | KM_MAYFAIL);
	if (ptr)
		return ptr;

/*
 * __vmalloc() will allocate data pages and auxillary structures (e.g.
	 * pagetables) with GFP_KERNEL, yet we may be under GFP_NOFS context
	 * here. Hence we need to tell memory reclaim that we are in such a
	 * context via PF_MEMALLOC_NOFS to prevent memory reclaim re-entering
	 * the filesystem here and potentially deadlocking.
 * pagetables) with GFP_KERNEL, yet we may be under GFP_NOFS context here. Hence
 * we need to tell memory reclaim that we are in such a context via
 * PF_MEMALLOC_NOFS to prevent memory reclaim re-entering the filesystem here
 * and potentially deadlocking.
 */
static void *
__kmem_vmalloc(size_t size, xfs_km_flags_t flags)
{
	unsigned nofs_flag = 0;
	void	*ptr;
	gfp_t	lflags = kmem_flags_convert(flags);

	if (flags & KM_NOFS)
		nofs_flag = memalloc_nofs_save();

	lflags = kmem_flags_convert(flags);
	ptr = __vmalloc(size, lflags, PAGE_KERNEL);

	if (flags & KM_NOFS)
@@ -58,6 +56,44 @@ kmem_alloc_large(size_t size, xfs_km_flags_t flags)
	return ptr;
}

/*
 * Same as kmem_alloc_large, except we guarantee the buffer returned is aligned
 * to the @align_mask. We only guarantee alignment up to page size, we'll clamp
 * alignment at page size if it is larger. vmalloc always returns a PAGE_SIZE
 * aligned region.
 */
void *
kmem_alloc_io(size_t size, int align_mask, xfs_km_flags_t flags)
{
	void	*ptr;

	trace_kmem_alloc_io(size, flags, _RET_IP_);

	if (WARN_ON_ONCE(align_mask >= PAGE_SIZE))
		align_mask = PAGE_SIZE - 1;

	ptr = kmem_alloc(size, flags | KM_MAYFAIL);
	if (ptr) {
		if (!((uintptr_t)ptr & align_mask))
			return ptr;
		kfree(ptr);
	}
	return __kmem_vmalloc(size, flags);
}

void *
kmem_alloc_large(size_t size, xfs_km_flags_t flags)
{
	void	*ptr;

	trace_kmem_alloc_large(size, flags, _RET_IP_);

	ptr = kmem_alloc(size, flags | KM_MAYFAIL);
	if (ptr)
		return ptr;
	return __kmem_vmalloc(size, flags);
}

void *
kmem_realloc(const void *old, size_t newsize, xfs_km_flags_t flags)
{
@@ -65,9 +101,11 @@ kmem_realloc(const void *old, size_t newsize, xfs_km_flags_t flags)
	gfp_t	lflags = kmem_flags_convert(flags);
	void	*ptr;

	trace_kmem_realloc(newsize, flags, _RET_IP_);

	do {
		ptr = krealloc(old, newsize, lflags);
		if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP)))
		if (ptr || (flags & KM_MAYFAIL))
			return ptr;
		if (!(++retries % 100))
			xfs_err(NULL,
@@ -85,9 +123,10 @@ kmem_zone_alloc(kmem_zone_t *zone, xfs_km_flags_t flags)
	gfp_t	lflags = kmem_flags_convert(flags);
	void	*ptr;

	trace_kmem_zone_alloc(kmem_cache_size(zone), flags, _RET_IP_);
	do {
		ptr = kmem_cache_alloc(zone, lflags);
		if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP)))
		if (ptr || (flags & KM_MAYFAIL))
			return ptr;
		if (!(++retries % 100))
			xfs_err(NULL,
+5 −10
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@
 */

typedef unsigned __bitwise xfs_km_flags_t;
#define KM_SLEEP	((__force xfs_km_flags_t)0x0001u)
#define KM_NOSLEEP	((__force xfs_km_flags_t)0x0002u)
#define KM_NOFS		((__force xfs_km_flags_t)0x0004u)
#define KM_MAYFAIL	((__force xfs_km_flags_t)0x0008u)
#define KM_ZERO		((__force xfs_km_flags_t)0x0010u)
@@ -32,15 +30,11 @@ kmem_flags_convert(xfs_km_flags_t flags)
{
	gfp_t	lflags;

	BUG_ON(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL|KM_ZERO));
	BUG_ON(flags & ~(KM_NOFS|KM_MAYFAIL|KM_ZERO));

	if (flags & KM_NOSLEEP) {
		lflags = GFP_ATOMIC | __GFP_NOWARN;
	} else {
	lflags = GFP_KERNEL | __GFP_NOWARN;
	if (flags & KM_NOFS)
		lflags &= ~__GFP_FS;
	}

	/*
	 * Default page/slab allocator behavior is to retry for ever
@@ -59,6 +53,7 @@ kmem_flags_convert(xfs_km_flags_t flags)
}

extern void *kmem_alloc(size_t, xfs_km_flags_t);
extern void *kmem_alloc_io(size_t size, int align_mask, xfs_km_flags_t flags);
extern void *kmem_alloc_large(size_t size, xfs_km_flags_t);
extern void *kmem_realloc(const void *, size_t, xfs_km_flags_t);
static inline void  kmem_free(const void *ptr)
+1 −1
Original line number Diff line number Diff line
@@ -2205,7 +2205,7 @@ xfs_defer_agfl_block(
	ASSERT(xfs_bmap_free_item_zone != NULL);
	ASSERT(oinfo != NULL);

	new = kmem_zone_alloc(xfs_bmap_free_item_zone, KM_SLEEP);
	new = kmem_zone_alloc(xfs_bmap_free_item_zone, 0);
	new->xefi_startblock = XFS_AGB_TO_FSB(mp, agno, agbno);
	new->xefi_blockcount = 1;
	new->xefi_oinfo = *oinfo;
+3 −4
Original line number Diff line number Diff line
@@ -81,10 +81,9 @@ typedef struct xfs_alloc_arg {
/*
 * Defines for datatype
 */
#define XFS_ALLOC_USERDATA		(1 << 0)/* allocation is for user data*/
#define XFS_ALLOC_INITIAL_USER_DATA	(1 << 1)/* special case start of file */
#define XFS_ALLOC_USERDATA_ZERO		(1 << 2)/* zero extent on allocation */
#define XFS_ALLOC_NOBUSY		(1 << 3)/* Busy extents not allowed */
#define XFS_ALLOC_INITIAL_USER_DATA	(1 << 0)/* special case start of file */
#define XFS_ALLOC_USERDATA_ZERO		(1 << 1)/* zero extent on allocation */
#define XFS_ALLOC_NOBUSY		(1 << 2)/* Busy extents not allowed */

static inline bool
xfs_alloc_is_userdata(int datatype)
+55 −24
Original line number Diff line number Diff line
@@ -97,7 +97,10 @@ xfs_inode_hasattr(
 * Overall external interface routines.
 *========================================================================*/

/* Retrieve an extended attribute and its value.  Must have ilock. */
/*
 * Retrieve an extended attribute and its value.  Must have ilock.
 * Returns 0 on successful retrieval, otherwise an error.
 */
int
xfs_attr_get_ilocked(
	struct xfs_inode	*ip,
@@ -115,12 +118,28 @@ xfs_attr_get_ilocked(
		return xfs_attr_node_get(args);
}

/* Retrieve an extended attribute by name, and its value. */
/*
 * Retrieve an extended attribute by name, and its value if requested.
 *
 * If ATTR_KERNOVAL is set in @flags, then the caller does not want the value,
 * just an indication whether the attribute exists and the size of the value if
 * it exists. The size is returned in @valuelenp,
 *
 * If the attribute is found, but exceeds the size limit set by the caller in
 * @valuelenp, return -ERANGE with the size of the attribute that was found in
 * @valuelenp.
 *
 * If ATTR_ALLOC is set in @flags, allocate the buffer for the value after
 * existence of the attribute has been determined. On success, return that
 * buffer to the caller and leave them to free it. On failure, free any
 * allocated buffer and ensure the buffer pointer returned to the caller is
 * null.
 */
int
xfs_attr_get(
	struct xfs_inode	*ip,
	const unsigned char	*name,
	unsigned char		*value,
	unsigned char		**value,
	int			*valuelenp,
	int			flags)
{
@@ -128,6 +147,8 @@ xfs_attr_get(
	uint			lock_mode;
	int			error;

	ASSERT((flags & (ATTR_ALLOC | ATTR_KERNOVAL)) || *value);

	XFS_STATS_INC(ip->i_mount, xs_attr_get);

	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
@@ -137,17 +158,29 @@ xfs_attr_get(
	if (error)
		return error;

	args.value = value;
	args.valuelen = *valuelenp;
	/* Entirely possible to look up a name which doesn't exist */
	args.op_flags = XFS_DA_OP_OKNOENT;
	if (flags & ATTR_ALLOC)
		args.op_flags |= XFS_DA_OP_ALLOCVAL;
	else
		args.value = *value;
	args.valuelen = *valuelenp;

	lock_mode = xfs_ilock_attr_map_shared(ip);
	error = xfs_attr_get_ilocked(ip, &args);
	xfs_iunlock(ip, lock_mode);

	*valuelenp = args.valuelen;
	return error == -EEXIST ? 0 : error;

	/* on error, we have to clean up allocated value buffers */
	if (error) {
		if (flags & ATTR_ALLOC) {
			kmem_free(args.value);
			*value = NULL;
		}
		return error;
	}
	*value = args.value;
	return 0;
}

/*
@@ -768,6 +801,8 @@ xfs_attr_leaf_removename(
 *
 * This leaf block cannot have a "remote" value, we only call this routine
 * if bmap_one_block() says there is only one block (ie: no remote blks).
 *
 * Returns 0 on successful retrieval, otherwise an error.
 */
STATIC int
xfs_attr_leaf_get(xfs_da_args_t *args)
@@ -789,9 +824,6 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
	}
	error = xfs_attr3_leaf_getvalue(bp, args);
	xfs_trans_brelse(args->trans, bp);
	if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) {
		error = xfs_attr_rmtval_get(args);
	}
	return error;
}

@@ -1268,11 +1300,13 @@ xfs_attr_refillstate(xfs_da_state_t *state)
}

/*
 * Look up a filename in a node attribute list.
 * Retrieve the attribute data from a node attribute list.
 *
 * This routine gets called for any attribute fork that has more than one
 * block, ie: both true Btree attr lists and for single-leaf-blocks with
 * "remote" values taking up more blocks.
 *
 * Returns 0 on successful retrieval, otherwise an error.
 */
STATIC int
xfs_attr_node_get(xfs_da_args_t *args)
@@ -1294,24 +1328,21 @@ xfs_attr_node_get(xfs_da_args_t *args)
	error = xfs_da3_node_lookup_int(state, &retval);
	if (error) {
		retval = error;
	} else if (retval == -EEXIST) {
		blk = &state->path.blk[ state->path.active-1 ];
		ASSERT(blk->bp != NULL);
		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
		goto out_release;
	}
	if (retval != -EEXIST)
		goto out_release;

	/*
	 * Get the value, local or "remote"
	 */
	blk = &state->path.blk[state->path.active - 1];
	retval = xfs_attr3_leaf_getvalue(blk->bp, args);
		if (!retval && (args->rmtblkno > 0)
		    && !(args->flags & ATTR_KERNOVAL)) {
			retval = xfs_attr_rmtval_get(args);
		}
	}

	/*
	 * If not in a transaction, we have to release all the buffers.
	 */
out_release:
	for (i = 0; i < state->path.active; i++) {
		xfs_trans_brelse(args->trans, state->path.blk[i].bp);
		state->path.blk[i].bp = NULL;
Loading