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

Commit 36274526 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

Merge branch 'writeback'

parents 7f94ed24 e033fb51
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@ obj-$(CONFIG_NFS_FS) += nfs.o

CFLAGS_nfstrace.o += -I$(src)
nfs-y 			:= client.o dir.o file.o getroot.o inode.o super.o \
			   direct.o pagelist.o read.o symlink.o unlink.o \
			   io.o direct.o pagelist.o read.o symlink.o unlink.o \
			   write.o namespace.o mount_clnt.o nfstrace.o
nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o
nfs-$(CONFIG_SYSCTL)	+= sysctl.o
+31 −21
Original line number Diff line number Diff line
@@ -2231,21 +2231,37 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, st
	return NULL;
}

static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res)
static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res, bool may_block)
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_access_entry *cache;
	int err = -ENOENT;
	bool retry = true;
	int err;

	spin_lock(&inode->i_lock);
	for(;;) {
		if (nfsi->cache_validity & NFS_INO_INVALID_ACCESS)
			goto out_zap;
		cache = nfs_access_search_rbtree(inode, cred);
		err = -ENOENT;
		if (cache == NULL)
			goto out;
	if (!nfs_have_delegated_attributes(inode) &&
	    !time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo))
		goto out_stale;
		/* Found an entry, is our attribute cache valid? */
		if (!nfs_attribute_cache_expired(inode) &&
		    !(nfsi->cache_validity & NFS_INO_INVALID_ATTR))
			break;
		err = -ECHILD;
		if (!may_block)
			goto out;
		if (!retry)
			goto out_zap;
		spin_unlock(&inode->i_lock);
		err = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
		if (err)
			return err;
		spin_lock(&inode->i_lock);
		retry = false;
	}
	res->jiffies = cache->jiffies;
	res->cred = cache->cred;
	res->mask = cache->mask;
@@ -2254,12 +2270,6 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str
out:
	spin_unlock(&inode->i_lock);
	return err;
out_stale:
	rb_erase(&cache->rb_node, &nfsi->access_cache);
	list_del(&cache->lru);
	spin_unlock(&inode->i_lock);
	nfs_access_free_entry(cache);
	return -ENOENT;
out_zap:
	spin_unlock(&inode->i_lock);
	nfs_access_zap_cache(inode);
@@ -2286,13 +2296,12 @@ static int nfs_access_get_cached_rcu(struct inode *inode, struct rpc_cred *cred,
		cache = NULL;
	if (cache == NULL)
		goto out;
	if (!nfs_have_delegated_attributes(inode) &&
	    !time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo))
	err = nfs_revalidate_inode_rcu(NFS_SERVER(inode), inode);
	if (err)
		goto out;
	res->jiffies = cache->jiffies;
	res->cred = cache->cred;
	res->mask = cache->mask;
	err = 0;
out:
	rcu_read_unlock();
	return err;
@@ -2381,18 +2390,19 @@ EXPORT_SYMBOL_GPL(nfs_access_set_mask);
static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
{
	struct nfs_access_entry cache;
	bool may_block = (mask & MAY_NOT_BLOCK) == 0;
	int status;

	trace_nfs_access_enter(inode);

	status = nfs_access_get_cached_rcu(inode, cred, &cache);
	if (status != 0)
		status = nfs_access_get_cached(inode, cred, &cache);
		status = nfs_access_get_cached(inode, cred, &cache, may_block);
	if (status == 0)
		goto out_cached;

	status = -ECHILD;
	if (mask & MAY_NOT_BLOCK)
	if (!may_block)
		goto out;

	/* Be clever: ask server to check for all possible rights */
+32 −61
Original line number Diff line number Diff line
@@ -196,6 +196,12 @@ static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq,
	WARN_ON_ONCE(verfp->committed < 0);
}

static int nfs_direct_cmp_verf(const struct nfs_writeverf *v1,
		const struct nfs_writeverf *v2)
{
	return nfs_write_verifier_cmp(&v1->verifier, &v2->verifier);
}

/*
 * nfs_direct_cmp_hdr_verf - compare verifier for pgio header
 * @dreq - direct request possibly spanning multiple servers
@@ -215,7 +221,7 @@ static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq,
		nfs_direct_set_hdr_verf(dreq, hdr);
		return 0;
	}
	return memcmp(verfp, &hdr->verf, sizeof(struct nfs_writeverf));
	return nfs_direct_cmp_verf(verfp, &hdr->verf);
}

/*
@@ -238,7 +244,7 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq,
	if (verfp->committed < 0)
		return 1;

	return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf));
	return nfs_direct_cmp_verf(verfp, &data->verf);
}

/**
@@ -368,22 +374,10 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq)
 * Synchronous I/O uses a stack-allocated iocb.  Thus we can't trust
 * the iocb is still valid here if this is a synchronous request.
 */
