Commit 4dd58158 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'akpm' (patches from Andrew)

Merge more fixes from Andrew Morton:
 "17 fixes"

Mostly mm fixes and one ocfs2 locking fix.

* emailed patches from Andrew Morton <akpm@linux-foundation.org>:
  mm: memcontrol: fix network errors from failing __GFP_ATOMIC charges
  mm/memory_hotplug: fix updating the node span
  scripts/gdb: fix debugging modules compiled with hot/cold partitioning
  mm: slab: make page_cgroup_ino() to recognize non-compound slab pages properly
  MAINTAINERS: update information for "MEMORY MANAGEMENT"
  dump_stack: avoid the livelock of the dump_lock
  zswap: add Vitaly to the maintainers list
  mm/page_alloc.c: ratelimit allocation failure warnings more aggressively
  mm/khugepaged: fix might_sleep() warn with CONFIG_HIGHPTE=y
  mm, vmstat: reduce zone->lock holding time by /proc/pagetypeinfo
  mm, vmstat: hide /proc/pagetypeinfo from normal users
  mm/mmu_notifiers: use the right return code for WARN_ON
  ocfs2: protect extent tree in ocfs2_prepare_inode_for_write()
  mm: thp: handle page cache THP correctly in PageTransCompoundMap
  mm, meminit: recalculate pcpu batch and high limits after init completes
  mm/gup_benchmark: fix MAP_HUGETLB case
  mm: memcontrol: fix NULL-ptr deref in percpu stats flush
parents 26bc6721 869712fd
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -10519,8 +10519,12 @@ F: mm/memblock.c
F:	Documentation/core-api/boot-time-mm.rst
MEMORY MANAGEMENT
M:	Andrew Morton <akpm@linux-foundation.org>
L:	linux-mm@kvack.org
W:	http://www.linux-mm.org
T:	quilt https://ozlabs.org/~akpm/mmotm/
T:	quilt https://ozlabs.org/~akpm/mmots/
T:	git git://github.com/hnaz/linux-mm.git
S:	Maintained
F:	include/linux/mm.h
F:	include/linux/gfp.h
@@ -18034,6 +18038,7 @@ F: Documentation/vm/zsmalloc.rst
ZSWAP COMPRESSED SWAP CACHING
M:	Seth Jennings <sjenning@redhat.com>
M:	Dan Streetman <ddstreet@ieee.org>
M:	Vitaly Wool <vitaly.wool@konsulko.com>
L:	linux-mm@kvack.org
S:	Maintained
F:	mm/zswap.c
+90 −44
Original line number Diff line number Diff line
@@ -2098,53 +2098,89 @@ static int ocfs2_is_io_unaligned(struct inode *inode, size_t count, loff_t pos)
	return 0;
}

static int ocfs2_prepare_inode_for_refcount(struct inode *inode,
					    struct file *file,
					    loff_t pos, size_t count,
					    int *meta_level)
static int ocfs2_inode_lock_for_extent_tree(struct inode *inode,
					    struct buffer_head **di_bh,
					    int meta_level,
					    int overwrite_io,
					    int write_sem,
					    int wait)
{
	int ret;
	struct buffer_head *di_bh = NULL;
	u32 cpos = pos >> OCFS2_SB(inode->i_sb)->s_clustersize_bits;
	u32 clusters =
		ocfs2_clusters_for_bytes(inode->i_sb, pos + count) - cpos;
	int ret = 0;

	ret = ocfs2_inode_lock(inode, &di_bh, 1);
	if (ret) {
		mlog_errno(ret);
	if (wait)
		ret = ocfs2_inode_lock(inode, NULL, meta_level);
	else
		ret = ocfs2_try_inode_lock(inode,
			overwrite_io ? NULL : di_bh, meta_level);
	if (ret < 0)
		goto out;

	if (wait) {
		if (write_sem)
			down_write(&OCFS2_I(inode)->ip_alloc_sem);
		else
			down_read(&OCFS2_I(inode)->ip_alloc_sem);
	} else {
		if (write_sem)
			ret = down_write_trylock(&OCFS2_I(inode)->ip_alloc_sem);
		else
			ret = down_read_trylock(&OCFS2_I(inode)->ip_alloc_sem);

		if (!ret) {
			ret = -EAGAIN;
			goto out_unlock;
		}
	}

	*meta_level = 1;
	return ret;

	ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters, UINT_MAX);
	if (ret)
		mlog_errno(ret);
out_unlock:
	brelse(*di_bh);
	ocfs2_inode_unlock(inode, meta_level);
out:
	brelse(di_bh);
	return ret;
}

static void ocfs2_inode_unlock_for_extent_tree(struct inode *inode,
					       struct buffer_head **di_bh,
					       int meta_level,
					       int write_sem)
{
	if (write_sem)
		up_write(&OCFS2_I(inode)->ip_alloc_sem);
	else
		up_read(&OCFS2_I(inode)->ip_alloc_sem);

	brelse(*di_bh);
	*di_bh = NULL;

	if (meta_level >= 0)
		ocfs2_inode_unlock(inode, meta_level);
}

static int ocfs2_prepare_inode_for_write(struct file *file,
					 loff_t pos, size_t count, int wait)
{
	int ret = 0, meta_level = 0, overwrite_io = 0;
	int write_sem = 0;
	struct dentry *dentry = file->f_path.dentry;
	struct inode *inode = d_inode(dentry);
	struct buffer_head *di_bh = NULL;
	u32 cpos;
	u32 clusters;

	/*
	 * We start with a read level meta lock and only jump to an ex
	 * if we need to make modifications here.
	 */
	for(;;) {
		if (wait)
			ret = ocfs2_inode_lock(inode, NULL, meta_level);
		else
			ret = ocfs2_try_inode_lock(inode,
				overwrite_io ? NULL : &di_bh, meta_level);
		ret = ocfs2_inode_lock_for_extent_tree(inode,
						       &di_bh,
						       meta_level,
						       overwrite_io,
						       write_sem,
						       wait);
		if (ret < 0) {
			meta_level = -1;
			if (ret != -EAGAIN)
				mlog_errno(ret);
			goto out;
@@ -2156,15 +2192,8 @@ static int ocfs2_prepare_inode_for_write(struct file *file,
		 */
		if (!wait && !overwrite_io) {
			overwrite_io = 1;
			if (!down_read_trylock(&OCFS2_I(inode)->ip_alloc_sem)) {
				ret = -EAGAIN;
				goto out_unlock;
			}

			ret = ocfs2_overwrite_io(inode, di_bh, pos, count);
			brelse(di_bh);
			di_bh = NULL;
			up_read(&OCFS2_I(inode)->ip_alloc_sem);
			if (ret < 0) {
				if (ret != -EAGAIN)
					mlog_errno(ret);
@@ -2183,7 +2212,10 @@ static int ocfs2_prepare_inode_for_write(struct file *file,
		 * set inode->i_size at the end of a write. */
		if (should_remove_suid(dentry)) {
			if (meta_level == 0) {
				ocfs2_inode_unlock(inode, meta_level);
				ocfs2_inode_unlock_for_extent_tree(inode,
								   &di_bh,
								   meta_level,
								   write_sem);
				meta_level = 1;
				continue;
			}
@@ -2197,17 +2229,31 @@ static int ocfs2_prepare_inode_for_write(struct file *file,

		ret = ocfs2_check_range_for_refcount(inode, pos, count);
		if (ret == 1) {
			ocfs2_inode_unlock(inode, meta_level);
			meta_level = -1;
			ocfs2_inode_unlock_for_extent_tree(inode,
							   &di_bh,
							   meta_level,
							   write_sem);
			ret = ocfs2_inode_lock_for_extent_tree(inode,
							       &di_bh,
							       meta_level,
							       overwrite_io,
							       1,
							       wait);
			write_sem = 1;
			if (ret < 0) {
				if (ret != -EAGAIN)
					mlog_errno(ret);
				goto out;
			}

			ret = ocfs2_prepare_inode_for_refcount(inode,
							       file,
							       pos,
							       count,
							       &meta_level);
			cpos = pos >> OCFS2_SB(inode->i_sb)->s_clustersize_bits;
			clusters =
				ocfs2_clusters_for_bytes(inode->i_sb, pos + count) - cpos;
			ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters, UINT_MAX);
		}

		if (ret < 0) {
			if (ret != -EAGAIN)
				mlog_errno(ret);
			goto out_unlock;
		}
@@ -2219,10 +2265,10 @@ out_unlock:
	trace_ocfs2_prepare_inode_for_write(OCFS2_I(inode)->ip_blkno,
					    pos, count, wait);

	brelse(di_bh);

	if (meta_level >= 0)
		ocfs2_inode_unlock(inode, meta_level);
	ocfs2_inode_unlock_for_extent_tree(inode,
					   &di_bh,
					   meta_level,
					   write_sem);

out:
	return ret;
+0 −5
Original line number Diff line number Diff line
@@ -695,11 +695,6 @@ static inline void *kvcalloc(size_t n, size_t size, gfp_t flags)

extern void kvfree(const void *addr);

static inline atomic_t *compound_mapcount_ptr(struct page *page)
{
	return &page[1].compound_mapcount;
}

static inline int compound_mapcount(struct page *page)
{
	VM_BUG_ON_PAGE(!PageCompound(page), page);
+5 −0
Original line number Diff line number Diff line
@@ -221,6 +221,11 @@ struct page {
#endif
} _struct_page_alignment;

static inline atomic_t *compound_mapcount_ptr(struct page *page)
{
	return &page[1].compound_mapcount;
}

/*
 * Used for sizing the vmemmap region on some architectures
 */
+18 −2
Original line number Diff line number Diff line
@@ -622,12 +622,28 @@ static inline int PageTransCompound(struct page *page)
 *
 * Unlike PageTransCompound, this is safe to be called only while
 * split_huge_pmd() cannot run from under us, like if protected by the
 * MMU notifier, otherwise it may result in page->_mapcount < 0 false
 * MMU notifier, otherwise it may result in page->_mapcount check false
 * positives.
 *
 * We have to treat page cache THP differently since every subpage of it
 * would get _mapcount inc'ed once it is PMD mapped.  But, it may be PTE
 * mapped in the current process so comparing subpage's _mapcount to
 * compound_mapcount to filter out PTE mapped case.
 */
static inline int PageTransCompoundMap(struct page *page)
{
	return PageTransCompound(page) && atomic_read(&page->_mapcount) < 0;
	struct page *head;

	if (!PageTransCompound(page))
		return 0;

	if (PageAnon(page))
		return atomic_read(&page->_mapcount) < 0;

	head = compound_head(page);
	/* File THP is PMD mapped and not PTE mapped */
	return atomic_read(&page->_mapcount) ==
	       atomic_read(compound_mapcount_ptr(head));
}

/*
Loading