Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d333fc8d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'fixes' of git://git.linux-nfs.org/pub/linux/nfs-2.6:
  NFS: Fix nfs_direct_dirty_pages()
  NFS: Fix handful of compiler warnings in direct.c
  NFS: Avoid a deadlock situation on write
parents 1a93fa86 d4a8f367
Loading
Loading
Loading
Loading
+33 −20
Original line number Diff line number Diff line
@@ -122,19 +122,25 @@ ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_
	return -EINVAL;
}

static void nfs_direct_dirty_pages(struct page **pages, int npages)
static void nfs_direct_dirty_pages(struct page **pages, unsigned int pgbase, size_t count)
{
	int i;
	unsigned int npages;
	unsigned int i;

	if (count == 0)
		return;
	pages += (pgbase >> PAGE_SHIFT);
	npages = (count + (pgbase & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT;
	for (i = 0; i < npages; i++) {
		struct page *page = pages[i];
		if (!PageCompound(page))
			set_page_dirty_lock(page);
			set_page_dirty(page);
	}
}

static void nfs_direct_release_pages(struct page **pages, int npages)
static void nfs_direct_release_pages(struct page **pages, unsigned int npages)
{
	int i;
	unsigned int i;
	for (i = 0; i < npages; i++)
		page_cache_release(pages[i]);
}
@@ -224,17 +230,18 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
	if (nfs_readpage_result(task, data) != 0)
		return;

	nfs_direct_dirty_pages(data->pagevec, data->npages);
	nfs_direct_release_pages(data->pagevec, data->npages);

	spin_lock(&dreq->lock);

	if (likely(task->tk_status >= 0))
		dreq->count += data->res.count;
	else
	if (unlikely(task->tk_status < 0)) {
		dreq->error = task->tk_status;

		spin_unlock(&dreq->lock);
	} else {
		dreq->count += data->res.count;
		spin_unlock(&dreq->lock);
		nfs_direct_dirty_pages(data->pagevec,
				data->args.pgbase,
				data->res.count);
	}
	nfs_direct_release_pages(data->pagevec, data->npages);

	if (put_dreq(dreq))
		nfs_direct_complete(dreq);
@@ -279,8 +286,11 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo
		result = get_user_pages(current, current->mm, user_addr,
					data->npages, 1, 0, data->pagevec, NULL);
		up_read(&current->mm->mmap_sem);
		if (unlikely(result < data->npages)) {
			if (result > 0)
		if (result < 0) {
			nfs_readdata_release(data);
			break;
		}
		if ((unsigned)result < data->npages) {
			nfs_direct_release_pages(data->pagevec, result);
			nfs_readdata_release(data);
			break;
@@ -610,8 +620,11 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l
		result = get_user_pages(current, current->mm, user_addr,
					data->npages, 0, 0, data->pagevec, NULL);
		up_read(&current->mm->mmap_sem);
		if (unlikely(result < data->npages)) {
			if (result > 0)
		if (result < 0) {
			nfs_writedata_release(data);
			break;
		}
		if ((unsigned)result < data->npages) {
			nfs_direct_release_pages(data->pagevec, result);
			nfs_writedata_release(data);
			break;
+20 −0
Original line number Diff line number Diff line
@@ -355,6 +355,26 @@ void nfs_pageio_complete(struct nfs_pageio_descriptor *desc)
	nfs_pageio_doio(desc);
}

/**
 * nfs_pageio_cond_complete - Conditional I/O completion
 * @desc: pointer to io descriptor
 * @index: page index
 *
 * It is important to ensure that processes don't try to take locks
 * on non-contiguous ranges of pages as that might deadlock. This
 * function should be called before attempting to wait on a locked
 * nfs_page. It will complete the I/O if the page index 'index'
 * is not contiguous with the existing list of pages in 'desc'.
 */
void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
{
	if (!list_empty(&desc->pg_list)) {
		struct nfs_page *prev = nfs_list_entry(desc->pg_list.prev);
		if (index != prev->wb_index + 1)
			nfs_pageio_doio(desc);
	}
}

#define NFS_SCAN_MAXENTRIES 16
/**
 * nfs_scan_list - Scan a list for matching requests
+4 −2
Original line number Diff line number Diff line
@@ -273,8 +273,6 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
		 *	 request as dirty (in which case we don't care).
		 */
		spin_unlock(req_lock);
		/* Prevent deadlock! */
		nfs_pageio_complete(pgio);
		ret = nfs_wait_on_request(req);
		nfs_release_request(req);
		if (ret != 0)
@@ -321,6 +319,8 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc
		pgio = &mypgio;
	}

	nfs_pageio_cond_complete(pgio, page->index);

	err = nfs_page_async_flush(pgio, page);
	if (err <= 0)
		goto out;
@@ -329,6 +329,8 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc
	if (!offset)
		goto out;

	nfs_pageio_cond_complete(pgio, page->index);

	ctx = nfs_find_open_context(inode, NULL, FMODE_WRITE);
	if (ctx == NULL) {
		err = -EBADF;
+1 −0
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
extern	int nfs_pageio_add_request(struct nfs_pageio_descriptor *,
				   struct nfs_page *);
extern	void nfs_pageio_complete(struct nfs_pageio_descriptor *desc);
extern	void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *, pgoff_t);
extern  int nfs_wait_on_request(struct nfs_page *);
extern	void nfs_unlock_request(struct nfs_page *req);
extern  int nfs_set_page_writeback_locked(struct nfs_page *req);