static void nfs_direct_complete(struct nfs_direct_req *dreq, bool write)
static void nfs_direct_complete(struct nfs_direct_req *dreq)
{
	struct inode *inode = dreq->inode;

	if (dreq->iocb && write) {
		loff_t pos = dreq->iocb->ki_pos + dreq->count;

		spin_lock(&inode->i_lock);
		if (i_size_read(inode) < pos)
			i_size_write(inode, pos);
		spin_unlock(&inode->i_lock);
	}

	if (write)
		nfs_zap_mapping(inode, inode->i_mapping);

	inode_dio_end(inode);

	if (dreq->iocb) {
@@ -438,7 +432,7 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
	}
out_put:
	if (put_dreq(dreq))
		nfs_direct_complete(dreq, false);
		nfs_direct_complete(dreq);
	hdr->release(hdr);
}

@@ -544,7 +538,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
	}

	if (put_dreq(dreq))
		nfs_direct_complete(dreq, false);
		nfs_direct_complete(dreq);
	return 0;
}

@@ -585,17 +579,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
	if (!count)
		goto out;

	inode_lock(inode);
	result = nfs_sync_mapping(mapping);
	if (result)
		goto out_unlock;

	task_io_account_read(count);

	result = -ENOMEM;
	dreq = nfs_direct_req_alloc();
	if (dreq == NULL)
		goto out_unlock;
		goto out;

	dreq->inode = inode;
	dreq->bytes_left = dreq->max_count = count;
@@ -610,10 +599,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
	if (!is_sync_kiocb(iocb))
		dreq->iocb = iocb;

	nfs_start_io_direct(inode);

	NFS_I(inode)->read_io += count;
	result = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos);

	inode_unlock(inode);
	nfs_end_io_direct(inode);

	if (!result) {
		result = nfs_direct_wait(dreq);
@@ -621,13 +612,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
			iocb->ki_pos += result;
	}

	nfs_direct_req_release(dreq);
	return result;

out_release:
	nfs_direct_req_release(dreq);
out_unlock:
	inode_unlock(inode);
out:
	return result;
}
@@ -659,6 +645,8 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
	nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo);

	dreq->count = 0;
	dreq->verf.committed = NFS_INVALID_STABLE_HOW;
	nfs_clear_pnfs_ds_commit_verifiers(&dreq->ds_cinfo);
	for (i = 0; i < dreq->mirror_count; i++)
		dreq->mirrors[i].count = 0;
	get_dreq(dreq);
@@ -777,7 +765,8 @@ static void nfs_direct_write_schedule_work(struct work_struct *work)
			nfs_direct_write_reschedule(dreq);
			break;
		default:
			nfs_direct_complete(dreq, true);
			nfs_zap_mapping(dreq->inode, dreq->inode->i_mapping);
			nfs_direct_complete(dreq);
	}
}

@@ -993,6 +982,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
{
	ssize_t result = -EINVAL;
	size_t count;
	struct file *file = iocb->ki_filp;
	struct address_space *mapping = file->f_mapping;
	struct inode *inode = mapping->host;
@@ -1003,34 +993,24 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
	dfprintk(FILE, "NFS: direct write(%pD2, %zd@%Ld)\n",
		file, iov_iter_count(iter), (long long) iocb->ki_pos);

	nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES,
		      iov_iter_count(iter));
	result = generic_write_checks(iocb, iter);
	if (result <= 0)
		return result;
	count = result;
	nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count);

	pos = iocb->ki_pos;
	end = (pos + iov_iter_count(iter) - 1) >> PAGE_SHIFT;

	inode_lock(inode);

	result = nfs_sync_mapping(mapping);
	if (result)
		goto out_unlock;

	if (mapping->nrpages) {
		result = invalidate_inode_pages2_range(mapping,
					pos >> PAGE_SHIFT, end);
		if (result)
			goto out_unlock;
	}

	task_io_account_write(iov_iter_count(iter));
	task_io_account_write(count);

	result = -ENOMEM;
	dreq = nfs_direct_req_alloc();
	if (!dreq)
		goto out_unlock;
		goto out;

	dreq->inode = inode;
	dreq->bytes_left = dreq->max_count = iov_iter_count(iter);
	dreq->bytes_left = dreq->max_count = count;
	dreq->io_start = pos;
	dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
	l_ctx = nfs_get_lock_context(dreq->ctx);
@@ -1042,6 +1022,8 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
	if (!is_sync_kiocb(iocb))
		dreq->iocb = iocb;

	nfs_start_io_direct(inode);

	result = nfs_direct_write_schedule_iovec(dreq, iter, pos);

	if (mapping->nrpages) {
@@ -1049,30 +1031,19 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
					      pos >> PAGE_SHIFT, end);
	}

	inode_unlock(inode);
	nfs_end_io_direct(inode);

	if (!result) {
		result = nfs_direct_wait(dreq);
		if (result > 0) {
			struct inode *inode = mapping->host;

			iocb->ki_pos = pos + result;
			spin_lock(&inode->i_lock);
			if (i_size_read(inode) < iocb->ki_pos)
				i_size_write(inode, iocb->ki_pos);
			spin_unlock(&inode->i_lock);

			/* XXX: should check the generic_write_sync retval */
			generic_write_sync(iocb, result);
		}
	}
	nfs_direct_req_release(dreq);
	return result;

out_release:
	nfs_direct_req_release(dreq);
out_unlock:
	inode_unlock(inode);
out:
	return result;
}

+27 −69
Original line number Diff line number Diff line
@@ -170,12 +170,14 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
		iocb->ki_filp,
		iov_iter_count(to), (unsigned long) iocb->ki_pos);

	result = nfs_revalidate_mapping_protected(inode, iocb->ki_filp->f_mapping);
	nfs_start_io_read(inode);
	result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
	if (!result) {
		result = generic_file_read_iter(iocb, to);
		if (result > 0)
			nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result);
	}
	nfs_end_io_read(inode);
	return result;
}
EXPORT_SYMBOL_GPL(nfs_file_read);
@@ -191,12 +193,14 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos,
	dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n",
		filp, (unsigned long) count, (unsigned long long) *ppos);

	res = nfs_revalidate_mapping_protected(inode, filp->f_mapping);
	nfs_start_io_read(inode);
	res = nfs_revalidate_mapping(inode, filp->f_mapping);
	if (!res) {
		res = generic_file_splice_read(filp, ppos, pipe, count, flags);
		if (res > 0)
			nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, res);
	}
	nfs_end_io_read(inode);
	return res;
}
EXPORT_SYMBOL_GPL(nfs_file_splice_read);
@@ -272,16 +276,13 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)

	trace_nfs_fsync_enter(inode);

	inode_dio_wait(inode);
	do {
		ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
		if (ret != 0)
			break;
		inode_lock(inode);
		ret = nfs_file_fsync_commit(file, start, end, datasync);
		if (!ret)
			ret = pnfs_sync_inode(inode, !!datasync);
		inode_unlock(inode);
		/*
		 * If nfs_file_fsync_commit detected a server reboot, then
		 * resend all dirty pages that might have been covered by
@@ -359,19 +360,6 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
		file, mapping->host->i_ino, len, (long long) pos);

start:
	/*
	 * Prevent starvation issues if someone is doing a consistency
	 * sync-to-disk
	 */
	ret = wait_on_bit_action(&NFS_I(mapping->host)->flags, NFS_INO_FLUSHING,
				 nfs_wait_bit_killable, TASK_KILLABLE);
	if (ret)
		return ret;
	/*
	 * Wait for O_DIRECT to complete
	 */
	inode_dio_wait(mapping->host);

	page = grab_cache_page_write_begin(mapping, index, flags);
	if (!page)
		return -ENOMEM;
@@ -470,31 +458,8 @@ static void nfs_invalidate_page(struct page *page, unsigned int offset,
 */
static int nfs_release_page(struct page *page, gfp_t gfp)
{
	struct address_space *mapping = page->mapping;

	dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);

	/* Always try to initiate a 'commit' if relevant, but only
	 * wait for it if the caller allows blocking.  Even then,
	 * only wait 1 second and only if the 'bdi' is not congested.
	 * Waiting indefinitely can cause deadlocks when the NFS
	 * server is on this machine, when a new TCP connection is
	 * needed and in other rare cases.  There is no particular
	 * need to wait extensively here.  A short wait has the
	 * benefit that someone else can worry about the freezer.
	 */
	if (mapping) {
		struct nfs_server *nfss = NFS_SERVER(mapping->host);
		nfs_commit_inode(mapping->host, 0);
		if (gfpflags_allow_blocking(gfp) &&
		    !bdi_write_congested(&nfss->backing_dev_info)) {
			wait_on_page_bit_killable_timeout(page, PG_private,
							  HZ);
			if (PagePrivate(page))
				set_bdi_congested(&nfss->backing_dev_info,
						  BLK_RW_ASYNC);
		}
	}
	/* If PagePrivate() is set, then the page is not freeable */
	if (PagePrivate(page))
		return 0;
@@ -604,6 +569,8 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
		filp, filp->f_mapping->host->i_ino,
		(long long)page_offset(page));

	sb_start_pagefault(inode->i_sb);

	/* make sure the cache has finished storing the page */
	nfs_fscache_wait_on_page_write(NFS_I(inode), page);

@@ -630,6 +597,7 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
out_unlock:
	unlock_page(page);
out:
	sb_end_pagefault(inode->i_sb);
	return ret;
}

