Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 294624
b: refs/heads/master
c: 281627d
h: refs/heads/master
v: v3
  • Loading branch information
Christoph Hellwig authored and Ben Myers committed Mar 13, 2012
1 parent fcdac82 commit b4d87b0
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 25 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: 84803fb78237014cbbc86c0f012b273a199f4691
refs/heads/master: 281627df3eb55e1b729b9bb06fff5ff112929646
133 changes: 109 additions & 24 deletions trunk/fs/xfs/xfs_aops.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "xfs_bmap_btree.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
#include "xfs_alloc.h"
#include "xfs_error.h"
#include "xfs_rw.h"
Expand Down Expand Up @@ -107,25 +108,65 @@ static inline bool xfs_ioend_is_append(struct xfs_ioend *ioend)
XFS_I(ioend->io_inode)->i_d.di_size;
}

STATIC int
xfs_setfilesize_trans_alloc(
struct xfs_ioend *ioend)
{
struct xfs_mount *mp = XFS_I(ioend->io_inode)->i_mount;
struct xfs_trans *tp;
int error;

tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);

error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
if (error) {
xfs_trans_cancel(tp, 0);
return error;
}

ioend->io_append_trans = tp;

/*
* We hand off the transaction to the completion thread now, so
* clear the flag here.
*/
current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
return 0;
}

/*
* Update on-disk file size now that data has been written to disk.
*/
STATIC void
STATIC int
xfs_setfilesize(
struct xfs_ioend *ioend)
{
struct xfs_inode *ip = XFS_I(ioend->io_inode);
struct xfs_trans *tp = ioend->io_append_trans;
xfs_fsize_t isize;

/*
* The transaction was allocated in the I/O submission thread,
* thus we need to mark ourselves as beeing in a transaction
* manually.
*/
current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);

xfs_ilock(ip, XFS_ILOCK_EXCL);
isize = xfs_new_eof(ip, ioend->io_offset + ioend->io_size);
if (isize) {
trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size);
ip->i_d.di_size = isize;
xfs_mark_inode_dirty(ip);
if (!isize) {
xfs_iunlock(ip, XFS_ILOCK_EXCL);
xfs_trans_cancel(tp, 0);
return 0;
}

xfs_iunlock(ip, XFS_ILOCK_EXCL);
trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size);

ip->i_d.di_size = isize;
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);

return xfs_trans_commit(tp, 0);
}

/*
Expand All @@ -143,7 +184,7 @@ xfs_finish_ioend(

if (ioend->io_type == IO_UNWRITTEN)
queue_work(mp->m_unwritten_workqueue, &ioend->io_work);
else if (xfs_ioend_is_append(ioend))
else if (ioend->io_append_trans)
queue_work(mp->m_data_workqueue, &ioend->io_work);
else
xfs_destroy_ioend(ioend);
Expand Down Expand Up @@ -173,18 +214,32 @@ xfs_end_io(
* range to normal written extens after the data I/O has finished.
*/
if (ioend->io_type == IO_UNWRITTEN) {
/*
* For buffered I/O we never preallocate a transaction when
* doing the unwritten extent conversion, but for direct I/O
* we do not know if we are converting an unwritten extent
* or not at the point where we preallocate the transaction.
*/
if (ioend->io_append_trans) {
ASSERT(ioend->io_isdirect);

current_set_flags_nested(
&ioend->io_append_trans->t_pflags, PF_FSTRANS);
xfs_trans_cancel(ioend->io_append_trans, 0);
}

error = xfs_iomap_write_unwritten(ip, ioend->io_offset,
ioend->io_size);
if (error) {
ioend->io_error = -error;
goto done;
}
} else if (ioend->io_append_trans) {
error = xfs_setfilesize(ioend);
if (error)
ioend->io_error = -error;
} else {
/*
* We might have to update the on-disk file size after
* extending writes.
*/
xfs_setfilesize(ioend);
ASSERT(!xfs_ioend_is_append(ioend));
}

