Skip to content

Commit

Permalink
Merge tag 'xfs-5.4-merge-7' of git://git.kernel.org/pub/scm/fs/xfs/xf…
Browse files Browse the repository at this point in the history
…s-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
  ...
  • Loading branch information
torvalds committed Sep 19, 2019
2 parents e6bc9de + 14e15f1 commit b41dae0
Show file tree
Hide file tree
Showing 81 changed files with 1,315 additions and 1,089 deletions.
79 changes: 59 additions & 20 deletions fs/xfs/kmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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,
Expand All @@ -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)

/*
* __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.
*/
static void *
__kmem_vmalloc(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;
gfp_t lflags = kmem_flags_convert(flags);

/*
* __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.
*/
if (flags & KM_NOFS)
nofs_flag = memalloc_nofs_save();

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

if (flags & KM_NOFS)
Expand All @@ -58,16 +56,56 @@ 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)
{
int retries = 0;
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,
Expand All @@ -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,
Expand Down
15 changes: 5 additions & 10 deletions fs/xfs/kmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
}
lflags = GFP_KERNEL | __GFP_NOWARN;
if (flags & KM_NOFS)
lflags &= ~__GFP_FS;

/*
* Default page/slab allocator behavior is to retry for ever
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/libxfs/xfs_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 3 additions & 4 deletions fs/xfs/libxfs/xfs_alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
79 changes: 55 additions & 24 deletions fs/xfs/libxfs/xfs_attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -115,19 +118,37 @@ 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)
{
struct xfs_da_args args;
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))
Expand All @@ -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;
}

/*
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}

Expand Down Expand Up @@ -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)
Expand All @@ -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);

/*
* Get the value, local or "remote"
*/
retval = xfs_attr3_leaf_getvalue(blk->bp, args);
if (!retval && (args->rmtblkno > 0)
&& !(args->flags & ATTR_KERNOVAL)) {
retval = xfs_attr_rmtval_get(args);
}
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 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;
Expand Down
6 changes: 4 additions & 2 deletions fs/xfs/libxfs/xfs_attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ struct xfs_attr_list_context;
#define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */

#define ATTR_INCOMPLETE 0x4000 /* [kernel] return INCOMPLETE attr keys */
#define ATTR_ALLOC 0x8000 /* allocate xattr buffer on demand */

#define XFS_ATTR_FLAGS \
{ ATTR_DONTFOLLOW, "DONTFOLLOW" }, \
Expand All @@ -47,7 +48,8 @@ struct xfs_attr_list_context;
{ ATTR_REPLACE, "REPLACE" }, \
{ ATTR_KERNOTIME, "KERNOTIME" }, \
{ ATTR_KERNOVAL, "KERNOVAL" }, \
{ ATTR_INCOMPLETE, "INCOMPLETE" }
{ ATTR_INCOMPLETE, "INCOMPLETE" }, \
{ ATTR_ALLOC, "ALLOC" }

/*
* The maximum size (into the kernel or returned from the kernel) of an
Expand Down Expand Up @@ -143,7 +145,7 @@ int xfs_attr_list_int(struct xfs_attr_list_context *);
int xfs_inode_hasattr(struct xfs_inode *ip);
int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
unsigned char *value, int *valuelenp, int flags);
unsigned char **value, int *valuelenp, int flags);
int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
unsigned char *value, int valuelen, int flags);
int xfs_attr_set_args(struct xfs_da_args *args);
Expand Down
Loading

0 comments on commit b41dae0

Please sign in to comment.