Commit 91f1a956 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull xfs updates from Darrick Wong:
 "In this release we clean out the last of the old 32-bit timestamp
  code, fix a number of bugs and memory corruptions on 32-bit platforms,
  and a refactoring of some of the extended attribute code.

  I think I'll be back next week with some refactoring of how the XFS
  buffer code returns error codes, however I prefer to hold onto that
  for another week to let it soak a while longer

  Summary:

   - Get rid of compat_time_t

   - Convert time_t to time64_t in quota code

   - Remove shadow variables

   - Prevent ATTR_ flag misuse in the attrmulti ioctls

   - Clean out strlen in the attr code

   - Remove some bogus asserts

   - Fix various file size limit calculation errors with 32-bit kernels

   - Pack xfs_dir2_sf_entry_t to fix build errors on arm oabi

   - Fix nowait inode locking calls for directio aio reads

   - Fix memory corruption bugs when invalidating remote xattr value
     buffers

   - Streamline remote attr value removal

   - Make the buffer log format size consistent across platforms

   - Strengthen buffer log format size checking

   - Fix messed up return types of xfs_inode_need_cow

   - Fix some unused variable warnings"

* tag 'xfs-5.6-merge-6' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: (24 commits)
  xfs: remove unused variable 'done'
  xfs: fix uninitialized variable in xfs_attr3_leaf_inactive
  xfs: change return value of xfs_inode_need_cow to int
  xfs: check log iovec size to make sure it's plausibly a buffer log format
  xfs: make struct xfs_buf_log_format have a consistent size
  xfs: complain if anyone tries to create a too-large buffer log item
  xfs: clean up xfs_buf_item_get_format return value
  xfs: streamline xfs_attr3_leaf_inactive
  xfs: fix memory corruption during remote attr value buffer invalidation
  xfs: refactor remote attr value buffer invalidation
  xfs: fix IOCB_NOWAIT handling in xfs_file_dio_aio_read
  xfs: Add __packed to xfs_dir2_sf_entry_t definition
  xfs: fix s_maxbytes computation on 32-bit kernels
  xfs: truncate should remove all blocks, not just to the end of the page cache
  xfs: introduce XFS_MAX_FILEOFF
  xfs: remove bogus assertion when online repair isn't enabled
  xfs: Remove all strlen in all xfs_attr_* functions for attr names.
  xfs: fix misuse of the XFS_ATTR_INCOMPLETE flag
  xfs: also remove cached ACLs when removing the underlying attr
  xfs: reject invalid flags combinations in XFS_IOC_ATTRMULTI_BY_HANDLE
  ...
