mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
Merge a349e4c659 ("Merge tag 'xfs-5.10-fixes-7' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux") into android-mainline
Steps on the way to 5.10-rc5 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: Idd51203521e6bc05f6648743b2b10c92beba865d
This commit is contained in:
@@ -178,6 +178,7 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct dentry *parent;
|
||||
bool parent_watched = dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED;
|
||||
bool parent_needed, parent_interested;
|
||||
__u32 p_mask;
|
||||
struct inode *p_inode = NULL;
|
||||
struct name_snapshot name;
|
||||
@@ -193,7 +194,8 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
|
||||
return 0;
|
||||
|
||||
parent = NULL;
|
||||
if (!parent_watched && !fsnotify_event_needs_parent(inode, mnt, mask))
|
||||
parent_needed = fsnotify_event_needs_parent(inode, mnt, mask);
|
||||
if (!parent_watched && !parent_needed)
|
||||
goto notify;
|
||||
|
||||
/* Does parent inode care about events on children? */
|
||||
@@ -205,17 +207,17 @@ int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data,
|
||||
|
||||
/*
|
||||
* Include parent/name in notification either if some notification
|
||||
* groups require parent info (!parent_watched case) or the parent is
|
||||
* interested in this event.
|
||||
* groups require parent info or the parent is interested in this event.
|
||||
*/
|
||||
if (!parent_watched || (mask & p_mask & ALL_FSNOTIFY_EVENTS)) {
|
||||
parent_interested = mask & p_mask & ALL_FSNOTIFY_EVENTS;
|
||||
if (parent_needed || parent_interested) {
|
||||
/* When notifying parent, child should be passed as data */
|
||||
WARN_ON_ONCE(inode != fsnotify_data_inode(data, data_type));
|
||||
|
||||
/* Notify both parent and child with child name info */
|
||||
take_dentry_name_snapshot(&name, dentry);
|
||||
file_name = &name.name;
|
||||
if (parent_watched)
|
||||
if (parent_interested)
|
||||
mask |= FS_EVENT_ON_CHILD;
|
||||
}
|
||||
|
||||
|
||||
@@ -515,7 +515,7 @@ xfs_attr_copy_value(
|
||||
*========================================================================*/
|
||||
|
||||
/*
|
||||
* Query whether the requested number of additional bytes of extended
|
||||
* Query whether the total requested number of attr fork bytes of extended
|
||||
* attribute space will be able to fit inline.
|
||||
*
|
||||
* Returns zero if not, else the di_forkoff fork offset to be used in the
|
||||
@@ -535,6 +535,12 @@ xfs_attr_shortform_bytesfit(
|
||||
int maxforkoff;
|
||||
int offset;
|
||||
|
||||
/*
|
||||
* Check if the new size could fit at all first:
|
||||
*/
|
||||
if (bytes > XFS_LITINO(mp))
|
||||
return 0;
|
||||
|
||||
/* rounded down */
|
||||
offset = (XFS_LITINO(mp) - bytes) >> 3;
|
||||
|
||||
|
||||
@@ -243,8 +243,8 @@ xfs_rmapbt_key_diff(
|
||||
else if (y > x)
|
||||
return -1;
|
||||
|
||||
x = be64_to_cpu(kp->rm_offset);
|
||||
y = xfs_rmap_irec_offset_pack(rec);
|
||||
x = XFS_RMAP_OFF(be64_to_cpu(kp->rm_offset));
|
||||
y = rec->rm_offset;
|
||||
if (x > y)
|
||||
return 1;
|
||||
else if (y > x)
|
||||
@@ -275,8 +275,8 @@ xfs_rmapbt_diff_two_keys(
|
||||
else if (y > x)
|
||||
return -1;
|
||||
|
||||
x = be64_to_cpu(kp1->rm_offset);
|
||||
y = be64_to_cpu(kp2->rm_offset);
|
||||
x = XFS_RMAP_OFF(be64_to_cpu(kp1->rm_offset));
|
||||
y = XFS_RMAP_OFF(be64_to_cpu(kp2->rm_offset));
|
||||
if (x > y)
|
||||
return 1;
|
||||
else if (y > x)
|
||||
@@ -390,8 +390,8 @@ xfs_rmapbt_keys_inorder(
|
||||
return 1;
|
||||
else if (a > b)
|
||||
return 0;
|
||||
a = be64_to_cpu(k1->rmap.rm_offset);
|
||||
b = be64_to_cpu(k2->rmap.rm_offset);
|
||||
a = XFS_RMAP_OFF(be64_to_cpu(k1->rmap.rm_offset));
|
||||
b = XFS_RMAP_OFF(be64_to_cpu(k2->rmap.rm_offset));
|
||||
if (a <= b)
|
||||
return 1;
|
||||
return 0;
|
||||
@@ -420,8 +420,8 @@ xfs_rmapbt_recs_inorder(
|
||||
return 1;
|
||||
else if (a > b)
|
||||
return 0;
|
||||
a = be64_to_cpu(r1->rmap.rm_offset);
|
||||
b = be64_to_cpu(r2->rmap.rm_offset);
|
||||
a = XFS_RMAP_OFF(be64_to_cpu(r1->rmap.rm_offset));
|
||||
b = XFS_RMAP_OFF(be64_to_cpu(r2->rmap.rm_offset));
|
||||
if (a <= b)
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
@@ -218,13 +218,13 @@ xchk_bmap_xref_rmap(
|
||||
* which doesn't track unwritten state.
|
||||
*/
|
||||
if (owner != XFS_RMAP_OWN_COW &&
|
||||
irec->br_state == XFS_EXT_UNWRITTEN &&
|
||||
!(rmap.rm_flags & XFS_RMAP_UNWRITTEN))
|
||||
!!(irec->br_state == XFS_EXT_UNWRITTEN) !=
|
||||
!!(rmap.rm_flags & XFS_RMAP_UNWRITTEN))
|
||||
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
|
||||
irec->br_startoff);
|
||||
|
||||
if (info->whichfork == XFS_ATTR_FORK &&
|
||||
!(rmap.rm_flags & XFS_RMAP_ATTR_FORK))
|
||||
if (!!(info->whichfork == XFS_ATTR_FORK) !=
|
||||
!!(rmap.rm_flags & XFS_RMAP_ATTR_FORK))
|
||||
xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
|
||||
irec->br_startoff);
|
||||
if (rmap.rm_flags & XFS_RMAP_BMBT_BLOCK)
|
||||
|
||||
@@ -452,32 +452,41 @@ xchk_btree_check_minrecs(
|
||||
int level,
|
||||
struct xfs_btree_block *block)
|
||||
{
|
||||
unsigned int numrecs;
|
||||
int ok_level;
|
||||
|
||||
numrecs = be16_to_cpu(block->bb_numrecs);
|
||||
struct xfs_btree_cur *cur = bs->cur;
|
||||
unsigned int root_level = cur->bc_nlevels - 1;
|
||||
unsigned int numrecs = be16_to_cpu(block->bb_numrecs);
|
||||
|
||||
/* More records than minrecs means the block is ok. */
|
||||
if (numrecs >= bs->cur->bc_ops->get_minrecs(bs->cur, level))
|
||||
if (numrecs >= cur->bc_ops->get_minrecs(cur, level))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Certain btree blocks /can/ have fewer than minrecs records. Any
|
||||
* level greater than or equal to the level of the highest dedicated
|
||||
* btree block are allowed to violate this constraint.
|
||||
*
|
||||
* For a btree rooted in a block, the btree root can have fewer than
|
||||
* minrecs records. If the btree is rooted in an inode and does not
|
||||
* store records in the root, the direct children of the root and the
|
||||
* root itself can have fewer than minrecs records.
|
||||
* For btrees rooted in the inode, it's possible that the root block
|
||||
* contents spilled into a regular ondisk block because there wasn't
|
||||
* enough space in the inode root. The number of records in that
|
||||
* child block might be less than the standard minrecs, but that's ok
|
||||
* provided that there's only one direct child of the root.
|
||||
*/
|
||||
ok_level = bs->cur->bc_nlevels - 1;
|
||||
if (bs->cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
|
||||
ok_level--;
|
||||
if (level >= ok_level)
|
||||
return;
|
||||
if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
|
||||
level == cur->bc_nlevels - 2) {
|
||||
struct xfs_btree_block *root_block;
|
||||
struct xfs_buf *root_bp;
|
||||
int root_maxrecs;
|
||||
|
||||
xchk_btree_set_corrupt(bs->sc, bs->cur, level);
|
||||
root_block = xfs_btree_get_block(cur, root_level, &root_bp);
|
||||
root_maxrecs = cur->bc_ops->get_dmaxrecs(cur, root_level);
|
||||
if (be16_to_cpu(root_block->bb_numrecs) != 1 ||
|
||||
numrecs <= root_maxrecs)
|
||||
xchk_btree_set_corrupt(bs->sc, cur, level);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, only the root level is allowed to have fewer than minrecs
|
||||
* records or keyptrs.
|
||||
*/
|
||||
if (level < root_level)
|
||||
xchk_btree_set_corrupt(bs->sc, cur, level);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -558,14 +558,27 @@ xchk_directory_leaf1_bestfree(
|
||||
/* Check all the bestfree entries. */
|
||||
for (i = 0; i < bestcount; i++, bestp++) {
|
||||
best = be16_to_cpu(*bestp);
|
||||
if (best == NULLDATAOFF)
|
||||
continue;
|
||||
error = xfs_dir3_data_read(sc->tp, sc->ip,
|
||||
i * args->geo->fsbcount, 0, &dbp);
|
||||
xfs_dir2_db_to_da(args->geo, i),
|
||||
XFS_DABUF_MAP_HOLE_OK,
|
||||
&dbp);
|
||||
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk,
|
||||
&error))
|
||||
break;
|
||||
xchk_directory_check_freesp(sc, lblk, dbp, best);
|
||||
|
||||
if (!dbp) {
|
||||
if (best != NULLDATAOFF) {
|
||||
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,
|
||||
lblk);
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (best == NULLDATAOFF)
|
||||
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
|
||||
else
|
||||
xchk_directory_check_freesp(sc, lblk, dbp, best);
|
||||
xfs_trans_brelse(sc->tp, dbp);
|
||||
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
|
||||
break;
|
||||
|
||||
@@ -706,6 +706,23 @@ relock:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the imap we are going to return to the caller spans the entire
|
||||
* range that the caller requested for the IO.
|
||||
*/
|
||||
static bool
|
||||
imap_spans_range(
|
||||
struct xfs_bmbt_irec *imap,
|
||||
xfs_fileoff_t offset_fsb,
|
||||
xfs_fileoff_t end_fsb)
|
||||
{
|
||||
if (imap->br_startoff > offset_fsb)
|
||||
return false;
|
||||
if (imap->br_startoff + imap->br_blockcount < end_fsb)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
xfs_direct_write_iomap_begin(
|
||||
struct inode *inode,
|
||||
@@ -766,6 +783,18 @@ xfs_direct_write_iomap_begin(
|
||||
if (imap_needs_alloc(inode, flags, &imap, nimaps))
|
||||
goto allocate_blocks;
|
||||
|
||||
/*
|
||||
* NOWAIT IO needs to span the entire requested IO with a single map so
|
||||
* that we avoid partial IO failures due to the rest of the IO range not
|
||||
* covered by this map triggering an EAGAIN condition when it is
|
||||
* subsequently mapped and aborting the IO.
|
||||
*/
|
||||
if ((flags & IOMAP_NOWAIT) &&
|
||||
!imap_spans_range(&imap, offset_fsb, end_fsb)) {
|
||||
error = -EAGAIN;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
xfs_iunlock(ip, lockmode);
|
||||
trace_xfs_iomap_found(ip, offset, length, XFS_DATA_FORK, &imap);
|
||||
return xfs_bmbt_to_iomap(ip, iomap, &imap, iomap_flags);
|
||||
|
||||
@@ -55,6 +55,9 @@ struct xfs_iwalk_ag {
|
||||
/* Where do we start the traversal? */
|
||||
xfs_ino_t startino;
|
||||
|
||||
/* What was the last inode number we saw when iterating the inobt? */
|
||||
xfs_ino_t lastino;
|
||||
|
||||
/* Array of inobt records we cache. */
|
||||
struct xfs_inobt_rec_incore *recs;
|
||||
|
||||
@@ -301,6 +304,9 @@ xfs_iwalk_ag_start(
|
||||
if (XFS_IS_CORRUPT(mp, *has_more != 1))
|
||||
return -EFSCORRUPTED;
|
||||
|
||||
iwag->lastino = XFS_AGINO_TO_INO(mp, agno,
|
||||
irec->ir_startino + XFS_INODES_PER_CHUNK - 1);
|
||||
|
||||
/*
|
||||
* If the LE lookup yielded an inobt record before the cursor position,
|
||||
* skip it and see if there's another one after it.
|
||||
@@ -347,15 +353,17 @@ xfs_iwalk_run_callbacks(
|
||||
struct xfs_mount *mp = iwag->mp;
|
||||
struct xfs_trans *tp = iwag->tp;
|
||||
struct xfs_inobt_rec_incore *irec;
|
||||
xfs_agino_t restart;
|
||||
xfs_agino_t next_agino;
|
||||
int error;
|
||||
|
||||
next_agino = XFS_INO_TO_AGINO(mp, iwag->lastino) + 1;
|
||||
|
||||
ASSERT(iwag->nr_recs > 0);
|
||||
|
||||
/* Delete cursor but remember the last record we cached... */
|
||||
xfs_iwalk_del_inobt(tp, curpp, agi_bpp, 0);
|
||||
irec = &iwag->recs[iwag->nr_recs - 1];
|
||||
restart = irec->ir_startino + XFS_INODES_PER_CHUNK - 1;
|
||||
ASSERT(next_agino == irec->ir_startino + XFS_INODES_PER_CHUNK);
|
||||
|
||||
error = xfs_iwalk_ag_recs(iwag);
|
||||
if (error)
|
||||
@@ -372,7 +380,7 @@ xfs_iwalk_run_callbacks(
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return xfs_inobt_lookup(*curpp, restart, XFS_LOOKUP_GE, has_more);
|
||||
return xfs_inobt_lookup(*curpp, next_agino, XFS_LOOKUP_GE, has_more);
|
||||
}
|
||||
|
||||
/* Walk all inodes in a single AG, from @iwag->startino to the end of the AG. */
|
||||
@@ -396,6 +404,7 @@ xfs_iwalk_ag(
|
||||
|
||||
while (!error && has_more) {
|
||||
struct xfs_inobt_rec_incore *irec;
|
||||
xfs_ino_t rec_fsino;
|
||||
|
||||
cond_resched();
|
||||
if (xfs_pwork_want_abort(&iwag->pwork))
|
||||
@@ -407,6 +416,15 @@ xfs_iwalk_ag(
|
||||
if (error || !has_more)
|
||||
break;
|
||||
|
||||
/* Make sure that we always move forward. */
|
||||
rec_fsino = XFS_AGINO_TO_INO(mp, agno, irec->ir_startino);
|
||||
if (iwag->lastino != NULLFSINO &&
|
||||
XFS_IS_CORRUPT(mp, iwag->lastino >= rec_fsino)) {
|
||||
error = -EFSCORRUPTED;
|
||||
goto out;
|
||||
}
|
||||
iwag->lastino = rec_fsino + XFS_INODES_PER_CHUNK - 1;
|
||||
|
||||
/* No allocated inodes in this chunk; skip it. */
|
||||
if (iwag->skip_empty && irec->ir_freecount == irec->ir_count) {
|
||||
error = xfs_btree_increment(cur, 0, &has_more);
|
||||
@@ -535,6 +553,7 @@ xfs_iwalk(
|
||||
.trim_start = 1,
|
||||
.skip_empty = 1,
|
||||
.pwork = XFS_PWORK_SINGLE_THREADED,
|
||||
.lastino = NULLFSINO,
|
||||
};
|
||||
xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, startino);
|
||||
int error;
|
||||
@@ -623,6 +642,7 @@ xfs_iwalk_threaded(
|
||||
iwag->data = data;
|
||||
iwag->startino = startino;
|
||||
iwag->sz_recs = xfs_iwalk_prefetch(inode_records);
|
||||
iwag->lastino = NULLFSINO;
|
||||
xfs_pwork_queue(&pctl, &iwag->pwork);
|
||||
startino = XFS_AGINO_TO_INO(mp, agno + 1, 0);
|
||||
if (flags & XFS_INOBT_WALK_SAME_AG)
|
||||
@@ -696,6 +716,7 @@ xfs_inobt_walk(
|
||||
.startino = startino,
|
||||
.sz_recs = xfs_inobt_walk_prefetch(inobt_records),
|
||||
.pwork = XFS_PWORK_SINGLE_THREADED,
|
||||
.lastino = NULLFSINO,
|
||||
};
|
||||
xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, startino);
|
||||
int error;
|
||||
|
||||
@@ -194,20 +194,25 @@ xfs_initialize_perag(
|
||||
}
|
||||
|
||||
pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL);
|
||||
if (!pag)
|
||||
if (!pag) {
|
||||
error = -ENOMEM;
|
||||
goto out_unwind_new_pags;
|
||||
}
|
||||
pag->pag_agno = index;
|
||||
pag->pag_mount = mp;
|
||||
spin_lock_init(&pag->pag_ici_lock);
|
||||
INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
|
||||
if (xfs_buf_hash_init(pag))
|
||||
|
||||
error = xfs_buf_hash_init(pag);
|
||||
if (error)
|
||||
goto out_free_pag;
|
||||
init_waitqueue_head(&pag->pagb_wait);
|
||||
spin_lock_init(&pag->pagb_lock);
|
||||
pag->pagb_count = 0;
|
||||
pag->pagb_tree = RB_ROOT;
|
||||
|
||||
if (radix_tree_preload(GFP_NOFS))
|
||||
error = radix_tree_preload(GFP_NOFS);
|
||||
if (error)
|
||||
goto out_hash_destroy;
|
||||
|
||||
spin_lock(&mp->m_perag_lock);
|
||||
|
||||
@@ -264,17 +264,11 @@ static int ptrace_check_attach(struct task_struct *child, bool ignore_state)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool ptrace_has_cap(const struct cred *cred, struct user_namespace *ns,
|
||||
unsigned int mode)
|
||||
static bool ptrace_has_cap(struct user_namespace *ns, unsigned int mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (mode & PTRACE_MODE_NOAUDIT)
|
||||
ret = security_capable(cred, ns, CAP_SYS_PTRACE, CAP_OPT_NOAUDIT);
|
||||
else
|
||||
ret = security_capable(cred, ns, CAP_SYS_PTRACE, CAP_OPT_NONE);
|
||||
|
||||
return ret == 0;
|
||||
return ns_capable_noaudit(ns, CAP_SYS_PTRACE);
|
||||
return ns_capable(ns, CAP_SYS_PTRACE);
|
||||
}
|
||||
|
||||
/* Returns 0 on success, -errno on denial. */
|
||||
@@ -326,7 +320,7 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
|
||||
gid_eq(caller_gid, tcred->sgid) &&
|
||||
gid_eq(caller_gid, tcred->gid))
|
||||
goto ok;
|
||||
if (ptrace_has_cap(cred, tcred->user_ns, mode))
|
||||
if (ptrace_has_cap(tcred->user_ns, mode))
|
||||
goto ok;
|
||||
rcu_read_unlock();
|
||||
return -EPERM;
|
||||
@@ -345,7 +339,7 @@ ok:
|
||||
mm = task->mm;
|
||||
if (mm &&
|
||||
((get_dumpable(mm) != SUID_DUMP_USER) &&
|
||||
!ptrace_has_cap(cred, mm->user_ns, mode)))
|
||||
!ptrace_has_cap(mm->user_ns, mode)))
|
||||
return -EPERM;
|
||||
|
||||
return security_ptrace_access_check(task, mode);
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#include <linux/filter.h>
|
||||
#include <linux/pid.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/tracehook.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/anon_inodes.h>
|
||||
@@ -558,8 +558,7 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
|
||||
* behavior of privileged children.
|
||||
*/
|
||||
if (!task_no_new_privs(current) &&
|
||||
security_capable(current_cred(), current_user_ns(),
|
||||
CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) != 0)
|
||||
!ns_capable_noaudit(current_user_ns(), CAP_SYS_ADMIN))
|
||||
return ERR_PTR(-EACCES);
|
||||
|
||||
/* Allocate a new seccomp_filter */
|
||||
|
||||
@@ -1758,10 +1758,10 @@ TEST_F(TRACE_poke, getpid_runs_normally)
|
||||
* and the code is stored as a positive value. \
|
||||
*/ \
|
||||
if (_result < 0) { \
|
||||
SYSCALL_RET(_regs) = -result; \
|
||||
SYSCALL_RET(_regs) = -_result; \
|
||||
(_regs).ccr |= 0x10000000; \
|
||||
} else { \
|
||||
SYSCALL_RET(_regs) = result; \
|
||||
SYSCALL_RET(_regs) = _result; \
|
||||
(_regs).ccr &= ~0x10000000; \
|
||||
} \
|
||||
} while (0)
|
||||
@@ -1804,8 +1804,8 @@ TEST_F(TRACE_poke, getpid_runs_normally)
|
||||
#define SYSCALL_RET(_regs) (_regs).a[(_regs).windowbase * 4 + 2]
|
||||
#elif defined(__sh__)
|
||||
# define ARCH_REGS struct pt_regs
|
||||
# define SYSCALL_NUM(_regs) (_regs).gpr[3]
|
||||
# define SYSCALL_RET(_regs) (_regs).gpr[0]
|
||||
# define SYSCALL_NUM(_regs) (_regs).regs[3]
|
||||
# define SYSCALL_RET(_regs) (_regs).regs[0]
|
||||
#else
|
||||
# error "Do not know how to find your architecture's registers and syscalls"
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user