Re: [PATCH RESEND 2/2] fs/aio: Add support to aio ring pages migration

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Ben,

On 07/16/2013 09:34 PM, Benjamin LaHaise wrote:

> On Tue, Jul 16, 2013 at 05:56:16PM +0800, Gu Zheng wrote:
>> As the aio job will pin the ring pages, that will lead to mem migrated
>> failed. In order to fix this problem we use an anon inode to manage the aio ring
>> pages, and  setup the migratepage callback in the anon inode's address space, so
>> that when mem migrating the aio ring pages will be moved to other mem node safely.
> 
> There are a few minor issues that needed to be fixed -- see below.  I've 
> made these changes and added them to git://git.kvack.org/~bcrl/aio-next.git ,
> and will ask for that tree to be included in linux-next.

Thanks very much, and your review.
Stephen sent out a build failed msg when merger this patch into next-tree from your aio_next.
This is because we use migrate_page_move_mapping() which is protected by CONFIG_MIGRATION, I'll
fix this issue in the next version.

Best regards,
Gu
  

> 
> mm folks: can someone familiar with page migration / hot plug memory please 
> review the migration changes?
> 
>>
>> Signed-off-by: Gu Zheng <guz.fnst@xxxxxxxxxxxxxx>
>> Signed-off-by: Benjamin LaHaise <bcrl@xxxxxxxxx>
> 
> Again, I had not provided my Signed-off-by on this patch previously, so 
> don't add it for me.

Sorry again.:)

