Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 309606
b: refs/heads/master
c: 1d59d61
h: refs/heads/master
v: v3
  • Loading branch information
Trond Myklebust authored and Linus Torvalds committed May 31, 2012
1 parent 39f8d65 commit 097c774
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 55 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 2d117403b30cd7301af60d7d54b279a9f566d10d
refs/heads/master: 1d59d61f606547f0712aa6971f91f71154071c99
44 changes: 0 additions & 44 deletions trunk/fs/direct-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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?
*/
Expand Down
47 changes: 47 additions & 0 deletions trunk/fs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
15 changes: 12 additions & 3 deletions trunk/fs/nfs/direct.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
}
}
Expand All @@ -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
Expand Down Expand Up @@ -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];
Expand All @@ -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;
}
Expand Down
5 changes: 4 additions & 1 deletion trunk/fs/nfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions trunk/fs/nfs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down
9 changes: 3 additions & 6 deletions trunk/include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2453,8 +2453,6 @@ enum {
};

void dio_end_io(struct bio *bio, int error);
void inode_dio_wait(struct inode *inode);
void inode_dio_done(struct inode *inode);

ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
struct block_device *bdev, const struct iovec *iov, loff_t offset,
Expand All @@ -2469,12 +2467,11 @@ static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb,
offset, nr_segs, get_block, NULL, NULL,
DIO_LOCKING | DIO_SKIP_HOLES);
}
#else
static inline void inode_dio_wait(struct inode *inode)
{
}
#endif

void inode_dio_wait(struct inode *inode);
void inode_dio_done(struct inode *inode);

extern const struct file_operations generic_ro_fops;

#define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
Expand Down

0 comments on commit 097c774

Please sign in to comment.