@@ -656,23 +624,17 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
	struct inode *inode = file_inode(file);
	unsigned long written = 0;
	ssize_t result;
	size_t count = iov_iter_count(from);

	result = nfs_key_timeout_notify(file, inode);
	if (result)
		return result;

	if (iocb->ki_flags & IOCB_DIRECT) {
		result = generic_write_checks(iocb, from);
		if (result <= 0)
			return result;
	if (iocb->ki_flags & IOCB_DIRECT)
		return nfs_file_direct_write(iocb, from);
	}

	dprintk("NFS: write(%pD2, %zu@%Ld)\n",
		file, count, (long long) iocb->ki_pos);
		file, iov_iter_count(from), (long long) iocb->ki_pos);

	result = -EBUSY;
	if (IS_SWAPFILE(inode))
		goto out_swapfile;
	/*
@@ -684,28 +646,33 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
			goto out;
	}

	result = count;
	if (!count)
	nfs_start_io_write(inode);
	result = generic_write_checks(iocb, from);
	if (result > 0) {
		current->backing_dev_info = inode_to_bdi(inode);
		result = generic_perform_write(file, from, iocb->ki_pos);
		current->backing_dev_info = NULL;
	}
	nfs_end_io_write(inode);
	if (result <= 0)
		goto out;

	result = generic_file_write_iter(iocb, from);
	if (result > 0)
		written = result;
	written = generic_write_sync(iocb, result);
	iocb->ki_pos += written;

	/* Return error values */
	if (result >= 0 && nfs_need_check_write(file, inode)) {
	if (nfs_need_check_write(file, inode)) {
		int err = vfs_fsync(file, 0);
		if (err < 0)
			result = err;
	}
	if (result > 0)
	nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written);
out:
	return result;

out_swapfile:
	printk(KERN_INFO "NFS: attempt to write to active swap file!\n");
	goto out;
	return -EBUSY;
}
EXPORT_SYMBOL_GPL(nfs_file_write);

@@ -779,11 +746,6 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
	return status;
}

static int
is_time_granular(struct timespec *ts) {
	return ((ts->tv_sec == 0) && (ts->tv_nsec <= 1000));
}

static int
do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
{
@@ -817,12 +779,8 @@ do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
	 * This makes locking act as a cache coherency point.
	 */
	nfs_sync_mapping(filp->f_mapping);
	if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) {
		if (is_time_granular(&NFS_SERVER(inode)->time_delta))
			__nfs_revalidate_inode(NFS_SERVER(inode), inode);
		else
			nfs_zap_caches(inode);
	}
	if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
		nfs_zap_mapping(inode, filp->f_mapping);
out:
	return status;
}
+13 −5
Original line number Diff line number Diff line
@@ -255,13 +255,16 @@ static int filelayout_read_done_cb(struct rpc_task *task,
static void
filelayout_set_layoutcommit(struct nfs_pgio_header *hdr)
{
	loff_t end_offs = 0;

	if (FILELAYOUT_LSEG(hdr->lseg)->commit_through_mds ||
	    hdr->res.verf->committed != NFS_DATA_SYNC)
	    hdr->res.verf->committed == NFS_FILE_SYNC)
		return;
	if (hdr->res.verf->committed == NFS_DATA_SYNC)
		end_offs = hdr->mds_offset + (loff_t)hdr->res.count;

	pnfs_set_layoutcommit(hdr->inode, hdr->lseg,
			hdr->mds_offset + hdr->res.count);
	/* Note: if the write is unstable, don't set end_offs until commit */
	pnfs_set_layoutcommit(hdr->inode, hdr->lseg, end_offs);
	dprintk("%s inode %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino,
		(unsigned long) NFS_I(hdr->inode)->layout->plh_lwb);
}
@@ -354,6 +357,12 @@ static int filelayout_write_done_cb(struct rpc_task *task,
	}

	filelayout_set_layoutcommit(hdr);

	/* zero out the fattr */
	hdr->fattr.valid = 0;
	if (task->tk_status >= 0)
		nfs_writeback_update_inode(hdr);

	return 0;
}

@@ -375,7 +384,6 @@ static int filelayout_commit_done_cb(struct rpc_task *task,
		return -EAGAIN;
	}

	if (data->verf.committed == NFS_UNSTABLE)
	pnfs_set_layoutcommit(data->inode, data->lseg, data->lwb);

	return 0;
Loading