> 
>> ---
>>  fs/aio.c                |  120 ++++++++++++++++++++++++++++++++++++++++++----
>>  include/linux/migrate.h |    3 +
>>  mm/migrate.c            |    2 +-
>>  3 files changed, 113 insertions(+), 12 deletions(-)
>>
>> diff --git a/fs/aio.c b/fs/aio.c
>> index 9b5ca11..d10f956 100644
>> --- a/fs/aio.c
>> +++ b/fs/aio.c
>> @@ -35,6 +35,9 @@
>>  #include <linux/eventfd.h>
>>  #include <linux/blkdev.h>
>>  #include <linux/compat.h>
>> +#include <linux/anon_inodes.h>
>> +#include <linux/migrate.h>
>> +#include <linux/ramfs.h>
>>  
>>  #include <asm/kmap_types.h>
>>  #include <asm/uaccess.h>
>> @@ -110,6 +113,7 @@ struct kioctx {
>>  	} ____cacheline_aligned_in_smp;
>>  
>>  	struct page		*internal_pages[AIO_RING_PAGES];
>> +	struct file		*aio_ring_file;
>>  };
>>  
>>  /*------ sysctl variables----*/
>> @@ -138,15 +142,78 @@ __initcall(aio_setup);
>>  
>>  static void aio_free_ring(struct kioctx *ctx)
>>  {
>> -	long i;
>> +	int i;
>> +	struct file *aio_ring_file = ctx->aio_ring_file;
>>  
>> -	for (i = 0; i < ctx->nr_pages; i++)
>> +	for (i = 0; i < ctx->nr_pages; i++) {
>> +		pr_debug("pid(%d) [%d] page->count=%d\n", current->pid, i,
>> +				page_count(ctx->ring_pages[i]));
>>  		put_page(ctx->ring_pages[i]);
>> +	}
>>  
>>  	if (ctx->ring_pages && ctx->ring_pages != ctx->internal_pages)
>>  		kfree(ctx->ring_pages);
>> +
>> +	if (aio_ring_file) {
>> +		truncate_setsize(aio_ring_file->f_inode, 0);
>> +		pr_debug("pid(%d) i_nlink=%u d_count=%d d_unhashed=%d i_count=%d\n",
>> +			current->pid, aio_ring_file->f_inode->i_nlink,
>> +			aio_ring_file->f_path.dentry->d_count,
>> +			d_unhashed(aio_ring_file->f_path.dentry),
>> +			atomic_read(&aio_ring_file->f_inode->i_count));
>> +		fput(aio_ring_file);
>> +		ctx->aio_ring_file = NULL;
>> +	}
>> +}
>> +
>> +static int aio_ring_mmap(struct file *file, struct vm_area_struct *vma)
>> +{
>> +	vma->vm_ops = &generic_file_vm_ops;
>> +	return 0;
>> +}
>> +
>> +static const struct file_operations aio_ring_fops = {
>> +	.mmap = aio_ring_mmap,
>> +};
>> +
>> +static int aio_set_page_dirty(struct page *page)
>> +{
>> +	return 0;
>>  }
>>  
>> +static int aio_migratepage(struct address_space *mapping, struct page *new,
>> +			struct page *old, enum migrate_mode mode)
>> +{
>> +	struct kioctx *ctx = mapping->private_data;
>> +	unsigned long flags;
>> +	unsigned idx = old->index;
>> +	int rc;
>> +
>> +	/*Writeback must be complete*/
> 
> Missing spaces before/after beginning and end of comment.

> 
>> +	BUG_ON(PageWriteback(old));
>> +	put_page(old);
>> +
>> +	rc = migrate_page_move_mapping(mapping, new, old, NULL, mode);
>> +	if (rc != MIGRATEPAGE_SUCCESS) {
>> +		get_page(old);
>> +		return rc;
>> +	}
>> +
>> +	get_page(new);
>> +
>> +	spin_lock_irqsave(&ctx->completion_lock, flags);
>> +	migrate_page_copy(new, old);
>> +	ctx->ring_pages[idx] = new;
>> +	spin_unlock_irqrestore(&ctx->completion_lock, flags);
>> +
>> +	return rc;
>> +}
>> +
>> +static const struct address_space_operations aio_ctx_aops = {
>> +	.set_page_dirty = aio_set_page_dirty,
>> +	.migratepage	= aio_migratepage,
>> +};
>> +
>>  static int aio_setup_ring(struct kioctx *ctx)
>>  {
>>  	struct aio_ring *ring;
>> @@ -154,20 +221,45 @@ static int aio_setup_ring(struct kioctx *ctx)
>>  	struct mm_struct *mm = current->mm;
>>  	unsigned long size, populate;
>>  	int nr_pages;
>> +	int i;
>> +	struct file *file;
>>  
>>  	/* Compensate for the ring buffer's head/tail overlap entry */
>>  	nr_events += 2;	/* 1 is required, 2 for good luck */
>>  
>>  	size = sizeof(struct aio_ring);
>>  	size += sizeof(struct io_event) * nr_events;
>> -	nr_pages = (size + PAGE_SIZE-1) >> PAGE_SHIFT;
>>  
>> +	nr_pages = (size + PAGE_SIZE-1) >> PAGE_SHIFT;
> 
> Hrm, this should probably be replaced by PFN_UP(size) rather than the old 
> open coding of same.
> 
>>  	if (nr_pages < 0)
>>  		return -EINVAL;
>>  
>> -	nr_events = (PAGE_SIZE * nr_pages - sizeof(struct aio_ring)) / sizeof(struct io_event);
>> +	file = anon_inode_getfile_private("[aio]", &aio_ring_fops, ctx, O_RDWR);
>> +	if (IS_ERR(file)) {
>> +		ctx->aio_ring_file = NULL;
>> +		return -EAGAIN;
>> +	}
>> +
>> +	file->f_inode->i_mapping->a_ops = &aio_ctx_aops;
>> +	file->f_inode->i_mapping->private_data = ctx;
>> +	file->f_inode->i_size = PAGE_SIZE * (loff_t)nr_pages;
>> +
>> +	for (i = 0; i < nr_pages; i++) {
>> +		struct page *page;
>> +		page = find_or_create_page(file->f_inode->i_mapping,
>> +					   i, GFP_HIGHUSER | __GFP_ZERO);
>> +		if (!page)
>> +			break;
>> +		pr_debug("pid(%d) page[%d]->count=%d\n",
>> +			 current->pid, i, page_count(page));
>> +		SetPageUptodate(page);
>> +		SetPageDirty(page);
>> +		unlock_page(page);
>> +	}
>> +	ctx->aio_ring_file = file;
>> +	nr_events = (PAGE_SIZE * nr_pages - sizeof(struct aio_ring))
>> +			/ sizeof(struct io_event);
>>  
>> -	ctx->nr_events = 0;
>>  	ctx->ring_pages = ctx->internal_pages;
>>  	if (nr_pages > AIO_RING_PAGES) {
>>  		ctx->ring_pages = kcalloc(nr_pages, sizeof(struct page *),
>> @@ -178,28 +270,31 @@ static int aio_setup_ring(struct kioctx *ctx)
>>  
>>  	ctx->mmap_size = nr_pages * PAGE_SIZE;
>>  	pr_debug("attempting mmap of %lu bytes\n", ctx->mmap_size);
>> +
>>  	down_write(&mm->mmap_sem);
>> -	ctx->mmap_base = do_mmap_pgoff(NULL, 0, ctx->mmap_size,
>> -				       PROT_READ|PROT_WRITE,
>> -				       MAP_ANONYMOUS|MAP_PRIVATE, 0, &populate);
>> +	ctx->mmap_base = do_mmap_pgoff(ctx->aio_ring_file, 0, ctx->mmap_size,
>> +				       PROT_READ | PROT_WRITE,
>> +				       MAP_SHARED | MAP_POPULATE, 0, &populate);
>>  	if (IS_ERR((void *)ctx->mmap_base)) {
>>  		up_write(&mm->mmap_sem);
>>  		ctx->mmap_size = 0;
>>  		aio_free_ring(ctx);
>>  		return -EAGAIN;
>>  	}
>> +	up_write(&mm->mmap_sem);
>> +
>> +	mm_populate(ctx->mmap_base, populate);
>>  
>>  	pr_debug("mmap address: 0x%08lx\n", ctx->mmap_base);
>>  	ctx->nr_pages = get_user_pages(current, mm, ctx->mmap_base, nr_pages,
>>  				       1, 0, ctx->ring_pages, NULL);
>> -	up_write(&mm->mmap_sem);
>> +	for (i = 0; i < ctx->nr_pages; i++)
>> +		put_page(ctx->ring_pages[i]);
>>  
>>  	if (unlikely(ctx->nr_pages != nr_pages)) {
>>  		aio_free_ring(ctx);
>>  		return -EAGAIN;
>>  	}
>> -	if (populate)
>> -		mm_populate(ctx->mmap_base, populate);
>>  
>>  	ctx->user_id = ctx->mmap_base;
>>  	ctx->nr_events = nr_events; /* trusted copy */
>> @@ -399,6 +494,8 @@ out_cleanup:
>>  	err = -EAGAIN;
>>  	aio_free_ring(ctx);
>>  out_freectx:
>> +	if (ctx->aio_ring_file)
>> +		fput(ctx->aio_ring_file);
>>  	kmem_cache_free(kioctx_cachep, ctx);
>>  	pr_debug("error allocating ioctx %d\n", err);
>>  	return ERR_PTR(err);
>> @@ -852,6 +949,7 @@ SYSCALL_DEFINE2(io_setup, unsigned, nr_events, aio_context_t __user *, ctxp)
>>  	ioctx = ioctx_alloc(nr_events);
>>  	ret = PTR_ERR(ioctx);
>>  	if (!IS_ERR(ioctx)) {
>> +		ctx = ioctx->user_id;
>>  		ret = put_user(ioctx->user_id, ctxp);
>>  		if (ret)
>>  			kill_ioctx(ioctx);
> 
> This hunk doesn't do anything and needs to be removed.  That should cover 
> things.
> 
> 		-ben
> 
>> diff --git a/include/linux/migrate.h b/include/linux/migrate.h
>> index a405d3dc..c407d88 100644
>> --- a/include/linux/migrate.h
>> +++ b/include/linux/migrate.h
>> @@ -55,6 +55,9 @@ extern int migrate_vmas(struct mm_struct *mm,
>>  extern void migrate_page_copy(struct page *newpage, struct page *page);
>>  extern int migrate_huge_page_move_mapping(struct address_space *mapping,
>>  				  struct page *newpage, struct page *page);
>> +extern int migrate_page_move_mapping(struct address_space *mapping,
>> +		struct page *newpage, struct page *page,
>> +		struct buffer_head *head, enum migrate_mode mode);
>>  #else
>>  
>>  static inline void putback_lru_pages(struct list_head *l) {}
>> diff --git a/mm/migrate.c b/mm/migrate.c
>> index 6f0c244..1da0092 100644
>> --- a/mm/migrate.c
>> +++ b/mm/migrate.c
>> @@ -307,7 +307,7 @@ static inline bool buffer_migrate_lock_buffers(struct buffer_head *head,
>>   * 2 for pages with a mapping
>>   * 3 for pages with a mapping and PagePrivate/PagePrivate2 set.
>>   */
>> -static int migrate_page_move_mapping(struct address_space *mapping,
>> +int migrate_page_move_mapping(struct address_space *mapping,
>>  		struct page *newpage, struct page *page,
>>  		struct buffer_head *head, enum migrate_mode mode)
>>  {
>> -- 
>> 1.7.7
>>
> 


--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@xxxxxxxxx.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@xxxxxxxxx";> email@xxxxxxxxx </a>




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]