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

Commit 1d59d61f authored by Trond Myklebust's avatar Trond Myklebust Committed by Linus Torvalds
Browse files

NFS: Ensure that setattr and getattr wait for O_DIRECT write completion



Use the same mechanism as the block devices are using, but move the
helper functions from fs/direct-io.c into fs/inode.c to remove the
dependency on CONFIG_BLOCK.

Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Fred Isaman <iisaman@netapp.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 2d117403
Loading
Loading
Loading
Loading
+0 −44
Original line number Diff line number Diff line
@@ -145,50 +145,6 @@ struct dio {

static struct kmem_cache *dio_cache __read_mostly;

static void __inode_dio_wait(struct inode *inode)
{
	wait_queue_head_t *wq = bit_waitqueue(&inode->i_state, __I_DIO_WAKEUP);
	DEFINE_WAIT_BIT(q, &inode->i_state, __I_DIO_WAKEUP);

	do {
		prepare_to_wait(wq, &q.wait, TASK_UNINTERRUPTIBLE);
		if (atomic_read(&inode->i_dio_count))
			schedule();
	} while (atomic_read(&inode->i_dio_count));
	finish_wait(wq, &q.wait);
}

/**
 * inode_dio_wait - wait for outstanding DIO requests to finish
 * @inode: inode to wait for
 *
 * Waits for all pending direct I/O requests to finish so that we can
 * proceed with a truncate or equivalent operation.
 *
 * Must be called under a lock that serializes taking new references
 * to i_dio_count, usually by inode->i_mutex.
 */
void inode_dio_wait(struct inode *inode)
{
	if (atomic_read(&inode->i_dio_count))
		__inode_dio_wait(inode);
}
EXPORT_SYMBOL(inode_dio_wait);

/*
 * inode_dio_done - signal finish of a direct I/O requests
 * @inode: inode the direct I/O happens on
 *
 * This is called once we've finished processing a direct I/O request,
 * and is used to wake up callers waiting for direct I/O to be quiesced.
 */
void inode_dio_done(struct inode *inode)
{
	if (atomic_dec_and_test(&inode->i_dio_count))
		wake_up_bit(&inode->i_state, __I_DIO_WAKEUP);
}
EXPORT_SYMBOL(inode_dio_done);

/*
 * How many pages are in the queue?
 */
+47 −0
Original line number Diff line number Diff line
@@ -1748,3 +1748,50 @@ bool inode_owner_or_capable(const struct inode *inode)
	return false;
}
EXPORT_SYMBOL(inode_owner_or_capable);

/*
 * Direct i/o helper functions
 */
static void __inode_dio_wait(struct inode *inode)
{
	wait_queue_head_t *wq = bit_waitqueue(&inode->i_state, __I_DIO_WAKEUP);
	DEFINE_WAIT_BIT(q, &inode->i_state, __I_DIO_WAKEUP);

	do {
		prepare_to_wait(wq, &q.wait, TASK_UNINTERRUPTIBLE);
		if (atomic_read(&inode->i_dio_count))
			schedule();
	} while (atomic_read(&inode->i_dio_count));
	finish_wait(wq, &q.wait);
}

/**
 * inode_dio_wait - wait for outstanding DIO requests to finish
 * @inode: inode to wait for
 *
 * Waits for all pending direct I/O requests to finish so that we can
 * proceed with a truncate or equivalent operation.
 *
 * Must be called under a lock that serializes taking new references
 * to i_dio_count, usually by inode->i_mutex.
 */
void inode_dio_wait(struct inode *inode)
{
	if (atomic_read(&inode->i_dio_count))
		__inode_dio_wait(inode);
}
EXPORT_SYMBOL(inode_dio_wait);

/*
 * inode_dio_done - signal finish of a direct I/O requests
 * @inode: inode the direct I/O happens on
 *
 * This is called once we've finished processing a direct I/O request,
 * and is used to wake up callers waiting for direct I/O to be quiesced.
 */
void inode_dio_done(struct inode *inode)
{
	if (atomic_dec_and_test(&inode->i_dio_count))
		wake_up_bit(&inode->i_state, __I_DIO_WAKEUP);
}
EXPORT_SYMBOL(inode_dio_done);
+12 −3
Original line number Diff line number Diff line
@@ -454,6 +454,12 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov,
	return result;
}

static void nfs_inode_dio_write_done(struct inode *inode)
{
	nfs_zap_mapping(inode, inode->i_mapping);
	inode_dio_done(inode);
}

#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
{
@@ -564,7 +570,7 @@ static void nfs_direct_write_schedule_work(struct work_struct *work)
			nfs_direct_write_reschedule(dreq);
			break;
		default:
			nfs_zap_mapping(dreq->inode, dreq->inode->i_mapping);
			nfs_inode_dio_write_done(dreq->inode);
			nfs_direct_complete(dreq);
	}
}
@@ -581,7 +587,7 @@ static void nfs_direct_write_schedule_work(struct work_struct *work)

static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode)
{
	nfs_zap_mapping(inode, inode->i_mapping);
	nfs_inode_dio_write_done(inode);
	nfs_direct_complete(dreq);
}
#endif
@@ -766,14 +772,16 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
					       loff_t pos)
{
	struct nfs_pageio_descriptor desc;
	struct inode *inode = dreq->inode;
	ssize_t result = 0;
	size_t requested_bytes = 0;
	unsigned long seg;

	nfs_pageio_init_write(&desc, dreq->inode, FLUSH_COND_STABLE,
	nfs_pageio_init_write(&desc, inode, FLUSH_COND_STABLE,
			      &nfs_direct_write_completion_ops);
	desc.pg_dreq = dreq;
	get_dreq(dreq);
	atomic_inc(&inode->i_dio_count);

	for (seg = 0; seg < nr_segs; seg++) {
		const struct iovec *vec = &iov[seg];
@@ -793,6 +801,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
	 * generic layer handle the completion.
	 */
	if (requested_bytes == 0) {
		inode_dio_done(inode);
		nfs_direct_req_release(dreq);
		return result < 0 ? result : -EIO;
	}
+4 −1
Original line number Diff line number Diff line
@@ -418,8 +418,10 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
		return 0;

	/* Write all dirty data */
	if (S_ISREG(inode->i_mode))
	if (S_ISREG(inode->i_mode)) {
		nfs_inode_dio_wait(inode);
		nfs_wb_all(inode);
	}

	fattr = nfs_alloc_fattr();
	if (fattr == NULL)
@@ -503,6 +505,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)

	/* Flush out writes to the server in order to update c/mtime.  */
	if (S_ISREG(inode->i_mode)) {
		nfs_inode_dio_wait(inode);
		err = filemap_write_and_wait(inode->i_mapping);
		if (err)
			goto out;
+4 −0
Original line number Diff line number Diff line
@@ -369,6 +369,10 @@ extern int nfs_migrate_page(struct address_space *,
/* direct.c */
void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo,
			      struct nfs_direct_req *dreq);
static inline void nfs_inode_dio_wait(struct inode *inode)
{
	inode_dio_wait(inode);
}

/* nfs4proc.c */
extern void __nfs4_read_done_cb(struct nfs_read_data *);
Loading