parents e5da4c93 b3531f5f
...@@ -62,6 +62,7 @@ xfs_attr_args_init( ...@@ -62,6 +62,7 @@ xfs_attr_args_init(
struct xfs_da_args *args, struct xfs_da_args *args,
struct xfs_inode *dp, struct xfs_inode *dp,
const unsigned char *name, const unsigned char *name,
size_t namelen,
int flags) int flags)
{ {
...@@ -74,7 +75,7 @@ xfs_attr_args_init( ...@@ -74,7 +75,7 @@ xfs_attr_args_init(
args->dp = dp; args->dp = dp;
args->flags = flags; args->flags = flags;
args->name = name; args->name = name;
args->namelen = strlen((const char *)name); args->namelen = namelen;
if (args->namelen >= MAXNAMELEN) if (args->namelen >= MAXNAMELEN)
return -EFAULT; /* match IRIX behaviour */ return -EFAULT; /* match IRIX behaviour */
...@@ -139,6 +140,7 @@ int ...@@ -139,6 +140,7 @@ int
xfs_attr_get( xfs_attr_get(
struct xfs_inode *ip, struct xfs_inode *ip,
const unsigned char *name, const unsigned char *name,
size_t namelen,
unsigned char **value, unsigned char **value,
int *valuelenp, int *valuelenp,
int flags) int flags)
...@@ -154,7 +156,7 @@ xfs_attr_get( ...@@ -154,7 +156,7 @@ xfs_attr_get(
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return -EIO; return -EIO;
error = xfs_attr_args_init(&args, ip, name, flags); error = xfs_attr_args_init(&args, ip, name, namelen, flags);
if (error) if (error)
return error; return error;
...@@ -338,6 +340,7 @@ int ...@@ -338,6 +340,7 @@ int
xfs_attr_set( xfs_attr_set(
struct xfs_inode *dp, struct xfs_inode *dp,
const unsigned char *name, const unsigned char *name,
size_t namelen,
unsigned char *value, unsigned char *value,
int valuelen, int valuelen,
int flags) int flags)
...@@ -353,7 +356,7 @@ xfs_attr_set( ...@@ -353,7 +356,7 @@ xfs_attr_set(
if (XFS_FORCED_SHUTDOWN(dp->i_mount)) if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return -EIO; return -EIO;
error = xfs_attr_args_init(&args, dp, name, flags); error = xfs_attr_args_init(&args, dp, name, namelen, flags);
if (error) if (error)
return error; return error;
...@@ -442,6 +445,7 @@ int ...@@ -442,6 +445,7 @@ int
xfs_attr_remove( xfs_attr_remove(
struct xfs_inode *dp, struct xfs_inode *dp,
const unsigned char *name, const unsigned char *name,
size_t namelen,
int flags) int flags)
{ {
struct xfs_mount *mp = dp->i_mount; struct xfs_mount *mp = dp->i_mount;
...@@ -453,7 +457,7 @@ xfs_attr_remove( ...@@ -453,7 +457,7 @@ xfs_attr_remove(
if (XFS_FORCED_SHUTDOWN(dp->i_mount)) if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return -EIO; return -EIO;
error = xfs_attr_args_init(&args, dp, name, flags); error = xfs_attr_args_init(&args, dp, name, namelen, flags);
if (error) if (error)
return error; return error;
...@@ -1007,7 +1011,7 @@ xfs_attr_node_addname( ...@@ -1007,7 +1011,7 @@ xfs_attr_node_addname(
* The INCOMPLETE flag means that we will find the "old" * The INCOMPLETE flag means that we will find the "old"
* attr, not the "new" one. * attr, not the "new" one.
*/ */
args->flags |= XFS_ATTR_INCOMPLETE; args->op_flags |= XFS_DA_OP_INCOMPLETE;
state = xfs_da_state_alloc(); state = xfs_da_state_alloc();
state->args = args; state->args = args;
state->mp = mp; state->mp = mp;
......
...@@ -26,7 +26,7 @@ struct xfs_attr_list_context; ...@@ -26,7 +26,7 @@ struct xfs_attr_list_context;
*========================================================================*/ *========================================================================*/
#define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */ #define ATTR_DONTFOLLOW 0x0001 /* -- ignored, from IRIX -- */
#define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */ #define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */
#define ATTR_TRUST 0x0004 /* -- unused, from IRIX -- */ #define ATTR_TRUST 0x0004 /* -- unused, from IRIX -- */
#define ATTR_SECURE 0x0008 /* use attrs in security namespace */ #define ATTR_SECURE 0x0008 /* use attrs in security namespace */
...@@ -37,7 +37,10 @@ struct xfs_attr_list_context; ...@@ -37,7 +37,10 @@ struct xfs_attr_list_context;
#define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */ #define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */
#define ATTR_INCOMPLETE 0x4000 /* [kernel] return INCOMPLETE attr keys */ #define ATTR_INCOMPLETE 0x4000 /* [kernel] return INCOMPLETE attr keys */
#define ATTR_ALLOC 0x8000 /* allocate xattr buffer on demand */ #define ATTR_ALLOC 0x8000 /* [kernel] allocate xattr buffer on demand */
#define ATTR_KERNEL_FLAGS \
(ATTR_KERNOTIME | ATTR_KERNOVAL | ATTR_INCOMPLETE | ATTR_ALLOC)
#define XFS_ATTR_FLAGS \ #define XFS_ATTR_FLAGS \
{ ATTR_DONTFOLLOW, "DONTFOLLOW" }, \ { ATTR_DONTFOLLOW, "DONTFOLLOW" }, \
...@@ -145,11 +148,13 @@ int xfs_attr_list_int(struct xfs_attr_list_context *); ...@@ -145,11 +148,13 @@ int xfs_attr_list_int(struct xfs_attr_list_context *);
int xfs_inode_hasattr(struct xfs_inode *ip); 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_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name, int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
unsigned char **value, int *valuelenp, int flags); size_t namelen, unsigned char **value, int *valuelenp,
int flags);
int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name, int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
unsigned char *value, int valuelen, int flags); size_t namelen, unsigned char *value, int valuelen, int flags);
int xfs_attr_set_args(struct xfs_da_args *args); int xfs_attr_set_args(struct xfs_da_args *args);
int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags); int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
size_t namelen, int flags);
int xfs_attr_remove_args(struct xfs_da_args *args); int xfs_attr_remove_args(struct xfs_da_args *args);
int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize, int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
int flags, struct attrlist_cursor_kern *cursor); int flags, struct attrlist_cursor_kern *cursor);
......
...@@ -2403,8 +2403,8 @@ xfs_attr3_leaf_lookup_int( ...@@ -2403,8 +2403,8 @@ xfs_attr3_leaf_lookup_int(
* If we are looking for INCOMPLETE entries, show only those. * If we are looking for INCOMPLETE entries, show only those.
* If we are looking for complete entries, show only those. * If we are looking for complete entries, show only those.
*/ */
if ((args->flags & XFS_ATTR_INCOMPLETE) != if (!!(args->op_flags & XFS_DA_OP_INCOMPLETE) !=
(entry->flags & XFS_ATTR_INCOMPLETE)) { !!(entry->flags & XFS_ATTR_INCOMPLETE)) {
continue; continue;
} }
if (entry->flags & XFS_ATTR_LOCAL) { if (entry->flags & XFS_ATTR_LOCAL) {
......
...@@ -39,15 +39,6 @@ struct xfs_attr3_icleaf_hdr { ...@@ -39,15 +39,6 @@ struct xfs_attr3_icleaf_hdr {
} freemap[XFS_ATTR_LEAF_MAPSIZE]; } freemap[XFS_ATTR_LEAF_MAPSIZE];
}; };
/*
* Used to keep a list of "remote value" extents when unlinking an inode.
*/
typedef struct xfs_attr_inactive_list {
xfs_dablk_t valueblk; /* block number of value bytes */
int valuelen; /* number of bytes in value */
} xfs_attr_inactive_list_t;
/*======================================================================== /*========================================================================
* Function prototypes for the kernel. * Function prototypes for the kernel.
*========================================================================*/ *========================================================================*/
......
...@@ -25,6 +25,23 @@ ...@@ -25,6 +25,23 @@
#define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ #define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */
/*
* Remote Attribute Values
* =======================
*
* Remote extended attribute values are conceptually simple -- they're written
* to data blocks mapped by an inode's attribute fork, and they have an upper
* size limit of 64k. Setting a value does not involve the XFS log.
*
* However, on a v5 filesystem, maximally sized remote attr values require one
* block more than 64k worth of space to hold both the remote attribute value
* header (64 bytes). On a 4k block filesystem this results in a 68k buffer;
* on a 64k block filesystem, this would be a 128k buffer. Note that the log
* format can only handle a dirty buffer of XFS_MAX_BLOCKSIZE length (64k).
* Therefore, we /must/ ensure that remote attribute value buffers never touch
* the logging system and therefore never have a log item.
*/
/* /*
* Each contiguous block has a header, so it is not just a simple attribute * Each contiguous block has a header, so it is not just a simple attribute
* length to FSB conversion. * length to FSB conversion.
...@@ -401,17 +418,25 @@ xfs_attr_rmtval_get( ...@@ -401,17 +418,25 @@ xfs_attr_rmtval_get(
(map[i].br_startblock != HOLESTARTBLOCK)); (map[i].br_startblock != HOLESTARTBLOCK));
dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
error = xfs_trans_read_buf(mp, args->trans, bp = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt, 0,
mp->m_ddev_targp, &xfs_attr3_rmt_buf_ops);
dblkno, dblkcnt, 0, &bp, if (!bp)
&xfs_attr3_rmt_buf_ops); return -ENOMEM;
if (error) error = bp->b_error;
if (error) {
xfs_buf_ioerror_alert(bp, __func__);
xfs_buf_relse(bp);
/* bad CRC means corrupted metadata */
if (error == -EFSBADCRC)
error = -EFSCORRUPTED;
return error; return error;
}
error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino, error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
&offset, &valuelen, &offset, &valuelen,
&dst); &dst);
xfs_trans_brelse(args->trans, bp); xfs_buf_relse(bp);
if (error) if (error)
return error; return error;
...@@ -552,6 +577,33 @@ xfs_attr_rmtval_set( ...@@ -552,6 +577,33 @@ xfs_attr_rmtval_set(
return 0; return 0;
} }
/* Mark stale any incore buffers for the remote value. */
int
xfs_attr_rmtval_stale(
struct xfs_inode *ip,
struct xfs_bmbt_irec *map,
xfs_buf_flags_t incore_flags)
{
struct xfs_mount *mp = ip->i_mount;
struct xfs_buf *bp;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
if (XFS_IS_CORRUPT(mp, map->br_startblock == DELAYSTARTBLOCK) ||
XFS_IS_CORRUPT(mp, map->br_startblock == HOLESTARTBLOCK))
return -EFSCORRUPTED;
bp = xfs_buf_incore(mp->m_ddev_targp,
XFS_FSB_TO_DADDR(mp, map->br_startblock),
XFS_FSB_TO_BB(mp, map->br_blockcount), incore_flags);
if (bp) {
xfs_buf_stale(bp);
xfs_buf_relse(bp);
}
return 0;
}
/* /*
* Remove the value associated with an attribute by deleting the * Remove the value associated with an attribute by deleting the
* out-of-line buffer that it is stored on. * out-of-line buffer that it is stored on.
...@@ -560,7 +612,6 @@ int ...@@ -560,7 +612,6 @@ int
xfs_attr_rmtval_remove( xfs_attr_rmtval_remove(
struct xfs_da_args *args) struct xfs_da_args *args)
{ {
struct xfs_mount *mp = args->dp->i_mount;
xfs_dablk_t lblkno; xfs_dablk_t lblkno;
int blkcnt; int blkcnt;
int error; int error;
...@@ -575,9 +626,6 @@ xfs_attr_rmtval_remove( ...@@ -575,9 +626,6 @@ xfs_attr_rmtval_remove(
blkcnt = args->rmtblkcnt; blkcnt = args->rmtblkcnt;
while (blkcnt > 0) { while (blkcnt > 0) {
struct xfs_bmbt_irec map; struct xfs_bmbt_irec map;
struct xfs_buf *bp;
xfs_daddr_t dblkno;
int dblkcnt;
int nmap; int nmap;
/* /*
...@@ -588,22 +636,11 @@ xfs_attr_rmtval_remove( ...@@ -588,22 +636,11 @@ xfs_attr_rmtval_remove(
blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK); blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
if (error) if (error)
return error; return error;
ASSERT(nmap == 1); if (XFS_IS_CORRUPT(args->dp->i_mount, nmap != 1))
ASSERT((map.br_startblock != DELAYSTARTBLOCK) && return -EFSCORRUPTED;
(map.br_startblock != HOLESTARTBLOCK)); error = xfs_attr_rmtval_stale(args->dp, &map, XBF_TRYLOCK);
if (error)
dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), return error;
dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
/*
* If the "remote" value is in the cache, remove it.
*/
bp = xfs_buf_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK);
if (bp) {
xfs_buf_stale(bp);
xfs_buf_relse(bp);
bp = NULL;
}
lblkno += map.br_blockcount; lblkno += map.br_blockcount;
blkcnt -= map.br_blockcount; blkcnt -= map.br_blockcount;
......
...@@ -11,5 +11,7 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen); ...@@ -11,5 +11,7 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
int xfs_attr_rmtval_get(struct xfs_da_args *args); int xfs_attr_rmtval_get(struct xfs_da_args *args);
int xfs_attr_rmtval_set(struct xfs_da_args *args); int xfs_attr_rmtval_set(struct xfs_da_args *args);
int xfs_attr_rmtval_remove(struct xfs_da_args *args); int xfs_attr_rmtval_remove(struct xfs_da_args *args);
int xfs_attr_rmtval_stale(struct xfs_inode *ip, struct xfs_bmbt_irec *map,
xfs_buf_flags_t incore_flags);
#endif /* __XFS_ATTR_REMOTE_H__ */ #endif /* __XFS_ATTR_REMOTE_H__ */
...@@ -2389,8 +2389,6 @@ xfs_btree_lshift( ...@@ -2389,8 +2389,6 @@ xfs_btree_lshift(
XFS_BTREE_STATS_ADD(cur, moves, rrecs - 1); XFS_BTREE_STATS_ADD(cur, moves, rrecs - 1);
if (level > 0) { if (level > 0) {
/* It's a nonleaf. operate on keys and ptrs */ /* It's a nonleaf. operate on keys and ptrs */
int i; /* loop index */
for (i = 0; i < rrecs; i++) { for (i = 0; i < rrecs; i++) {
error = xfs_btree_debug_check_ptr(cur, rpp, i + 1, level); error = xfs_btree_debug_check_ptr(cur, rpp, i + 1, level);
if (error) if (error)
......
...@@ -89,6 +89,7 @@ typedef struct xfs_da_args { ...@@ -89,6 +89,7 @@ typedef struct xfs_da_args {
#define XFS_DA_OP_OKNOENT 0x0008 /* lookup/add op, ENOENT ok, else die */ #define XFS_DA_OP_OKNOENT 0x0008 /* lookup/add op, ENOENT ok, else die */
#define XFS_DA_OP_CILOOKUP 0x0010 /* lookup to return CI name if found */ #define XFS_DA_OP_CILOOKUP 0x0010 /* lookup to return CI name if found */
#define XFS_DA_OP_ALLOCVAL 0x0020 /* lookup to alloc buffer if found */ #define XFS_DA_OP_ALLOCVAL 0x0020 /* lookup to alloc buffer if found */
#define XFS_DA_OP_INCOMPLETE 0x0040 /* lookup INCOMPLETE attr keys */
#define XFS_DA_OP_FLAGS \ #define XFS_DA_OP_FLAGS \
{ XFS_DA_OP_JUSTCHECK, "JUSTCHECK" }, \ { XFS_DA_OP_JUSTCHECK, "JUSTCHECK" }, \
...@@ -96,7 +97,8 @@ typedef struct xfs_da_args { ...@@ -96,7 +97,8 @@ typedef struct xfs_da_args {
{ XFS_DA_OP_ADDNAME, "ADDNAME" }, \ { XFS_DA_OP_ADDNAME, "ADDNAME" }, \
{ XFS_DA_OP_OKNOENT, "OKNOENT" }, \ { XFS_DA_OP_OKNOENT, "OKNOENT" }, \
{ XFS_DA_OP_CILOOKUP, "CILOOKUP" }, \ { XFS_DA_OP_CILOOKUP, "CILOOKUP" }, \
{ XFS_DA_OP_ALLOCVAL, "ALLOCVAL" } { XFS_DA_OP_ALLOCVAL, "ALLOCVAL" }, \
{ XFS_DA_OP_INCOMPLETE, "INCOMPLETE" }
/* /*
* Storage for holding state during Btree searches and split/join ops. * Storage for holding state during Btree searches and split/join ops.
......
...@@ -217,7 +217,7 @@ typedef struct xfs_dir2_sf_entry { ...@@ -217,7 +217,7 @@ typedef struct xfs_dir2_sf_entry {
* A 64-bit or 32-bit inode number follows here, at a variable offset * A 64-bit or 32-bit inode number follows here, at a variable offset
* after the name. * after the name.
*/ */
} xfs_dir2_sf_entry_t; } __packed xfs_dir2_sf_entry_t;
static inline int xfs_dir2_sf_hdr_size(int i8count) static inline int xfs_dir2_sf_hdr_size(int i8count)
{ {
...@@ -683,8 +683,6 @@ struct xfs_attr3_leafblock { ...@@ -683,8 +683,6 @@ struct xfs_attr3_leafblock {
/* /*
* Flags used in the leaf_entry[i].flags field. * Flags used in the leaf_entry[i].flags field.
* NOTE: the INCOMPLETE bit must not collide with the flags bits specified
* on the system call, they are "or"ed together for various operations.
*/ */
#define XFS_ATTR_LOCAL_BIT 0 /* attr is stored locally */ #define XFS_ATTR_LOCAL_BIT 0 /* attr is stored locally */
#define XFS_ATTR_ROOT_BIT 1 /* limit access to trusted attrs */ #define XFS_ATTR_ROOT_BIT 1 /* limit access to trusted attrs */
......
...@@ -1540,6 +1540,13 @@ typedef struct xfs_bmdr_block { ...@@ -1540,6 +1540,13 @@ typedef struct xfs_bmdr_block {
#define BMBT_BLOCKCOUNT_BITLEN 21 #define BMBT_BLOCKCOUNT_BITLEN 21
#define BMBT_STARTOFF_MASK ((1ULL << BMBT_STARTOFF_BITLEN) - 1) #define BMBT_STARTOFF_MASK ((1ULL << BMBT_STARTOFF_BITLEN) - 1)
#define BMBT_BLOCKCOUNT_MASK ((1ULL << BMBT_BLOCKCOUNT_BITLEN) - 1)
/*
* bmbt records have a file offset (block) field that is 54 bits wide, so this
* is the largest xfs_fileoff_t that we ever expect to see.
*/
#define XFS_MAX_FILEOFF (BMBT_STARTOFF_MASK + BMBT_BLOCKCOUNT_MASK)
typedef struct xfs_bmbt_rec { typedef struct xfs_bmbt_rec {
__be64 l0, l1; __be64 l0, l1;
......
...@@ -462,11 +462,20 @@ static inline uint xfs_log_dinode_size(int version) ...@@ -462,11 +462,20 @@ static inline uint xfs_log_dinode_size(int version)
#define XFS_BLF_GDQUOT_BUF (1<<4) #define XFS_BLF_GDQUOT_BUF (1<<4)
/* /*
* This is the structure used to lay out a buf log item in the * This is the structure used to lay out a buf log item in the log. The data
* log. The data map describes which 128 byte chunks of the buffer * map describes which 128 byte chunks of the buffer have been logged.
* have been logged. *
*/ * The placement of blf_map_size causes blf_data_map to start at an odd
#define XFS_BLF_DATAMAP_SIZE ((XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK) / NBWORD) * multiple of sizeof(unsigned int) offset within the struct. Because the data
* bitmap size will always be an even number, the end of the data_map (and
* therefore the structure) will also be at an odd multiple of sizeof(unsigned
* int). Some 64-bit compilers will insert padding at the end of the struct to
* ensure 64-bit alignment of blf_blkno, but 32-bit ones will not. Therefore,
* XFS_BLF_DATAMAP_SIZE must be an odd number to make the padding explicit and
* keep the structure size consistent between 32-bit and 64-bit platforms.
*/
#define __XFS_BLF_DATAMAP_SIZE ((XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK) / NBWORD)
#define XFS_BLF_DATAMAP_SIZE (__XFS_BLF_DATAMAP_SIZE + 1)
typedef struct xfs_buf_log_format { typedef struct xfs_buf_log_format {
unsigned short blf_type; /* buf log item type indicator */ unsigned short blf_type; /* buf log item type indicator */
......
...@@ -75,7 +75,6 @@ static inline xfs_extlen_t ...@@ -75,7 +75,6 @@ static inline xfs_extlen_t
xrep_calc_ag_resblks( xrep_calc_ag_resblks(
struct xfs_scrub *sc) struct xfs_scrub *sc)
{ {
ASSERT(!(sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR));
return 0; return 0;
} }
......
...@@ -145,7 +145,8 @@ xfs_get_acl(struct inode *inode, int type) ...@@ -145,7 +145,8 @@ xfs_get_acl(struct inode *inode, int type)
* go out to the disk. * go out to the disk.
*/ */
len = XFS_ACL_MAX_SIZE(ip->i_mount); len = XFS_ACL_MAX_SIZE(ip->i_mount);
error = xfs_attr_get(ip, ea_name, (unsigned char **)&xfs_acl, &len, error = xfs_attr_get(ip, ea_name, strlen(ea_name),
(unsigned char **)&xfs_acl, &len,
ATTR_ALLOC | ATTR_ROOT); ATTR_ALLOC | ATTR_ROOT);
if (error) { if (error) {
/* /*
...@@ -196,15 +197,17 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) ...@@ -196,15 +197,17 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
len -= sizeof(struct xfs_acl_entry) * len -= sizeof(struct xfs_acl_entry) *
(XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count); (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
error = xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl, error = xfs_attr_set(ip, ea_name, strlen(ea_name),
len, ATTR_ROOT); (unsigned char *)xfs_acl, len, ATTR_ROOT);
kmem_free(xfs_acl); kmem_free(xfs_acl);
} else { } else {
/* /*
* A NULL ACL argument means we want to remove the ACL. * A NULL ACL argument means we want to remove the ACL.
*/ */
error = xfs_attr_remove(ip, ea_name, ATTR_ROOT); error = xfs_attr_remove(ip, ea_name,
strlen(ea_name),
ATTR_ROOT);
/* /*
* If the attribute didn't exist to start with that's fine. * If the attribute didn't exist to start with that's fine.
......
...@@ -25,22 +25,18 @@ ...@@ -25,22 +25,18 @@
#include "xfs_error.h" #include "xfs_error.h"
/* /*
* Look at all the extents for this logical region, * Invalidate any incore buffers associated with this remote attribute value
* invalidate any buffers that are incore/in transactions. * extent. We never log remote attribute value buffers, which means that they
* won't be attached to a transaction and are therefore safe to mark stale.
* The actual bunmapi will be taken care of later.
*/ */
STATIC int STATIC int
xfs_attr3_leaf_freextent( xfs_attr3_rmt_stale(
struct xfs_trans **trans,
struct xfs_inode *dp, struct xfs_inode *dp,
xfs_dablk_t blkno, xfs_dablk_t blkno,
int blkcnt) int blkcnt)
{ {
struct xfs_bmbt_irec map; struct xfs_bmbt_irec map;
struct xfs_buf *bp;
xfs_dablk_t tblkno;
xfs_daddr_t dblkno;
int tblkcnt;
int dblkcnt;
int nmap; int nmap;
int error; int error;
...@@ -48,47 +44,29 @@ xfs_attr3_leaf_freextent( ...@@ -48,47 +44,29 @@ xfs_attr3_leaf_freextent(
* Roll through the "value", invalidating the attribute value's * Roll through the "value", invalidating the attribute value's
* blocks. * blocks.
*/ */
tblkno = blkno; while (blkcnt > 0) {
tblkcnt = blkcnt;
while (tblkcnt > 0) {
/* /*
* Try to remember where we decided to put the value. * Try to remember where we decided to put the value.
*/ */
nmap = 1; nmap = 1;
error = xfs_bmapi_read(dp, (xfs_fileoff_t)tblkno, tblkcnt, error = xfs_bmapi_read(dp, (xfs_fileoff_t)blkno, blkcnt,
&map, &nmap, XFS_BMAPI_ATTRFORK); &map, &nmap, XFS_BMAPI_ATTRFORK);
if (error) { if (error)
return error; return error;
} if (XFS_IS_CORRUPT(dp->i_mount, nmap != 1))
ASSERT(nmap == 1); return -EFSCORRUPTED;
ASSERT(map.br_startblock != DELAYSTARTBLOCK);
/* /*
* If it's a hole, these are already unmapped * Mark any incore buffers for the remote value as stale. We
* so there's nothing to invalidate. * never log remote attr value buffers, so the buffer should be
* easy to kill.
*/ */
if (map.br_startblock != HOLESTARTBLOCK) { error = xfs_attr_rmtval_stale(dp, &map, 0);
if (error)
dblkno = XFS_FSB_TO_DADDR(dp->i_mount, return error;
map.br_startblock);
dblkcnt = XFS_FSB_TO_BB(dp->i_mount,
map.br_blockcount);
bp = xfs_trans_get_buf(*trans,
dp->i_mount->m_ddev_targp,
dblkno, dblkcnt, 0);
if (!bp)
return -ENOMEM;
xfs_trans_binval(*trans, bp);
/*
* Roll to next transaction.
*/
error = xfs_trans_roll_inode(trans, dp);
if (error)
return error;
}
tblkno += map.br_blockcount; blkno += map.br_blockcount;
tblkcnt -= map.br_blockcount; blkcnt -= map.br_blockcount;
} }
return 0; return 0;
...@@ -102,86 +80,45 @@ xfs_attr3_leaf_freextent( ...@@ -102,86 +80,45 @@ xfs_attr3_leaf_freextent(
*/ */
STATIC int STATIC int
xfs_attr3_leaf_inactive( xfs_attr3_leaf_inactive(
struct xfs_trans **trans, struct xfs_trans **trans,
struct xfs_inode *dp, struct xfs_inode *dp,
struct xfs_buf *bp) struct xfs_buf *bp)
{ {
struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr ichdr;
struct xfs_attr3_icleaf_hdr ichdr; struct xfs_mount *mp = bp->b_mount;
struct xfs_attr_leaf_entry *entry; struct xfs_attr_leafblock *leaf = bp->b_addr;
struct xfs_attr_leaf_entry *entry;
struct xfs_attr_leaf_name_remote *name_rmt; struct xfs_attr_leaf_name_remote *name_rmt;
struct xfs_attr_inactive_list *list; int error = 0;
struct xfs_attr_inactive_list *lp; int i;
int error;
int count;
int size;
int tmp;
int i;
struct xfs_mount *mp = bp->b_mount;
leaf = bp->b_addr;
xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf); xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
/* /*
* Count the number of "remote" value extents. * Find the remote value extents for this leaf and invalidate their
* incore buffers.
*/ */
count = 0;
entry = xfs_attr3_leaf_entryp(leaf); entry = xfs_attr3_leaf_entryp(leaf);
for (i = 0; i < ichdr.count; entry++, i++) { for (i = 0; i < ichdr.count; entry++, i++) {
if (be16_to_cpu(entry->nameidx) && int blkcnt;
((entry->flags & XFS_ATTR_LOCAL) == 0)) {
name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
if (name_rmt->valueblk)
count++;
}
}
/* if (!entry->nameidx || (entry->flags & XFS_ATTR_LOCAL))
* If there are no "remote" values, we're done. continue;
*/
if (count == 0) {
xfs_trans_brelse(*trans, bp);
return 0;
}
/*
* Allocate storage for a list of all the "remote" value extents.
*/
size = count * sizeof(xfs_attr_inactive_list_t);
list = kmem_alloc(size, 0);
/*
* Identify each of the "remote" value extents.
*/
lp = list;
entry = xfs_attr3_leaf_entryp(leaf);
for (i = 0; i < ichdr.count; entry++, i++) {
if (be16_to_cpu(entry->nameidx) &&
((entry->flags & XFS_ATTR_LOCAL) == 0)) {
name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
if (name_rmt->valueblk) {
lp->valueblk = be32_to_cpu(name_rmt->valueblk);
lp->valuelen = xfs_attr3_rmt_blocks(dp->i_mount,
be32_to_cpu(name_rmt->valuelen));
lp++;
}
}
}
xfs_trans_brelse(*trans, bp); /* unlock for trans. in freextent() */
/* name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
* Invalidate each of the "remote" value extents. if (!name_rmt->valueblk)
*/ continue;
error = 0;
for (lp = list, i = 0; i < count; i++, lp++) {
tmp = xfs_attr3_leaf_freextent(trans, dp,
lp->valueblk, lp->valuelen);
if (error == 0) blkcnt = xfs_attr3_rmt_blocks(dp->i_mount,
error = tmp; /* save only the 1st errno */ be32_to_cpu(name_rmt->valuelen));
error = xfs_attr3_rmt_stale(dp,
be32_to_cpu(name_rmt->valueblk), blkcnt);
if (error)
goto err;
} }
kmem_free(list); xfs_trans_brelse(*trans, bp);
err:
return error; return error;
} }
......
...@@ -27,6 +27,23 @@ static inline struct xfs_buf_log_item *BUF_ITEM(struct xfs_log_item *lip) ...@@ -27,6 +27,23 @@ static inline struct xfs_buf_log_item *BUF_ITEM(struct xfs_log_item *lip)
STATIC void xfs_buf_do_callbacks(struct xfs_buf *bp); STATIC void xfs_buf_do_callbacks(struct xfs_buf *bp);
/* Is this log iovec plausibly large enough to contain the buffer log format? */
bool
xfs_buf_log_check_iovec(
struct xfs_log_iovec *iovec)
{
struct xfs_buf_log_format *blfp = iovec->i_addr;
char *bmp_end;
char *item_end;
if (offsetof(struct xfs_buf_log_format, blf_data_map) > iovec->i_len)
return false;
item_end = (char *)iovec->i_addr + iovec->i_len;
bmp_end = (char *)&blfp->blf_data_map[blfp->blf_map_size];
return bmp_end <= item_end;
}
static inline int static inline int
xfs_buf_log_format_size( xfs_buf_log_format_size(
struct xfs_buf_log_format *blfp) struct xfs_buf_log_format *blfp)
...@@ -688,7 +705,7 @@ static const struct xfs_item_ops xfs_buf_item_ops = { ...@@ -688,7 +705,7 @@ static const struct xfs_item_ops xfs_buf_item_ops = {
.iop_push = xfs_buf_item_push, .iop_push = xfs_buf_item_push,
}; };
STATIC int STATIC void
xfs_buf_item_get_format( xfs_buf_item_get_format(
struct xfs_buf_log_item *bip, struct xfs_buf_log_item *bip,
int count) int count)
...@@ -698,14 +715,11 @@ xfs_buf_item_get_format( ...@@ -698,14 +715,11 @@ xfs_buf_item_get_format(
if (count == 1) { if (count == 1) {
bip->bli_formats = &bip->__bli_format; bip->bli_formats = &bip->__bli_format;
return 0; return;
} }
bip->bli_formats = kmem_zalloc(count * sizeof(struct xfs_buf_log_format), bip->bli_formats = kmem_zalloc(count * sizeof(struct xfs_buf_log_format),
0); 0);
if (!bip->bli_formats)
return -ENOMEM;
return 0;
} }
STATIC void STATIC void
...@@ -731,7 +745,6 @@ xfs_buf_item_init( ...@@ -731,7 +745,6 @@ xfs_buf_item_init(
struct xfs_buf_log_item *bip = bp->b_log_item; struct xfs_buf_log_item *bip = bp->b_log_item;
int chunks; int chunks;
int map_size; int map_size;
int error;
int i; int i;
/* /*
...@@ -760,19 +773,22 @@ xfs_buf_item_init( ...@@ -760,19 +773,22 @@ xfs_buf_item_init(
* Discontiguous buffer support follows the layout of the underlying * Discontiguous buffer support follows the layout of the underlying
* buffer. This makes the implementation as simple as possible. * buffer. This makes the implementation as simple as possible.
*/ */
error = xfs_buf_item_get_format(bip, bp->b_map_count); xfs_buf_item_get_format(bip, bp->b_map_count);
ASSERT(error == 0);
if (error) { /* to stop gcc throwing set-but-unused warnings */
kmem_cache_free(xfs_buf_item_zone, bip);
return error;
}
for (i = 0; i < bip->bli_format_count; i++) { for (i = 0; i < bip->bli_format_count; i++) {
chunks = DIV_ROUND_UP(BBTOB(bp->b_maps[i].bm_len), chunks = DIV_ROUND_UP(BBTOB(bp->b_maps[i].bm_len),
XFS_BLF_CHUNK); XFS_BLF_CHUNK);
map_size = DIV_ROUND_UP(chunks, NBWORD); map_size = DIV_ROUND_UP(chunks, NBWORD);
if (map_size > XFS_BLF_DATAMAP_SIZE) {
kmem_cache_free(xfs_buf_item_zone, bip);
xfs_err(mp,
"buffer item dirty bitmap (%u uints) too small to reflect %u bytes!",
map_size,
BBTOB(bp->b_maps[i].bm_len));
return -EFSCORRUPTED;
}
bip->bli_formats[i].blf_type = XFS_LI_BUF; bip->bli_formats[i].blf_type = XFS_LI_BUF;
bip->bli_formats[i].blf_blkno = bp->b_maps[i].bm_bn; bip->bli_formats[i].blf_blkno = bp->b_maps[i].bm_bn;
bip->bli_formats[i].blf_len = bp->b_maps[i].bm_len; bip->bli_formats[i].blf_len = bp->b_maps[i].bm_len;
...@@ -805,6 +821,9 @@ xfs_buf_item_log_segment( ...@@ -805,6 +821,9 @@ xfs_buf_item_log_segment(
uint end_bit; uint end_bit;
uint mask; uint mask;
ASSERT(first < XFS_BLF_DATAMAP_SIZE * XFS_BLF_CHUNK * NBWORD);
ASSERT(last < XFS_BLF_DATAMAP_SIZE * XFS_BLF_CHUNK * NBWORD);
/* /*
* Convert byte offsets to bit numbers. * Convert byte offsets to bit numbers.
*/ */
......
...@@ -61,6 +61,7 @@ void xfs_buf_iodone_callbacks(struct xfs_buf *); ...@@ -61,6 +61,7 @@ void xfs_buf_iodone_callbacks(struct xfs_buf *);
void xfs_buf_iodone(struct xfs_buf *, struct xfs_log_item *); void xfs_buf_iodone(struct xfs_buf *, struct xfs_log_item *);
bool xfs_buf_resubmit_failed_buffers(struct xfs_buf *, bool xfs_buf_resubmit_failed_buffers(struct xfs_buf *,
struct list_head *); struct list_head *);
bool xfs_buf_log_check_iovec(struct xfs_log_iovec *iovec);
extern kmem_zone_t *xfs_buf_item_zone; extern kmem_zone_t *xfs_buf_item_zone;
......
...@@ -137,7 +137,7 @@ xfs_qm_adjust_dqtimers( ...@@ -137,7 +137,7 @@ xfs_qm_adjust_dqtimers(
(d->d_blk_hardlimit && (d->d_blk_hardlimit &&
(be64_to_cpu(d->d_bcount) > (be64_to_cpu(d->d_bcount) >
be64_to_cpu(d->d_blk_hardlimit)))) { be64_to_cpu(d->d_blk_hardlimit)))) {
d->d_btimer = cpu_to_be32(get_seconds() + d->d_btimer = cpu_to_be32(ktime_get_real_seconds() +
mp->m_quotainfo->qi_btimelimit); mp->m_quotainfo->qi_btimelimit);
} else { } else {
d->d_bwarns = 0; d->d_bwarns = 0;
...@@ -160,7 +160,7 @@ xfs_qm_adjust_dqtimers( ...@@ -160,7 +160,7 @@ xfs_qm_adjust_dqtimers(
(d->d_ino_hardlimit && (d->d_ino_hardlimit &&
(be64_to_cpu(d->d_icount) > (be64_to_cpu(d->d_icount) >
be64_to_cpu(d->d_ino_hardlimit)))) { be64_to_cpu(d->d_ino_hardlimit)))) {
d->d_itimer = cpu_to_be32(get_seconds() + d->d_itimer = cpu_to_be32(ktime_get_real_seconds() +
mp->m_quotainfo->qi_itimelimit); mp->m_quotainfo->qi_itimelimit);
} else { } else {
d->d_iwarns = 0; d->d_iwarns = 0;
...@@ -183,7 +183,7 @@ xfs_qm_adjust_dqtimers( ...@@ -183,7 +183,7 @@ xfs_qm_adjust_dqtimers(
(d->d_rtb_hardlimit && (d->d_rtb_hardlimit &&
(be64_to_cpu(d->d_rtbcount) > (be64_to_cpu(d->d_rtbcount) >
be64_to_cpu(d->d_rtb_hardlimit)))) { be64_to_cpu(d->d_rtb_hardlimit)))) {
d->d_rtbtimer = cpu_to_be32(get_seconds() + d->d_rtbtimer = cpu_to_be32(ktime_get_real_seconds() +
mp->m_quotainfo->qi_rtbtimelimit); mp->m_quotainfo->qi_rtbtimelimit);
} else { } else {
d->d_rtbwarns = 0; d->d_rtbwarns = 0;
......
...@@ -187,7 +187,12 @@ xfs_file_dio_aio_read( ...@@ -187,7 +187,12 @@ xfs_file_dio_aio_read(
file_accessed(iocb->ki_filp); file_accessed(iocb->ki_filp);
xfs_ilock(ip, XFS_IOLOCK_SHARED); if (iocb->ki_flags & IOCB_NOWAIT) {
if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED))
return -EAGAIN;
} else {
xfs_ilock(ip, XFS_IOLOCK_SHARED);
}
ret = iomap_dio_rw(iocb, to, &xfs_read_iomap_ops, NULL, ret = iomap_dio_rw(iocb, to, &xfs_read_iomap_ops, NULL,
is_sync_kiocb(iocb)); is_sync_kiocb(iocb));
xfs_iunlock(ip, XFS_IOLOCK_SHARED); xfs_iunlock(ip, XFS_IOLOCK_SHARED);
......
...@@ -1518,10 +1518,8 @@ xfs_itruncate_extents_flags( ...@@ -1518,10 +1518,8 @@ xfs_itruncate_extents_flags(
struct xfs_mount *mp = ip->i_mount; struct xfs_mount *mp = ip->i_mount;
struct xfs_trans *tp = *tpp; struct xfs_trans *tp = *tpp;
xfs_fileoff_t first_unmap_block; xfs_fileoff_t first_unmap_block;
xfs_fileoff_t last_block;
xfs_filblks_t unmap_len; xfs_filblks_t unmap_len;
int error = 0; int error = 0;
int done = 0;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ASSERT(!atomic_read(&VFS_I(ip)->i_count) || ASSERT(!atomic_read(&VFS_I(ip)->i_count) ||
...@@ -1541,21 +1539,22 @@ xfs_itruncate_extents_flags( ...@@ -1541,21 +1539,22 @@ xfs_itruncate_extents_flags(
* the end of the file (in a crash where the space is allocated * the end of the file (in a crash where the space is allocated
* but the inode size is not yet updated), simply remove any * but the inode size is not yet updated), simply remove any
* blocks which show up between the new EOF and the maximum * blocks which show up between the new EOF and the maximum
* possible file size. If the first block to be removed is * possible file size.
* beyond the maximum file size (ie it is the same as last_block), *
* then there is nothing to do. * We have to free all the blocks to the bmbt maximum offset, even if
* the page cache can't scale that far.
*/ */
first_unmap_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size); first_unmap_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size);
last_block = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes); if (first_unmap_block >= XFS_MAX_FILEOFF) {
if (first_unmap_block == last_block) WARN_ON_ONCE(first_unmap_block > XFS_MAX_FILEOFF);
return 0; return 0;
}
ASSERT(first_unmap_block < last_block); unmap_len = XFS_MAX_FILEOFF - first_unmap_block + 1;
unmap_len = last_block - first_unmap_block + 1; while (unmap_len > 0) {
while (!done) {
ASSERT(tp->t_firstblock == NULLFSBLOCK); ASSERT(tp->t_firstblock == NULLFSBLOCK);
error = xfs_bunmapi(tp, ip, first_unmap_block, unmap_len, flags, error = __xfs_bunmapi(tp, ip, first_unmap_block, &unmap_len,
XFS_ITRUNC_MAX_EXTENTS, &done); flags, XFS_ITRUNC_MAX_EXTENTS);
if (error) if (error)
goto out; goto out;
...@@ -1575,7 +1574,7 @@ xfs_itruncate_extents_flags( ...@@ -1575,7 +1574,7 @@ xfs_itruncate_extents_flags(
if (whichfork == XFS_DATA_FORK) { if (whichfork == XFS_DATA_FORK) {
/* Remove all pending CoW reservations. */ /* Remove all pending CoW reservations. */
error = xfs_reflink_cancel_cow_blocks(ip, &tp, error = xfs_reflink_cancel_cow_blocks(ip, &tp,
first_unmap_block, last_block, true); first_unmap_block, XFS_MAX_FILEOFF, true);
if (error) if (error)
goto out; goto out;
......
...@@ -357,6 +357,7 @@ xfs_attrmulti_attr_get( ...@@ -357,6 +357,7 @@ xfs_attrmulti_attr_get(
{ {
unsigned char *kbuf; unsigned char *kbuf;
int error = -EFAULT; int error = -EFAULT;
size_t namelen;
if (*len > XFS_XATTR_SIZE_MAX) if (*len > XFS_XATTR_SIZE_MAX)
return -EINVAL; return -EINVAL;
...@@ -364,7 +365,9 @@ xfs_attrmulti_attr_get( ...@@ -364,7 +365,9 @@ xfs_attrmulti_attr_get(
if (!kbuf) if (!kbuf)
return -ENOMEM; return -ENOMEM;
error = xfs_attr_get(XFS_I(inode), name, &kbuf, (int *)len, flags); namelen = strlen(name);
error = xfs_attr_get(XFS_I(inode), name, namelen, &kbuf, (int *)len,
flags);
if (error) if (error)
goto out_kfree; goto out_kfree;
...@@ -386,6 +389,7 @@ xfs_attrmulti_attr_set( ...@@ -386,6 +389,7 @@ xfs_attrmulti_attr_set(
{ {
unsigned char *kbuf; unsigned char *kbuf;
int error; int error;
size_t namelen;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM; return -EPERM;
...@@ -396,7 +400,8 @@ xfs_attrmulti_attr_set( ...@@ -396,7 +400,8 @@ xfs_attrmulti_attr_set(
if (IS_ERR(kbuf)) if (IS_ERR(kbuf))
return PTR_ERR(kbuf); return PTR_ERR(kbuf);
error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags); namelen = strlen(name);
error = xfs_attr_set(XFS_I(inode), name, namelen, kbuf, len, flags);
if (!error) if (!error)
xfs_forget_acl(inode, name, flags); xfs_forget_acl(inode, name, flags);
kfree(kbuf); kfree(kbuf);
...@@ -410,10 +415,12 @@ xfs_attrmulti_attr_remove( ...@@ -410,10 +415,12 @@ xfs_attrmulti_attr_remove(
uint32_t flags) uint32_t flags)
{ {
int error; int error;
size_t namelen;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM; return -EPERM;
error = xfs_attr_remove(XFS_I(inode), name, flags); namelen = strlen(name);
error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
if (!error) if (!error)
xfs_forget_acl(inode, name, flags); xfs_forget_acl(inode, name, flags);
return error; return error;
...@@ -462,6 +469,13 @@ xfs_attrmulti_by_handle( ...@@ -462,6 +469,13 @@ xfs_attrmulti_by_handle(
error = 0; error = 0;
for (i = 0; i < am_hreq.opcount; i++) { for (i = 0; i < am_hreq.opcount; i++) {
if ((ops[i].am_flags & ATTR_ROOT) &&
(ops[i].am_flags & ATTR_SECURE)) {
ops[i].am_error = -EINVAL;
continue;
}
ops[i].am_flags &= ~ATTR_KERNEL_FLAGS;
ops[i].am_error = strncpy_from_user((char *)attr_name, ops[i].am_error = strncpy_from_user((char *)attr_name,
ops[i].am_attrname, MAXNAMELEN); ops[i].am_attrname, MAXNAMELEN);
if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN) if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)
......
...@@ -107,7 +107,7 @@ xfs_ioctl32_bstime_copyin( ...@@ -107,7 +107,7 @@ xfs_ioctl32_bstime_copyin(
xfs_bstime_t *bstime, xfs_bstime_t *bstime,
compat_xfs_bstime_t __user *bstime32) compat_xfs_bstime_t __user *bstime32)
{ {
compat_time_t sec32; /* tv_sec differs on 64 vs. 32 */ old_time32_t sec32; /* tv_sec differs on 64 vs. 32 */
if (get_user(sec32, &bstime32->tv_sec) || if (get_user(sec32, &bstime32->tv_sec) ||
get_user(bstime->tv_nsec, &bstime32->tv_nsec)) get_user(bstime->tv_nsec, &bstime32->tv_nsec))
...@@ -450,6 +450,13 @@ xfs_compat_attrmulti_by_handle( ...@@ -450,6 +450,13 @@ xfs_compat_attrmulti_by_handle(
error = 0; error = 0;
for (i = 0; i < am_hreq.opcount; i++) { for (i = 0; i < am_hreq.opcount; i++) {
if ((ops[i].am_flags & ATTR_ROOT) &&
(ops[i].am_flags & ATTR_SECURE)) {
ops[i].am_error = -EINVAL;
continue;
}
ops[i].am_flags &= ~ATTR_KERNEL_FLAGS;
ops[i].am_error = strncpy_from_user((char *)attr_name, ops[i].am_error = strncpy_from_user((char *)attr_name,
compat_ptr(ops[i].am_attrname), compat_ptr(ops[i].am_attrname),
MAXNAMELEN); MAXNAMELEN);
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
#endif #endif
typedef struct compat_xfs_bstime { typedef struct compat_xfs_bstime {
compat_time_t tv_sec; /* seconds */ old_time32_t tv_sec; /* seconds */
__s32 tv_nsec; /* and nanoseconds */ __s32 tv_nsec; /* and nanoseconds */
} compat_xfs_bstime_t; } compat_xfs_bstime_t;
......
...@@ -923,7 +923,7 @@ xfs_buffered_write_iomap_begin( ...@@ -923,7 +923,7 @@ xfs_buffered_write_iomap_begin(
xfs_trim_extent(&imap, offset_fsb, end_fsb - offset_fsb); xfs_trim_extent(&imap, offset_fsb, end_fsb - offset_fsb);
/* Trim the mapping to the nearest shared extent boundary. */ /* Trim the mapping to the nearest shared extent boundary. */
error = xfs_inode_need_cow(ip, &imap, &shared); error = xfs_bmap_trim_cow(ip, &imap, &shared);
if (error) if (error)
goto out_unlock; goto out_unlock;
......
...@@ -50,8 +50,10 @@ xfs_initxattrs( ...@@ -50,8 +50,10 @@ xfs_initxattrs(
int error = 0; int error = 0;
for (xattr = xattr_array; xattr->name != NULL; xattr++) { for (xattr = xattr_array; xattr->name != NULL; xattr++) {
error = xfs_attr_set(ip, xattr->name, xattr->value, error = xfs_attr_set(ip, xattr->name,
xattr->value_len, ATTR_SECURE); strlen(xattr->name),
xattr->value, xattr->value_len,
ATTR_SECURE);
if (error < 0) if (error < 0)
break; break;
} }
......
...@@ -1934,6 +1934,12 @@ xlog_recover_buffer_pass1( ...@@ -1934,6 +1934,12 @@ xlog_recover_buffer_pass1(
struct list_head *bucket; struct list_head *bucket;
struct xfs_buf_cancel *bcp; struct xfs_buf_cancel *bcp;
if (!xfs_buf_log_check_iovec(&item->ri_buf[0])) {
xfs_err(log->l_mp, "bad buffer log item size (%d)",
item->ri_buf[0].i_len);
return -EFSCORRUPTED;
}
/* /*
* If this isn't a cancel buffer item, then just return. * If this isn't a cancel buffer item, then just return.
*/ */
......
...@@ -111,6 +111,7 @@ xfs_check_ondisk_structs(void) ...@@ -111,6 +111,7 @@ xfs_check_ondisk_structs(void)
XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_hdr_t, 10); XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_hdr_t, 10);
/* log structures */ /* log structures */
XFS_CHECK_STRUCT_SIZE(struct xfs_buf_log_format, 88);
XFS_CHECK_STRUCT_SIZE(struct xfs_dq_logformat, 24); XFS_CHECK_STRUCT_SIZE(struct xfs_dq_logformat, 24);
XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_32, 28); XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_32, 28);
XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_64, 32); XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_64, 32);
......
...@@ -64,9 +64,9 @@ struct xfs_quotainfo { ...@@ -64,9 +64,9 @@ struct xfs_quotainfo {
struct xfs_inode *qi_pquotaip; /* project quota inode */ struct xfs_inode *qi_pquotaip; /* project quota inode */
struct list_lru qi_lru; struct list_lru qi_lru;
int qi_dquots; int qi_dquots;
time_t qi_btimelimit; /* limit for blks timer */ time64_t qi_btimelimit; /* limit for blks timer */
time_t qi_itimelimit; /* limit for inodes timer */ time64_t qi_itimelimit; /* limit for inodes timer */
time_t qi_rtbtimelimit;/* limit for rt blks timer */ time64_t qi_rtbtimelimit;/* limit for rt blks timer */
xfs_qwarncnt_t qi_bwarnlimit; /* limit for blks warnings */ xfs_qwarncnt_t qi_bwarnlimit; /* limit for blks warnings */
xfs_qwarncnt_t qi_iwarnlimit; /* limit for inodes warnings */ xfs_qwarncnt_t qi_iwarnlimit; /* limit for inodes warnings */
xfs_qwarncnt_t qi_rtbwarnlimit;/* limit for rt blks warnings */ xfs_qwarncnt_t qi_rtbwarnlimit;/* limit for rt blks warnings */
......
...@@ -37,9 +37,9 @@ xfs_qm_fill_state( ...@@ -37,9 +37,9 @@ xfs_qm_fill_state(
tstate->flags |= QCI_SYSFILE; tstate->flags |= QCI_SYSFILE;
tstate->blocks = ip->i_d.di_nblocks; tstate->blocks = ip->i_d.di_nblocks;
tstate->nextents = ip->i_d.di_nextents; tstate->nextents = ip->i_d.di_nextents;
tstate->spc_timelimit = q->qi_btimelimit; tstate->spc_timelimit = (u32)q->qi_btimelimit;
tstate->ino_timelimit = q->qi_itimelimit; tstate->ino_timelimit = (u32)q->qi_itimelimit;
tstate->rt_spc_timelimit = q->qi_rtbtimelimit; tstate->rt_spc_timelimit = (u32)q->qi_rtbtimelimit;
tstate->spc_warnlimit = q->qi_bwarnlimit; tstate->spc_warnlimit = q->qi_bwarnlimit;
tstate->ino_warnlimit = q->qi_iwarnlimit; tstate->ino_warnlimit = q->qi_iwarnlimit;
tstate->rt_spc_warnlimit = q->qi_rtbwarnlimit; tstate->rt_spc_warnlimit = q->qi_rtbwarnlimit;
......
...@@ -223,8 +223,8 @@ xfs_reflink_trim_around_shared( ...@@ -223,8 +223,8 @@ xfs_reflink_trim_around_shared(
} }
} }
bool int
xfs_inode_need_cow( xfs_bmap_trim_cow(
struct xfs_inode *ip, struct xfs_inode *ip,
struct xfs_bmbt_irec *imap, struct xfs_bmbt_irec *imap,
bool *shared) bool *shared)
...@@ -327,7 +327,7 @@ xfs_find_trim_cow_extent( ...@@ -327,7 +327,7 @@ xfs_find_trim_cow_extent(
if (cmap->br_startoff > offset_fsb) { if (cmap->br_startoff > offset_fsb) {
xfs_trim_extent(imap, imap->br_startoff, xfs_trim_extent(imap, imap->br_startoff,
cmap->br_startoff - imap->br_startoff); cmap->br_startoff - imap->br_startoff);
return xfs_inode_need_cow(ip, imap, shared); return xfs_bmap_trim_cow(ip, imap, shared);
} }
*shared = true; *shared = true;
...@@ -1457,7 +1457,8 @@ xfs_reflink_clear_inode_flag( ...@@ -1457,7 +1457,8 @@ xfs_reflink_clear_inode_flag(
* We didn't find any shared blocks so turn off the reflink flag. * We didn't find any shared blocks so turn off the reflink flag.
* First, get rid of any leftover CoW mappings. * First, get rid of any leftover CoW mappings.
*/ */
error = xfs_reflink_cancel_cow_blocks(ip, tpp, 0, NULLFILEOFF, true); error = xfs_reflink_cancel_cow_blocks(ip, tpp, 0, XFS_MAX_FILEOFF,
true);
if (error) if (error)
return error; return error;
......
...@@ -22,7 +22,7 @@ extern int xfs_reflink_find_shared(struct xfs_mount *mp, struct xfs_trans *tp, ...@@ -22,7 +22,7 @@ extern int xfs_reflink_find_shared(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_agblock_t *fbno, xfs_extlen_t *flen, bool find_maximal); xfs_agblock_t *fbno, xfs_extlen_t *flen, bool find_maximal);
extern int xfs_reflink_trim_around_shared(struct xfs_inode *ip, extern int xfs_reflink_trim_around_shared(struct xfs_inode *ip,
struct xfs_bmbt_irec *irec, bool *shared); struct xfs_bmbt_irec *irec, bool *shared);
bool xfs_inode_need_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap, int xfs_bmap_trim_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap,
bool *shared); bool *shared);
int xfs_reflink_allocate_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap, int xfs_reflink_allocate_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap,
......
...@@ -193,32 +193,6 @@ xfs_fs_show_options( ...@@ -193,32 +193,6 @@ xfs_fs_show_options(
return 0; return 0;
} }
static uint64_t
xfs_max_file_offset(
unsigned int blockshift)
{
unsigned int pagefactor = 1;
unsigned int bitshift = BITS_PER_LONG - 1;
/* Figure out maximum filesize, on Linux this can depend on
* the filesystem blocksize (on 32 bit platforms).
* __block_write_begin does this in an [unsigned] long long...
* page->index << (PAGE_SHIFT - bbits)
* So, for page sized blocks (4K on 32 bit platforms),
* this wraps at around 8Tb (hence MAX_LFS_FILESIZE which is
* (((u64)PAGE_SIZE << (BITS_PER_LONG-1))-1)
* but for smaller blocksizes it is less (bbits = log2 bsize).
*/
#if BITS_PER_LONG == 32
ASSERT(sizeof(sector_t) == 8);
pagefactor = PAGE_SIZE;
bitshift = BITS_PER_LONG;
#endif
return (((uint64_t)pagefactor) << bitshift) - 1;
}
/* /*
* Set parameters for inode allocation heuristics, taking into account * Set parameters for inode allocation heuristics, taking into account
* filesystem size and inode32/inode64 mount options; i.e. specifically * filesystem size and inode32/inode64 mount options; i.e. specifically
...@@ -1424,6 +1398,26 @@ xfs_fc_fill_super( ...@@ -1424,6 +1398,26 @@ xfs_fc_fill_super(
if (error) if (error)
goto out_free_sb; goto out_free_sb;
/*
* XFS block mappings use 54 bits to store the logical block offset.
* This should suffice to handle the maximum file size that the VFS
* supports (currently 2^63 bytes on 64-bit and ULONG_MAX << PAGE_SHIFT
* bytes on 32-bit), but as XFS and VFS have gotten the s_maxbytes
* calculation wrong on 32-bit kernels in the past, we'll add a WARN_ON
* to check this assertion.
*
* Avoid integer overflow by comparing the maximum bmbt offset to the
* maximum pagecache offset in units of fs blocks.
*/
if (XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE) > XFS_MAX_FILEOFF) {
xfs_warn(mp,
"MAX_LFS_FILESIZE block offset (%llu) exceeds extent map maximum (%llu)!",
XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE),
XFS_MAX_FILEOFF);
error = -EINVAL;
goto out_free_sb;
}
error = xfs_filestream_mount(mp); error = xfs_filestream_mount(mp);
if (error) if (error)
goto out_free_sb; goto out_free_sb;
...@@ -1435,7 +1429,7 @@ xfs_fc_fill_super( ...@@ -1435,7 +1429,7 @@ xfs_fc_fill_super(
sb->s_magic = XFS_SUPER_MAGIC; sb->s_magic = XFS_SUPER_MAGIC;
sb->s_blocksize = mp->m_sb.sb_blocksize; sb->s_blocksize = mp->m_sb.sb_blocksize;
sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1; sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1;
sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits); sb->s_maxbytes = MAX_LFS_FILESIZE;
sb->s_max_links = XFS_MAXLINK; sb->s_max_links = XFS_MAXLINK;
sb->s_time_gran = 1; sb->s_time_gran = 1;
sb->s_time_min = S32_MIN; sb->s_time_min = S32_MIN;
......
...@@ -580,7 +580,7 @@ xfs_trans_dqresv( ...@@ -580,7 +580,7 @@ xfs_trans_dqresv(
{ {
xfs_qcnt_t hardlimit; xfs_qcnt_t hardlimit;
xfs_qcnt_t softlimit; xfs_qcnt_t softlimit;
time_t timer; time64_t timer;
xfs_qwarncnt_t warns; xfs_qwarncnt_t warns;
xfs_qwarncnt_t warnlimit; xfs_qwarncnt_t warnlimit;
xfs_qcnt_t total_count; xfs_qcnt_t total_count;
...@@ -635,7 +635,8 @@ xfs_trans_dqresv( ...@@ -635,7 +635,8 @@ xfs_trans_dqresv(
goto error_return; goto error_return;
} }
if (softlimit && total_count > softlimit) { if (softlimit && total_count > softlimit) {
if ((timer != 0 && get_seconds() > timer) || if ((timer != 0 &&
ktime_get_real_seconds() > timer) ||
(warns != 0 && warns >= warnlimit)) { (warns != 0 && warns >= warnlimit)) {
xfs_quota_warn(mp, dqp, xfs_quota_warn(mp, dqp,
QUOTA_NL_BSOFTLONGWARN); QUOTA_NL_BSOFTLONGWARN);
...@@ -662,7 +663,8 @@ xfs_trans_dqresv( ...@@ -662,7 +663,8 @@ xfs_trans_dqresv(
goto error_return; goto error_return;
} }
if (softlimit && total_count > softlimit) { if (softlimit && total_count > softlimit) {
if ((timer != 0 && get_seconds() > timer) || if ((timer != 0 &&
ktime_get_real_seconds() > timer) ||
(warns != 0 && warns >= warnlimit)) { (warns != 0 && warns >= warnlimit)) {
xfs_quota_warn(mp, dqp, xfs_quota_warn(mp, dqp,
QUOTA_NL_ISOFTLONGWARN); QUOTA_NL_ISOFTLONGWARN);
......
...@@ -24,6 +24,7 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused, ...@@ -24,6 +24,7 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
int xflags = handler->flags; int xflags = handler->flags;
struct xfs_inode *ip = XFS_I(inode); struct xfs_inode *ip = XFS_I(inode);
int error, asize = size; int error, asize = size;
size_t namelen = strlen(name);
/* Convert Linux syscall to XFS internal ATTR flags */ /* Convert Linux syscall to XFS internal ATTR flags */
if (!size) { if (!size) {
...@@ -31,7 +32,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused, ...@@ -31,7 +32,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
value = NULL; value = NULL;
} }
error = xfs_attr_get(ip, name, (unsigned char **)&value, &asize, xflags); error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value,
&asize, xflags);
if (error) if (error)
return error; return error;
return asize; return asize;
...@@ -67,6 +69,7 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused, ...@@ -67,6 +69,7 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
int xflags = handler->flags; int xflags = handler->flags;
struct xfs_inode *ip = XFS_I(inode); struct xfs_inode *ip = XFS_I(inode);
int error; int error;
size_t namelen = strlen(name);
/* Convert Linux syscall to XFS internal ATTR flags */ /* Convert Linux syscall to XFS internal ATTR flags */
if (flags & XATTR_CREATE) if (flags & XATTR_CREATE)
...@@ -74,10 +77,11 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused, ...@@ -74,10 +77,11 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
if (flags & XATTR_REPLACE) if (flags & XATTR_REPLACE)
xflags |= ATTR_REPLACE; xflags |= ATTR_REPLACE;
if (!value) if (value)
return xfs_attr_remove(ip, (unsigned char *)name, xflags); error = xfs_attr_set(ip, name, namelen, (void *)value, size,
error = xfs_attr_set(ip, (unsigned char *)name, xflags);
(void *)value, size, xflags); else
error = xfs_attr_remove(ip, name, namelen, xflags);
if (!error) if (!error)
xfs_forget_acl(inode, name, xflags); xfs_forget_acl(inode, name, xflags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment