New code for 5.6:
- 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. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEUzaAxoMeQq6m2jMV+H93GTRKtOsFAl4rGQcACgkQ+H93GTRK tOv1uhAAo5F38h9ZpdoMK4TPJNaREmLtM+MAA03l3sk+BY5zGDo690WDaxa5cd8h cJi8pqHpcnroJVptCkbdagx0BIPnHMVpw7CKFpBlCjNHpFeO1ULLpk/RcvwISRZy OvEOmpn6Z/FQ2jTBjr45KXIiS5DAK3KRMrmGdvh6j73YVhQ1lgadY/6Jj2TRjzT1 FFjnYMGhufBsP0yV9Rg10AcIhNCIAr3RYmfjqFXMA8raEX33gdpsJ6GU6r5iyXRJ B9dByoBlGCL15ZlxZOqEiN4omqqBLux5jrJr1tg0L0hbfu7UIxMcwXiSTnoaO2SZ G7GjlEO3wszf3wGEeaaJd/tN58SQDvfz3yY9vZObrlTelN5iDrcziLHbWc+xkwPh mykly36x8+dZ8kqgBxiF1WFgRheYNQIWnZ9wtCfWvsPtjrklIZNZqKDEAxXnSg0w 8lRXgeNfy6Jh78A817aPQibqkUAtxSk8RJhimkPWyKwUA3jSzgv1LsjgzoRCM8ik /vmmRKmXviFrQwIgDKYQc/wHx58khKBi2Kna+rZUJrozrBU+P0EfG+AU6Rxjw1ob cOOSNooI5kp+uTrmlaKKr9mua80m0hACgrFT9Fj+SJWgi313343VVNXubRgK/yV7 WxTcTOZadkQgqgeQSMzwFQuQPjQob9bNoQf5PK01sJ/4v96Zsmg= =J5Em -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
91f1a9566f
|
@ -62,6 +62,7 @@ xfs_attr_args_init(
|
|||
struct xfs_da_args *args,
|
||||
struct xfs_inode *dp,
|
||||
const unsigned char *name,
|
||||
size_t namelen,
|
||||
int flags)
|
||||
{
|
||||
|
||||
|
@ -74,7 +75,7 @@ xfs_attr_args_init(
|
|||
args->dp = dp;
|
||||
args->flags = flags;
|
||||
args->name = name;
|
||||
args->namelen = strlen((const char *)name);
|
||||
args->namelen = namelen;
|
||||
if (args->namelen >= MAXNAMELEN)
|
||||
return -EFAULT; /* match IRIX behaviour */
|
||||
|
||||
|
@ -139,6 +140,7 @@ int
|
|||
xfs_attr_get(
|
||||
struct xfs_inode *ip,
|
||||
const unsigned char *name,
|
||||
size_t namelen,
|
||||
unsigned char **value,
|
||||
int *valuelenp,
|
||||
int flags)
|
||||
|
@ -154,7 +156,7 @@ xfs_attr_get(
|
|||
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
|
||||
return -EIO;
|
||||
|
||||
error = xfs_attr_args_init(&args, ip, name, flags);
|
||||
error = xfs_attr_args_init(&args, ip, name, namelen, flags);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -338,6 +340,7 @@ int
|
|||
xfs_attr_set(
|
||||
struct xfs_inode *dp,
|
||||
const unsigned char *name,
|
||||
size_t namelen,
|
||||
unsigned char *value,
|
||||
int valuelen,
|
||||
int flags)
|
||||
|
@ -353,7 +356,7 @@ xfs_attr_set(
|
|||
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
|
||||
return -EIO;
|
||||
|
||||
error = xfs_attr_args_init(&args, dp, name, flags);
|
||||
error = xfs_attr_args_init(&args, dp, name, namelen, flags);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -442,6 +445,7 @@ int
|
|||
xfs_attr_remove(
|
||||
struct xfs_inode *dp,
|
||||
const unsigned char *name,
|
||||
size_t namelen,
|
||||
int flags)
|
||||
{
|
||||
struct xfs_mount *mp = dp->i_mount;
|
||||
|
@ -453,7 +457,7 @@ xfs_attr_remove(
|
|||
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
|
||||
return -EIO;
|
||||
|
||||
error = xfs_attr_args_init(&args, dp, name, flags);
|
||||
error = xfs_attr_args_init(&args, dp, name, namelen, flags);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -1007,7 +1011,7 @@ restart:
|
|||
* The INCOMPLETE flag means that we will find the "old"
|
||||
* attr, not the "new" one.
|
||||
*/
|
||||
args->flags |= XFS_ATTR_INCOMPLETE;
|
||||
args->op_flags |= XFS_DA_OP_INCOMPLETE;
|
||||
state = xfs_da_state_alloc();
|
||||
state->args = args;
|
||||
state->mp = mp;
|
||||
|
|
|
@ -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_TRUST 0x0004 /* -- unused, from IRIX -- */
|
||||
#define ATTR_SECURE 0x0008 /* use attrs in security namespace */
|
||||
|
@ -37,7 +37,10 @@ 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 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 \
|
||||
{ ATTR_DONTFOLLOW, "DONTFOLLOW" }, \
|
||||
|
@ -145,11 +148,13 @@ 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);
|
||||
size_t namelen, 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);
|
||||
size_t namelen, unsigned char *value, int valuelen, int flags);
|
||||
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_list(struct xfs_inode *dp, char *buffer, int bufsize,
|
||||
int flags, struct attrlist_cursor_kern *cursor);
|
||||
|
|
|
@ -2403,8 +2403,8 @@ xfs_attr3_leaf_lookup_int(
|
|||
* If we are looking for INCOMPLETE entries, show only those.
|
||||
* If we are looking for complete entries, show only those.
|
||||
*/
|
||||
if ((args->flags & XFS_ATTR_INCOMPLETE) !=
|
||||
(entry->flags & XFS_ATTR_INCOMPLETE)) {
|
||||
if (!!(args->op_flags & XFS_DA_OP_INCOMPLETE) !=
|
||||
!!(entry->flags & XFS_ATTR_INCOMPLETE)) {
|
||||
continue;
|
||||
}
|
||||
if (entry->flags & XFS_ATTR_LOCAL) {
|
||||
|
|
|
@ -39,15 +39,6 @@ struct xfs_attr3_icleaf_hdr {
|
|||
} 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.
|
||||
*========================================================================*/
|
||||
|
|
|
@ -25,6 +25,23 @@
|
|||
|
||||
#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
|
||||
* length to FSB conversion.
|
||||
|
@ -401,17 +418,25 @@ xfs_attr_rmtval_get(
|
|||
(map[i].br_startblock != HOLESTARTBLOCK));
|
||||
dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
|
||||
dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
|
||||
error = xfs_trans_read_buf(mp, args->trans,
|
||||
mp->m_ddev_targp,
|
||||
dblkno, dblkcnt, 0, &bp,
|
||||
&xfs_attr3_rmt_buf_ops);
|
||||
if (error)
|
||||
bp = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt, 0,
|
||||
&xfs_attr3_rmt_buf_ops);
|
||||
if (!bp)
|
||||
return -ENOMEM;
|
||||
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;
|
||||
}
|
||||
|
||||
error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
|
||||
&offset, &valuelen,
|
||||
&dst);
|
||||
xfs_trans_brelse(args->trans, bp);
|
||||
xfs_buf_relse(bp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -552,6 +577,33 @@ xfs_attr_rmtval_set(
|
|||
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
|
||||
* out-of-line buffer that it is stored on.
|
||||
|
@ -560,7 +612,6 @@ int
|
|||
xfs_attr_rmtval_remove(
|
||||
struct xfs_da_args *args)
|
||||
{
|
||||
struct xfs_mount *mp = args->dp->i_mount;
|
||||
xfs_dablk_t lblkno;
|
||||
int blkcnt;
|
||||
int error;
|
||||
|
@ -575,9 +626,6 @@ xfs_attr_rmtval_remove(
|
|||
blkcnt = args->rmtblkcnt;
|
||||
while (blkcnt > 0) {
|
||||
struct xfs_bmbt_irec map;
|
||||
struct xfs_buf *bp;
|
||||
xfs_daddr_t dblkno;
|
||||
int dblkcnt;
|
||||
int nmap;
|
||||
|
||||
/*
|
||||
|
@ -588,22 +636,11 @@ xfs_attr_rmtval_remove(
|
|||
blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
|
||||
if (error)
|
||||
return error;
|
||||
ASSERT(nmap == 1);
|
||||
ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
|
||||
(map.br_startblock != HOLESTARTBLOCK));
|
||||
|
||||
dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
|
||||
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;
|
||||
}
|
||||
if (XFS_IS_CORRUPT(args->dp->i_mount, nmap != 1))
|
||||
return -EFSCORRUPTED;
|
||||
error = xfs_attr_rmtval_stale(args->dp, &map, XBF_TRYLOCK);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
lblkno += map.br_blockcount;
|
||||
blkcnt -= map.br_blockcount;
|
||||
|
|
|
@ -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_set(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__ */
|
||||
|
|
|
@ -2389,8 +2389,6 @@ xfs_btree_lshift(
|
|||
XFS_BTREE_STATS_ADD(cur, moves, rrecs - 1);
|
||||
if (level > 0) {
|
||||
/* It's a nonleaf. operate on keys and ptrs */
|
||||
int i; /* loop index */
|
||||
|
||||
for (i = 0; i < rrecs; i++) {
|
||||
error = xfs_btree_debug_check_ptr(cur, rpp, i + 1, level);
|
||||
if (error)
|
||||
|
|
|
@ -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_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_INCOMPLETE 0x0040 /* lookup INCOMPLETE attr keys */
|
||||
|
||||
#define XFS_DA_OP_FLAGS \
|
||||
{ XFS_DA_OP_JUSTCHECK, "JUSTCHECK" }, \
|
||||
|
@ -96,7 +97,8 @@ typedef struct xfs_da_args {
|
|||
{ XFS_DA_OP_ADDNAME, "ADDNAME" }, \
|
||||
{ XFS_DA_OP_OKNOENT, "OKNOENT" }, \
|
||||
{ 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.
|
||||
|
|
|
@ -217,7 +217,7 @@ typedef struct xfs_dir2_sf_entry {
|
|||
* A 64-bit or 32-bit inode number follows here, at a variable offset
|
||||
* after the name.
|
||||
*/
|
||||
} xfs_dir2_sf_entry_t;
|
||||
} __packed xfs_dir2_sf_entry_t;
|
||||
|
||||
static inline int xfs_dir2_sf_hdr_size(int i8count)
|
||||
{
|
||||
|
@ -683,8 +683,6 @@ struct xfs_attr3_leafblock {
|
|||
|
||||
/*
|
||||
* 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_ROOT_BIT 1 /* limit access to trusted attrs */
|
||||
|
|
|
@ -1540,6 +1540,13 @@ typedef struct xfs_bmdr_block {
|
|||
#define BMBT_BLOCKCOUNT_BITLEN 21
|
||||
|
||||
#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 {
|
||||
__be64 l0, l1;
|
||||
|
|
|
@ -462,11 +462,20 @@ static inline uint xfs_log_dinode_size(int version)
|
|||
#define XFS_BLF_GDQUOT_BUF (1<<4)
|
||||
|
||||
/*
|
||||
* This is the structure used to lay out a buf log item in the
|
||||
* log. The data map describes which 128 byte chunks of the buffer
|
||||
* have been logged.
|
||||
* This is the structure used to lay out a buf log item in the log. The data
|
||||
* map describes which 128 byte chunks of the buffer have been logged.
|
||||
*
|
||||
* The placement of blf_map_size causes blf_data_map to start at an odd
|
||||
* 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_MAX_BLOCKSIZE / XFS_BLF_CHUNK) / NBWORD)
|
||||
#define XFS_BLF_DATAMAP_SIZE (__XFS_BLF_DATAMAP_SIZE + 1)
|
||||
|
||||
typedef struct xfs_buf_log_format {
|
||||
unsigned short blf_type; /* buf log item type indicator */
|
||||
|
|
|
@ -75,7 +75,6 @@ static inline xfs_extlen_t
|
|||
xrep_calc_ag_resblks(
|
||||
struct xfs_scrub *sc)
|
||||
{
|
||||
ASSERT(!(sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -145,7 +145,8 @@ xfs_get_acl(struct inode *inode, int type)
|
|||
* go out to the disk.
|
||||
*/
|
||||
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);
|
||||
if (error) {
|
||||
/*
|
||||
|
@ -196,15 +197,17 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
|||
len -= sizeof(struct xfs_acl_entry) *
|
||||
(XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
|
||||
|
||||
error = xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
|
||||
len, ATTR_ROOT);
|
||||
error = xfs_attr_set(ip, ea_name, strlen(ea_name),
|
||||
(unsigned char *)xfs_acl, len, ATTR_ROOT);
|
||||
|
||||
kmem_free(xfs_acl);
|
||||
} else {
|
||||
/*
|
||||
* 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.
|
||||
|
|
|
@ -25,22 +25,18 @@
|
|||
#include "xfs_error.h"
|
||||
|
||||
/*
|
||||
* Look at all the extents for this logical region,
|
||||
* invalidate any buffers that are incore/in transactions.
|
||||
* Invalidate any incore buffers associated with this remote attribute value
|
||||
* 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
|
||||
xfs_attr3_leaf_freextent(
|
||||
struct xfs_trans **trans,
|
||||
xfs_attr3_rmt_stale(
|
||||
struct xfs_inode *dp,
|
||||
xfs_dablk_t blkno,
|
||||
int blkcnt)
|
||||
{
|
||||
struct xfs_bmbt_irec map;
|
||||
struct xfs_buf *bp;
|
||||
xfs_dablk_t tblkno;
|
||||
xfs_daddr_t dblkno;
|
||||
int tblkcnt;
|
||||
int dblkcnt;
|
||||
int nmap;
|
||||
int error;
|
||||
|
||||
|
@ -48,47 +44,29 @@ xfs_attr3_leaf_freextent(
|
|||
* Roll through the "value", invalidating the attribute value's
|
||||
* blocks.
|
||||
*/
|
||||
tblkno = blkno;
|
||||
tblkcnt = blkcnt;
|
||||
while (tblkcnt > 0) {
|
||||
while (blkcnt > 0) {
|
||||
/*
|
||||
* Try to remember where we decided to put the value.
|
||||
*/
|
||||
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);
|
||||
if (error) {
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
ASSERT(nmap == 1);
|
||||
ASSERT(map.br_startblock != DELAYSTARTBLOCK);
|
||||
if (XFS_IS_CORRUPT(dp->i_mount, nmap != 1))
|
||||
return -EFSCORRUPTED;
|
||||
|
||||
/*
|
||||
* If it's a hole, these are already unmapped
|
||||
* so there's nothing to invalidate.
|
||||
* Mark any incore buffers for the remote value as stale. We
|
||||
* 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)
|
||||
return error;
|
||||
|
||||
dblkno = XFS_FSB_TO_DADDR(dp->i_mount,
|
||||
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;
|
||||
tblkcnt -= map.br_blockcount;
|
||||
blkno += map.br_blockcount;
|
||||
blkcnt -= map.br_blockcount;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -102,86 +80,45 @@ xfs_attr3_leaf_freextent(
|
|||
*/
|
||||
STATIC int
|
||||
xfs_attr3_leaf_inactive(
|
||||
struct xfs_trans **trans,
|
||||
struct xfs_inode *dp,
|
||||
struct xfs_buf *bp)
|
||||
struct xfs_trans **trans,
|
||||
struct xfs_inode *dp,
|
||||
struct xfs_buf *bp)
|
||||
{
|
||||
struct xfs_attr_leafblock *leaf;
|
||||
struct xfs_attr3_icleaf_hdr ichdr;
|
||||
struct xfs_attr_leaf_entry *entry;
|
||||
struct xfs_attr3_icleaf_hdr ichdr;
|
||||
struct xfs_mount *mp = bp->b_mount;
|
||||
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_inactive_list *list;
|
||||
struct xfs_attr_inactive_list *lp;
|
||||
int error;
|
||||
int count;
|
||||
int size;
|
||||
int tmp;
|
||||
int i;
|
||||
struct xfs_mount *mp = bp->b_mount;
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
leaf = bp->b_addr;
|
||||
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);
|
||||
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)
|
||||
count++;
|
||||
}
|
||||
int blkcnt;
|
||||
|
||||
if (!entry->nameidx || (entry->flags & XFS_ATTR_LOCAL))
|
||||
continue;
|
||||
|
||||
name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
|
||||
if (!name_rmt->valueblk)
|
||||
continue;
|
||||
|
||||
blkcnt = xfs_attr3_rmt_blocks(dp->i_mount,
|
||||
be32_to_cpu(name_rmt->valuelen));
|
||||
error = xfs_attr3_rmt_stale(dp,
|
||||
be32_to_cpu(name_rmt->valueblk), blkcnt);
|
||||
if (error)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are no "remote" values, we're done.
|
||||
*/
|
||||
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() */
|
||||
|
||||
/*
|
||||
* Invalidate each of the "remote" value extents.
|
||||
*/
|
||||
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)
|
||||
error = tmp; /* save only the 1st errno */
|
||||
}
|
||||
|
||||
kmem_free(list);
|
||||
xfs_trans_brelse(*trans, bp);
|
||||
err:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
/* 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
|
||||
xfs_buf_log_format_size(
|
||||
struct xfs_buf_log_format *blfp)
|
||||
|
@ -688,7 +705,7 @@ static const struct xfs_item_ops xfs_buf_item_ops = {
|
|||
.iop_push = xfs_buf_item_push,
|
||||
};
|
||||
|
||||
STATIC int
|
||||
STATIC void
|
||||
xfs_buf_item_get_format(
|
||||
struct xfs_buf_log_item *bip,
|
||||
int count)
|
||||
|
@ -698,14 +715,11 @@ xfs_buf_item_get_format(
|
|||
|
||||
if (count == 1) {
|
||||
bip->bli_formats = &bip->__bli_format;
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
bip->bli_formats = kmem_zalloc(count * sizeof(struct xfs_buf_log_format),
|
||||
0);
|
||||
if (!bip->bli_formats)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC void
|
||||
|
@ -731,7 +745,6 @@ xfs_buf_item_init(
|
|||
struct xfs_buf_log_item *bip = bp->b_log_item;
|
||||
int chunks;
|
||||
int map_size;
|
||||
int error;
|
||||
int i;
|
||||
|
||||
/*
|
||||
|
@ -760,19 +773,22 @@ xfs_buf_item_init(
|
|||
* Discontiguous buffer support follows the layout of the underlying
|
||||
* buffer. This makes the implementation as simple as possible.
|
||||
*/
|
||||
error = 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;
|
||||
}
|
||||
|
||||
xfs_buf_item_get_format(bip, bp->b_map_count);
|
||||
|
||||
for (i = 0; i < bip->bli_format_count; i++) {
|
||||
chunks = DIV_ROUND_UP(BBTOB(bp->b_maps[i].bm_len),
|
||||
XFS_BLF_CHUNK);
|
||||
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_blkno = bp->b_maps[i].bm_bn;
|
||||
bip->bli_formats[i].blf_len = bp->b_maps[i].bm_len;
|
||||
|
@ -805,6 +821,9 @@ xfs_buf_item_log_segment(
|
|||
uint end_bit;
|
||||
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.
|
||||
*/
|
||||
|
|
|
@ -61,6 +61,7 @@ void xfs_buf_iodone_callbacks(struct xfs_buf *);
|
|||
void xfs_buf_iodone(struct xfs_buf *, struct xfs_log_item *);
|
||||
bool xfs_buf_resubmit_failed_buffers(struct xfs_buf *,
|
||||
struct list_head *);
|
||||
bool xfs_buf_log_check_iovec(struct xfs_log_iovec *iovec);
|
||||
|
||||
extern kmem_zone_t *xfs_buf_item_zone;
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ xfs_qm_adjust_dqtimers(
|
|||
(d->d_blk_hardlimit &&
|
||||
(be64_to_cpu(d->d_bcount) >
|
||||
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);
|
||||
} else {
|
||||
d->d_bwarns = 0;
|
||||
|
@ -160,7 +160,7 @@ xfs_qm_adjust_dqtimers(
|
|||
(d->d_ino_hardlimit &&
|
||||
(be64_to_cpu(d->d_icount) >
|
||||
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);
|
||||
} else {
|
||||
d->d_iwarns = 0;
|
||||
|
@ -183,7 +183,7 @@ xfs_qm_adjust_dqtimers(
|
|||
(d->d_rtb_hardlimit &&
|
||||
(be64_to_cpu(d->d_rtbcount) >
|
||||
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);
|
||||
} else {
|
||||
d->d_rtbwarns = 0;
|
||||
|
|
|
@ -187,7 +187,12 @@ xfs_file_dio_aio_read(
|
|||
|
||||
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,
|
||||
is_sync_kiocb(iocb));
|
||||
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
|
||||
|
|
|
@ -1518,10 +1518,8 @@ xfs_itruncate_extents_flags(
|
|||
struct xfs_mount *mp = ip->i_mount;
|
||||
struct xfs_trans *tp = *tpp;
|
||||
xfs_fileoff_t first_unmap_block;
|
||||
xfs_fileoff_t last_block;
|
||||
xfs_filblks_t unmap_len;
|
||||
int error = 0;
|
||||
int done = 0;
|
||||
|
||||
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
|
||||
ASSERT(!atomic_read(&VFS_I(ip)->i_count) ||
|
||||
|
@ -1541,21 +1539,22 @@ xfs_itruncate_extents_flags(
|
|||
* the end of the file (in a crash where the space is allocated
|
||||
* but the inode size is not yet updated), simply remove any
|
||||
* blocks which show up between the new EOF and the maximum
|
||||
* possible file size. If the first block to be removed is
|
||||
* beyond the maximum file size (ie it is the same as last_block),
|
||||
* then there is nothing to do.
|
||||
* possible file size.
|
||||
*
|
||||
* 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);
|
||||
last_block = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
|
||||
if (first_unmap_block == last_block)
|
||||
if (first_unmap_block >= XFS_MAX_FILEOFF) {
|
||||
WARN_ON_ONCE(first_unmap_block > XFS_MAX_FILEOFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ASSERT(first_unmap_block < last_block);
|
||||
unmap_len = last_block - first_unmap_block + 1;
|
||||
while (!done) {
|
||||
unmap_len = XFS_MAX_FILEOFF - first_unmap_block + 1;
|
||||
while (unmap_len > 0) {
|
||||
ASSERT(tp->t_firstblock == NULLFSBLOCK);
|
||||
error = xfs_bunmapi(tp, ip, first_unmap_block, unmap_len, flags,
|
||||
XFS_ITRUNC_MAX_EXTENTS, &done);
|
||||
error = __xfs_bunmapi(tp, ip, first_unmap_block, &unmap_len,
|
||||
flags, XFS_ITRUNC_MAX_EXTENTS);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
|
@ -1575,7 +1574,7 @@ xfs_itruncate_extents_flags(
|
|||
if (whichfork == XFS_DATA_FORK) {
|
||||
/* Remove all pending CoW reservations. */
|
||||
error = xfs_reflink_cancel_cow_blocks(ip, &tp,
|
||||
first_unmap_block, last_block, true);
|
||||
first_unmap_block, XFS_MAX_FILEOFF, true);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
|
|
|
@ -357,6 +357,7 @@ xfs_attrmulti_attr_get(
|
|||
{
|
||||
unsigned char *kbuf;
|
||||
int error = -EFAULT;
|
||||
size_t namelen;
|
||||
|
||||
if (*len > XFS_XATTR_SIZE_MAX)
|
||||
return -EINVAL;
|
||||
|
@ -364,7 +365,9 @@ xfs_attrmulti_attr_get(
|
|||
if (!kbuf)
|
||||
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)
|
||||
goto out_kfree;
|
||||
|
||||
|
@ -386,6 +389,7 @@ xfs_attrmulti_attr_set(
|
|||
{
|
||||
unsigned char *kbuf;
|
||||
int error;
|
||||
size_t namelen;
|
||||
|
||||
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
|
||||
return -EPERM;
|
||||
|
@ -396,7 +400,8 @@ xfs_attrmulti_attr_set(
|
|||
if (IS_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)
|
||||
xfs_forget_acl(inode, name, flags);
|
||||
kfree(kbuf);
|
||||
|
@ -410,10 +415,12 @@ xfs_attrmulti_attr_remove(
|
|||
uint32_t flags)
|
||||
{
|
||||
int error;
|
||||
size_t namelen;
|
||||
|
||||
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
|
||||
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)
|
||||
xfs_forget_acl(inode, name, flags);
|
||||
return error;
|
||||
|
@ -462,6 +469,13 @@ xfs_attrmulti_by_handle(
|
|||
|
||||
error = 0;
|
||||
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_attrname, MAXNAMELEN);
|
||||
if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)
|
||||
|
|
|
@ -107,7 +107,7 @@ xfs_ioctl32_bstime_copyin(
|
|||
xfs_bstime_t *bstime,
|
||||
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) ||
|
||||
get_user(bstime->tv_nsec, &bstime32->tv_nsec))
|
||||
|
@ -450,6 +450,13 @@ xfs_compat_attrmulti_by_handle(
|
|||
|
||||
error = 0;
|
||||
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,
|
||||
compat_ptr(ops[i].am_attrname),
|
||||
MAXNAMELEN);
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#endif
|
||||
|
||||
typedef struct compat_xfs_bstime {
|
||||
compat_time_t tv_sec; /* seconds */
|
||||
old_time32_t tv_sec; /* seconds */
|
||||
__s32 tv_nsec; /* and nanoseconds */
|
||||
} compat_xfs_bstime_t;
|
||||
|
||||
|
|
|
@ -923,7 +923,7 @@ xfs_buffered_write_iomap_begin(
|
|||
xfs_trim_extent(&imap, offset_fsb, end_fsb - offset_fsb);
|
||||
|
||||
/* 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)
|
||||
goto out_unlock;
|
||||
|
||||
|
|
|
@ -50,8 +50,10 @@ xfs_initxattrs(
|
|||
int error = 0;
|
||||
|
||||
for (xattr = xattr_array; xattr->name != NULL; xattr++) {
|
||||
error = xfs_attr_set(ip, xattr->name, xattr->value,
|
||||
xattr->value_len, ATTR_SECURE);
|
||||
error = xfs_attr_set(ip, xattr->name,
|
||||
strlen(xattr->name),
|
||||
xattr->value, xattr->value_len,
|
||||
ATTR_SECURE);
|
||||
if (error < 0)
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1934,6 +1934,12 @@ xlog_recover_buffer_pass1(
|
|||
struct list_head *bucket;
|
||||
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.
|
||||
*/
|
||||
|
|
|
@ -111,6 +111,7 @@ xfs_check_ondisk_structs(void)
|
|||
XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_hdr_t, 10);
|
||||
|
||||
/* 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_efd_log_format_32, 28);
|
||||
XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_64, 32);
|
||||
|
|
|
@ -64,9 +64,9 @@ struct xfs_quotainfo {
|
|||
struct xfs_inode *qi_pquotaip; /* project quota inode */
|
||||
struct list_lru qi_lru;
|
||||
int qi_dquots;
|
||||
time_t qi_btimelimit; /* limit for blks timer */
|
||||
time_t qi_itimelimit; /* limit for inodes timer */
|
||||
time_t qi_rtbtimelimit;/* limit for rt blks timer */
|
||||
time64_t qi_btimelimit; /* limit for blks timer */
|
||||
time64_t qi_itimelimit; /* limit for inodes timer */
|
||||
time64_t qi_rtbtimelimit;/* limit for rt blks timer */
|
||||
xfs_qwarncnt_t qi_bwarnlimit; /* limit for blks warnings */
|
||||
xfs_qwarncnt_t qi_iwarnlimit; /* limit for inodes warnings */
|
||||
xfs_qwarncnt_t qi_rtbwarnlimit;/* limit for rt blks warnings */
|
||||
|
|
|
@ -37,9 +37,9 @@ xfs_qm_fill_state(
|
|||
tstate->flags |= QCI_SYSFILE;
|
||||
tstate->blocks = ip->i_d.di_nblocks;
|
||||
tstate->nextents = ip->i_d.di_nextents;
|
||||
tstate->spc_timelimit = q->qi_btimelimit;
|
||||
tstate->ino_timelimit = q->qi_itimelimit;
|
||||
tstate->rt_spc_timelimit = q->qi_rtbtimelimit;
|
||||
tstate->spc_timelimit = (u32)q->qi_btimelimit;
|
||||
tstate->ino_timelimit = (u32)q->qi_itimelimit;
|
||||
tstate->rt_spc_timelimit = (u32)q->qi_rtbtimelimit;
|
||||
tstate->spc_warnlimit = q->qi_bwarnlimit;
|
||||
tstate->ino_warnlimit = q->qi_iwarnlimit;
|
||||
tstate->rt_spc_warnlimit = q->qi_rtbwarnlimit;
|
||||
|
|
|
@ -223,8 +223,8 @@ xfs_reflink_trim_around_shared(
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
xfs_inode_need_cow(
|
||||
int
|
||||
xfs_bmap_trim_cow(
|
||||
struct xfs_inode *ip,
|
||||
struct xfs_bmbt_irec *imap,
|
||||
bool *shared)
|
||||
|
@ -327,7 +327,7 @@ xfs_find_trim_cow_extent(
|
|||
if (cmap->br_startoff > offset_fsb) {
|
||||
xfs_trim_extent(imap, 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;
|
||||
|
@ -1457,7 +1457,8 @@ xfs_reflink_clear_inode_flag(
|
|||
* We didn't find any shared blocks so turn off the reflink flag.
|
||||
* 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)
|
||||
return error;
|
||||
|
||||
|
|
|
@ -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);
|
||||
extern int xfs_reflink_trim_around_shared(struct xfs_inode *ip,
|
||||
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);
|
||||
|
||||
int xfs_reflink_allocate_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap,
|
||||
|
|
|
@ -193,32 +193,6 @@ xfs_fs_show_options(
|
|||
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
|
||||
* filesystem size and inode32/inode64 mount options; i.e. specifically
|
||||
|
@ -1424,6 +1398,26 @@ xfs_fc_fill_super(
|
|||
if (error)
|
||||
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);
|
||||
if (error)
|
||||
goto out_free_sb;
|
||||
|
@ -1435,7 +1429,7 @@ xfs_fc_fill_super(
|
|||
sb->s_magic = XFS_SUPER_MAGIC;
|
||||
sb->s_blocksize = mp->m_sb.sb_blocksize;
|
||||
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_time_gran = 1;
|
||||
sb->s_time_min = S32_MIN;
|
||||
|
|
|
@ -580,7 +580,7 @@ xfs_trans_dqresv(
|
|||
{
|
||||
xfs_qcnt_t hardlimit;
|
||||
xfs_qcnt_t softlimit;
|
||||
time_t timer;
|
||||
time64_t timer;
|
||||
xfs_qwarncnt_t warns;
|
||||
xfs_qwarncnt_t warnlimit;
|
||||
xfs_qcnt_t total_count;
|
||||
|
@ -635,7 +635,8 @@ xfs_trans_dqresv(
|
|||
goto error_return;
|
||||
}
|
||||
if (softlimit && total_count > softlimit) {
|
||||
if ((timer != 0 && get_seconds() > timer) ||
|
||||
if ((timer != 0 &&
|
||||
ktime_get_real_seconds() > timer) ||
|
||||
(warns != 0 && warns >= warnlimit)) {
|
||||
xfs_quota_warn(mp, dqp,
|
||||
QUOTA_NL_BSOFTLONGWARN);
|
||||
|
@ -662,7 +663,8 @@ xfs_trans_dqresv(
|
|||
goto error_return;
|
||||
}
|
||||
if (softlimit && total_count > softlimit) {
|
||||
if ((timer != 0 && get_seconds() > timer) ||
|
||||
if ((timer != 0 &&
|
||||
ktime_get_real_seconds() > timer) ||
|
||||
(warns != 0 && warns >= warnlimit)) {
|
||||
xfs_quota_warn(mp, dqp,
|
||||
QUOTA_NL_ISOFTLONGWARN);
|
||||
|
|
|
@ -24,6 +24,7 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
|
|||
int xflags = handler->flags;
|
||||
struct xfs_inode *ip = XFS_I(inode);
|
||||
int error, asize = size;
|
||||
size_t namelen = strlen(name);
|
||||
|
||||
/* Convert Linux syscall to XFS internal ATTR flags */
|
||||
if (!size) {
|
||||
|
@ -31,7 +32,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
|
|||
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)
|
||||
return error;
|
||||
return asize;
|
||||
|
@ -67,6 +69,7 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
|
|||
int xflags = handler->flags;
|
||||
struct xfs_inode *ip = XFS_I(inode);
|
||||
int error;
|
||||
size_t namelen = strlen(name);
|
||||
|
||||
/* Convert Linux syscall to XFS internal ATTR flags */
|
||||
if (flags & XATTR_CREATE)
|
||||
|
@ -74,10 +77,11 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
|
|||
if (flags & XATTR_REPLACE)
|
||||
xflags |= ATTR_REPLACE;
|
||||
|
||||
if (!value)
|
||||
return xfs_attr_remove(ip, (unsigned char *)name, xflags);
|
||||
error = xfs_attr_set(ip, (unsigned char *)name,
|
||||
(void *)value, size, xflags);
|
||||
if (value)
|
||||
error = xfs_attr_set(ip, name, namelen, (void *)value, size,
|
||||
xflags);
|
||||
else
|
||||
error = xfs_attr_remove(ip, name, namelen, xflags);
|
||||
if (!error)
|
||||
xfs_forget_acl(inode, name, xflags);
|
||||
|
||||
|
|
Loading…
Reference in New Issue