done:
Expand Down Expand Up @@ -224,6 +279,7 @@ xfs_alloc_ioend(
*/
atomic_set(&ioend->io_remaining, 1);
ioend->io_isasync = 0;
ioend->io_isdirect = 0;
ioend->io_error = 0;
ioend->io_list = NULL;
ioend->io_type = type;
Expand All @@ -234,6 +290,7 @@ xfs_alloc_ioend(
ioend->io_size = 0;
ioend->io_iocb = NULL;
ioend->io_result = 0;
ioend->io_append_trans = NULL;

INIT_WORK(&ioend->io_work, xfs_end_io);
return ioend;
Expand Down Expand Up @@ -341,18 +398,9 @@ xfs_submit_ioend_bio(
xfs_ioend_t *ioend,
struct bio *bio)
{
struct xfs_inode *ip = XFS_I(ioend->io_inode);
atomic_inc(&ioend->io_remaining);
bio->bi_private = ioend;
bio->bi_end_io = xfs_end_bio;

/*
* If the I/O is beyond EOF we mark the inode dirty immediately
* but don't update the inode size until I/O completion.
*/
if (xfs_new_eof(ip, ioend->io_offset + ioend->io_size))
xfs_mark_inode_dirty(ip);

submit_bio(wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE, bio);
}

Expand Down Expand Up @@ -999,8 +1047,20 @@ xfs_vm_writepage(
wbc, end_index);
}

if (iohead)
if (iohead) {
/*
* Reserve log space if we might write beyond the on-disk
* inode size.
*/
if (ioend->io_type != IO_UNWRITTEN &&
xfs_ioend_is_append(ioend)) {
err = xfs_setfilesize_trans_alloc(ioend);
if (err)
goto error;
}

xfs_submit_ioend(wbc, iohead);
}

return 0;

Expand Down Expand Up @@ -1280,17 +1340,32 @@ xfs_vm_direct_IO(
{
struct inode *inode = iocb->ki_filp->f_mapping->host;
struct block_device *bdev = xfs_find_bdev_for_inode(inode);
struct xfs_ioend *ioend = NULL;
ssize_t ret;

if (rw & WRITE) {
iocb->private = xfs_alloc_ioend(inode, IO_DIRECT);
size_t size = iov_length(iov, nr_segs);

/*
* We need to preallocate a transaction for a size update
* here. In the case that this write both updates the size
* and converts at least on unwritten extent we will cancel
* the still clean transaction after the I/O has finished.
*/
iocb->private = ioend = xfs_alloc_ioend(inode, IO_DIRECT);
if (offset + size > XFS_I(inode)->i_d.di_size) {
ret = xfs_setfilesize_trans_alloc(ioend);
if (ret)
goto out_destroy_ioend;
ioend->io_isdirect = 1;
}

ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov,
offset, nr_segs,
xfs_get_blocks_direct,
xfs_end_io_direct_write, NULL, 0);
if (ret != -EIOCBQUEUED && iocb->private)
xfs_destroy_ioend(iocb->private);
goto out_trans_cancel;
} else {
ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov,
offset, nr_segs,
Expand All @@ -1299,6 +1374,16 @@ xfs_vm_direct_IO(
}

return ret;

out_trans_cancel:
if (ioend->io_append_trans) {
current_set_flags_nested(&ioend->io_append_trans->t_pflags,
PF_FSTRANS);
xfs_trans_cancel(ioend->io_append_trans, 0);
}
out_destroy_ioend:
xfs_destroy_ioend(ioend);
return ret;
}

STATIC void
Expand Down
2 changes: 2 additions & 0 deletions trunk/fs/xfs/xfs_aops.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,14 @@ typedef struct xfs_ioend {
int io_error; /* I/O error code */
atomic_t io_remaining; /* hold count */
unsigned int io_isasync : 1; /* needs aio_complete */
unsigned int io_isdirect : 1;/* direct I/O */
struct inode *io_inode; /* file being written to */
struct buffer_head *io_buffer_head;/* buffer linked list head */
struct buffer_head *io_buffer_tail;/* buffer linked list tail */
size_t io_size; /* size of the extent */
xfs_off_t io_offset; /* offset in the file */
struct work_struct io_work; /* xfsdatad work queue */
struct xfs_trans *io_append_trans;/* xact. for size update */
struct kiocb *io_iocb;
int io_result;
} xfs_ioend_t;
Expand Down

0 comments on commit b4d87b0

Please sign in to comment.