Loading fs/xfs/kmem.c +0 −10 Original line number Diff line number Diff line Loading @@ -91,16 +91,6 @@ kmem_zalloc_large(size_t size, xfs_km_flags_t flags) return ptr; } void kmem_free(const void *ptr) { if (!is_vmalloc_addr(ptr)) { kfree(ptr); } else { vfree(ptr); } } void * kmem_realloc(const void *ptr, size_t newsize, size_t oldsize, xfs_km_flags_t flags) Loading fs/xfs/kmem.h +4 −1 Original line number Diff line number Diff line Loading @@ -63,7 +63,10 @@ kmem_flags_convert(xfs_km_flags_t flags) extern void *kmem_alloc(size_t, xfs_km_flags_t); extern void *kmem_zalloc_large(size_t size, xfs_km_flags_t); extern void *kmem_realloc(const void *, size_t, size_t, xfs_km_flags_t); extern void kmem_free(const void *); static inline void kmem_free(const void *ptr) { kvfree(ptr); } extern void *kmem_zalloc_greedy(size_t *, size_t, size_t); Loading fs/xfs/xfs_aops.c +61 −88 Original line number Diff line number Diff line Loading @@ -135,30 +135,22 @@ xfs_setfilesize_trans_alloc( */ STATIC int xfs_setfilesize( struct xfs_ioend *ioend) struct xfs_inode *ip, struct xfs_trans *tp, xfs_off_t offset, size_t size) { struct xfs_inode *ip = XFS_I(ioend->io_inode); struct xfs_trans *tp = ioend->io_append_trans; xfs_fsize_t isize; /* * The transaction may have been allocated in the I/O submission thread, * thus we need to mark ourselves as beeing in a transaction manually. * Similarly for freeze protection. */ current_set_flags_nested(&tp->t_pflags, PF_FSTRANS); rwsem_acquire_read(&VFS_I(ip)->i_sb->s_writers.lock_map[SB_FREEZE_FS-1], 0, 1, _THIS_IP_); xfs_ilock(ip, XFS_ILOCK_EXCL); isize = xfs_new_eof(ip, ioend->io_offset + ioend->io_size); isize = xfs_new_eof(ip, offset + size); if (!isize) { xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_trans_cancel(tp, 0); return 0; } trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size); trace_xfs_setfilesize(ip, offset, size); ip->i_d.di_size = isize; xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); Loading @@ -167,6 +159,25 @@ xfs_setfilesize( return xfs_trans_commit(tp, 0); } STATIC int xfs_setfilesize_ioend( struct xfs_ioend *ioend) { struct xfs_inode *ip = XFS_I(ioend->io_inode); struct xfs_trans *tp = ioend->io_append_trans; /* * The transaction may have been allocated in the I/O submission thread, * thus we need to mark ourselves as being in a transaction manually. * Similarly for freeze protection. */ current_set_flags_nested(&tp->t_pflags, PF_FSTRANS); rwsem_acquire_read(&VFS_I(ip)->i_sb->s_writers.lock_map[SB_FREEZE_FS-1], 0, 1, _THIS_IP_); return xfs_setfilesize(ip, tp, ioend->io_offset, ioend->io_size); } /* * Schedule IO completion handling on the final put of an ioend. * Loading @@ -182,8 +193,7 @@ xfs_finish_ioend( if (ioend->io_type == XFS_IO_UNWRITTEN) queue_work(mp->m_unwritten_workqueue, &ioend->io_work); else if (ioend->io_append_trans || (ioend->io_isdirect && 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); Loading Loading @@ -215,22 +225,8 @@ xfs_end_io( if (ioend->io_type == XFS_IO_UNWRITTEN) { error = xfs_iomap_write_unwritten(ip, ioend->io_offset, ioend->io_size); } else if (ioend->io_isdirect && xfs_ioend_is_append(ioend)) { /* * For direct I/O we do not know if we need to allocate blocks * or not so we can't preallocate an append transaction as that * results in nested reservations and log space deadlocks. Hence * allocate the transaction here. While this is sub-optimal and * can block IO completion for some time, we're stuck with doing * it this way until we can pass the ioend to the direct IO * allocation callbacks and avoid nesting that way. */ error = xfs_setfilesize_trans_alloc(ioend); if (error) goto done; error = xfs_setfilesize(ioend); } else if (ioend->io_append_trans) { error = xfs_setfilesize(ioend); error = xfs_setfilesize_ioend(ioend); } else { ASSERT(!xfs_ioend_is_append(ioend)); } Loading @@ -241,17 +237,6 @@ xfs_end_io( xfs_destroy_ioend(ioend); } /* * Call IO completion handling in caller context on the final put of an ioend. */ STATIC void xfs_finish_ioend_sync( struct xfs_ioend *ioend) { if (atomic_dec_and_test(&ioend->io_remaining)) xfs_end_io(&ioend->io_work); } /* * Allocate and initialise an IO completion structure. * We need to track unwritten extent write completion here initially. Loading @@ -273,7 +258,6 @@ xfs_alloc_ioend( * all the I/O from calling the completion routine too early. */ atomic_set(&ioend->io_remaining, 1); ioend->io_isdirect = 0; ioend->io_error = 0; ioend->io_list = NULL; ioend->io_type = type; Loading Loading @@ -1459,11 +1443,7 @@ xfs_get_blocks_direct( * * If the private argument is non-NULL __xfs_get_blocks signals us that we * need to issue a transaction to convert the range from unwritten to written * extents. In case this is regular synchronous I/O we just call xfs_end_io * to do this and we are done. But in case this was a successful AIO * request this handler is called from interrupt context, from which we * can't start transactions. In that case offload the I/O completion to * the workqueues we also use for buffered I/O completion. * extents. */ STATIC void xfs_end_io_direct_write( Loading @@ -1472,7 +1452,12 @@ xfs_end_io_direct_write( ssize_t size, void *private) { struct xfs_ioend *ioend = iocb->private; struct inode *inode = file_inode(iocb->ki_filp); struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; if (XFS_FORCED_SHUTDOWN(mp)) return; /* * While the generic direct I/O code updates the inode size, it does Loading @@ -1480,22 +1465,33 @@ xfs_end_io_direct_write( * end_io handler thinks the on-disk size is outside the in-core * size. To prevent this just update it a little bit earlier here. */ if (offset + size > i_size_read(ioend->io_inode)) i_size_write(ioend->io_inode, offset + size); if (offset + size > i_size_read(inode)) i_size_write(inode, offset + size); /* * blockdev_direct_IO can return an error even after the I/O * completion handler was called. Thus we need to protect * against double-freeing. * For direct I/O we do not know if we need to allocate blocks or not, * so we can't preallocate an append transaction, as that results in * nested reservations and log space deadlocks. Hence allocate the * transaction here. While this is sub-optimal and can block IO * completion for some time, we're stuck with doing it this way until * we can pass the ioend to the direct IO allocation callbacks and * avoid nesting that way. */ iocb->private = NULL; if (private && size > 0) { xfs_iomap_write_unwritten(ip, offset, size); } else if (offset + size > ip->i_d.di_size) { struct xfs_trans *tp; int error; ioend->io_offset = offset; ioend->io_size = size; if (private && size > 0) ioend->io_type = XFS_IO_UNWRITTEN; tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_fsyncts, 0, 0); if (error) { xfs_trans_cancel(tp, 0); return; } xfs_finish_ioend_sync(ioend); xfs_setfilesize(ip, tp, offset, size); } } STATIC ssize_t Loading @@ -1507,41 +1503,18 @@ 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) { size_t size = iov_iter_count(iter); /* * We cannot preallocate a size update transaction here as we * don't know whether allocation is necessary or not. Hence we * can only tell IO completion that one is necessary if we are * not doing unwritten extent conversion. */ iocb->private = ioend = xfs_alloc_ioend(inode, XFS_IO_DIRECT); if (offset + size > XFS_I(inode)->i_d.di_size) ioend->io_isdirect = 1; ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iter, return __blockdev_direct_IO(rw, iocb, inode, bdev, iter, offset, xfs_get_blocks_direct, xfs_end_io_direct_write, NULL, DIO_ASYNC_EXTEND); if (ret != -EIOCBQUEUED && iocb->private) goto out_destroy_ioend; } else { ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iter, } return __blockdev_direct_IO(rw, iocb, inode, bdev, iter, offset, xfs_get_blocks_direct, NULL, NULL, 0); } return ret; out_destroy_ioend: xfs_destroy_ioend(ioend); return ret; } /* * Punch out the delalloc blocks we have already allocated. * Loading fs/xfs/xfs_aops.h +0 −3 Original line number Diff line number Diff line Loading @@ -24,14 +24,12 @@ extern mempool_t *xfs_ioend_pool; * Types of I/O for bmap clustering and I/O completion tracking. */ enum { XFS_IO_DIRECT = 0, /* special case for direct I/O ioends */ XFS_IO_DELALLOC, /* covers delalloc region */ XFS_IO_UNWRITTEN, /* covers allocated but uninitialized data */ XFS_IO_OVERWRITE, /* covers already allocated extent */ }; #define XFS_IO_TYPES \ { 0, "" }, \ { XFS_IO_DELALLOC, "delalloc" }, \ { XFS_IO_UNWRITTEN, "unwritten" }, \ { XFS_IO_OVERWRITE, "overwrite" } Loading @@ -45,7 +43,6 @@ typedef struct xfs_ioend { unsigned int io_type; /* delalloc / unwritten */ int io_error; /* I/O error code */ atomic_t io_remaining; /* hold count */ 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 */ Loading fs/xfs/xfs_file.c +42 −22 Original line number Diff line number Diff line Loading @@ -127,6 +127,42 @@ xfs_iozero( return (-status); } int xfs_update_prealloc_flags( struct xfs_inode *ip, enum xfs_prealloc_flags flags) { struct xfs_trans *tp; int error; tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_WRITEID); error = xfs_trans_reserve(tp, &M_RES(ip->i_mount)->tr_writeid, 0, 0); if (error) { xfs_trans_cancel(tp, 0); return error; } xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); if (!(flags & XFS_PREALLOC_INVISIBLE)) { ip->i_d.di_mode &= ~S_ISUID; if (ip->i_d.di_mode & S_IXGRP) ip->i_d.di_mode &= ~S_ISGID; xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); } if (flags & XFS_PREALLOC_SET) ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; if (flags & XFS_PREALLOC_CLEAR) ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); if (flags & XFS_PREALLOC_SYNC) xfs_trans_set_sync(tp); return xfs_trans_commit(tp, 0); } /* * Fsync operations on directories are much simpler than on regular files, * as there is no file data to flush, and thus also no need for explicit Loading Loading @@ -784,8 +820,8 @@ xfs_file_fallocate( { struct inode *inode = file_inode(file); struct xfs_inode *ip = XFS_I(inode); struct xfs_trans *tp; long error; enum xfs_prealloc_flags flags = 0; loff_t new_size = 0; if (!S_ISREG(inode->i_mode)) Loading Loading @@ -822,6 +858,8 @@ xfs_file_fallocate( if (error) goto out_unlock; } else { flags |= XFS_PREALLOC_SET; if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > i_size_read(inode)) { new_size = offset + len; Loading @@ -839,28 +877,10 @@ xfs_file_fallocate( goto out_unlock; } tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_WRITEID); error = xfs_trans_reserve(tp, &M_RES(ip->i_mount)->tr_writeid, 0, 0); if (error) { xfs_trans_cancel(tp, 0); goto out_unlock; } xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); ip->i_d.di_mode &= ~S_ISUID; if (ip->i_d.di_mode & S_IXGRP) ip->i_d.di_mode &= ~S_ISGID; if (!(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE))) ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); if (file->f_flags & O_DSYNC) xfs_trans_set_sync(tp); error = xfs_trans_commit(tp, 0); flags |= XFS_PREALLOC_SYNC; error = xfs_update_prealloc_flags(ip, flags); if (error) goto out_unlock; Loading Loading
fs/xfs/kmem.c +0 −10 Original line number Diff line number Diff line Loading @@ -91,16 +91,6 @@ kmem_zalloc_large(size_t size, xfs_km_flags_t flags) return ptr; } void kmem_free(const void *ptr) { if (!is_vmalloc_addr(ptr)) { kfree(ptr); } else { vfree(ptr); } } void * kmem_realloc(const void *ptr, size_t newsize, size_t oldsize, xfs_km_flags_t flags) Loading
fs/xfs/kmem.h +4 −1 Original line number Diff line number Diff line Loading @@ -63,7 +63,10 @@ kmem_flags_convert(xfs_km_flags_t flags) extern void *kmem_alloc(size_t, xfs_km_flags_t); extern void *kmem_zalloc_large(size_t size, xfs_km_flags_t); extern void *kmem_realloc(const void *, size_t, size_t, xfs_km_flags_t); extern void kmem_free(const void *); static inline void kmem_free(const void *ptr) { kvfree(ptr); } extern void *kmem_zalloc_greedy(size_t *, size_t, size_t); Loading
fs/xfs/xfs_aops.c +61 −88 Original line number Diff line number Diff line Loading @@ -135,30 +135,22 @@ xfs_setfilesize_trans_alloc( */ STATIC int xfs_setfilesize( struct xfs_ioend *ioend) struct xfs_inode *ip, struct xfs_trans *tp, xfs_off_t offset, size_t size) { struct xfs_inode *ip = XFS_I(ioend->io_inode); struct xfs_trans *tp = ioend->io_append_trans; xfs_fsize_t isize; /* * The transaction may have been allocated in the I/O submission thread, * thus we need to mark ourselves as beeing in a transaction manually. * Similarly for freeze protection. */ current_set_flags_nested(&tp->t_pflags, PF_FSTRANS); rwsem_acquire_read(&VFS_I(ip)->i_sb->s_writers.lock_map[SB_FREEZE_FS-1], 0, 1, _THIS_IP_); xfs_ilock(ip, XFS_ILOCK_EXCL); isize = xfs_new_eof(ip, ioend->io_offset + ioend->io_size); isize = xfs_new_eof(ip, offset + size); if (!isize) { xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_trans_cancel(tp, 0); return 0; } trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size); trace_xfs_setfilesize(ip, offset, size); ip->i_d.di_size = isize; xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); Loading @@ -167,6 +159,25 @@ xfs_setfilesize( return xfs_trans_commit(tp, 0); } STATIC int xfs_setfilesize_ioend( struct xfs_ioend *ioend) { struct xfs_inode *ip = XFS_I(ioend->io_inode); struct xfs_trans *tp = ioend->io_append_trans; /* * The transaction may have been allocated in the I/O submission thread, * thus we need to mark ourselves as being in a transaction manually. * Similarly for freeze protection. */ current_set_flags_nested(&tp->t_pflags, PF_FSTRANS); rwsem_acquire_read(&VFS_I(ip)->i_sb->s_writers.lock_map[SB_FREEZE_FS-1], 0, 1, _THIS_IP_); return xfs_setfilesize(ip, tp, ioend->io_offset, ioend->io_size); } /* * Schedule IO completion handling on the final put of an ioend. * Loading @@ -182,8 +193,7 @@ xfs_finish_ioend( if (ioend->io_type == XFS_IO_UNWRITTEN) queue_work(mp->m_unwritten_workqueue, &ioend->io_work); else if (ioend->io_append_trans || (ioend->io_isdirect && 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); Loading Loading @@ -215,22 +225,8 @@ xfs_end_io( if (ioend->io_type == XFS_IO_UNWRITTEN) { error = xfs_iomap_write_unwritten(ip, ioend->io_offset, ioend->io_size); } else if (ioend->io_isdirect && xfs_ioend_is_append(ioend)) { /* * For direct I/O we do not know if we need to allocate blocks * or not so we can't preallocate an append transaction as that * results in nested reservations and log space deadlocks. Hence * allocate the transaction here. While this is sub-optimal and * can block IO completion for some time, we're stuck with doing * it this way until we can pass the ioend to the direct IO * allocation callbacks and avoid nesting that way. */ error = xfs_setfilesize_trans_alloc(ioend); if (error) goto done; error = xfs_setfilesize(ioend); } else if (ioend->io_append_trans) { error = xfs_setfilesize(ioend); error = xfs_setfilesize_ioend(ioend); } else { ASSERT(!xfs_ioend_is_append(ioend)); } Loading @@ -241,17 +237,6 @@ xfs_end_io( xfs_destroy_ioend(ioend); } /* * Call IO completion handling in caller context on the final put of an ioend. */ STATIC void xfs_finish_ioend_sync( struct xfs_ioend *ioend) { if (atomic_dec_and_test(&ioend->io_remaining)) xfs_end_io(&ioend->io_work); } /* * Allocate and initialise an IO completion structure. * We need to track unwritten extent write completion here initially. Loading @@ -273,7 +258,6 @@ xfs_alloc_ioend( * all the I/O from calling the completion routine too early. */ atomic_set(&ioend->io_remaining, 1); ioend->io_isdirect = 0; ioend->io_error = 0; ioend->io_list = NULL; ioend->io_type = type; Loading Loading @@ -1459,11 +1443,7 @@ xfs_get_blocks_direct( * * If the private argument is non-NULL __xfs_get_blocks signals us that we * need to issue a transaction to convert the range from unwritten to written * extents. In case this is regular synchronous I/O we just call xfs_end_io * to do this and we are done. But in case this was a successful AIO * request this handler is called from interrupt context, from which we * can't start transactions. In that case offload the I/O completion to * the workqueues we also use for buffered I/O completion. * extents. */ STATIC void xfs_end_io_direct_write( Loading @@ -1472,7 +1452,12 @@ xfs_end_io_direct_write( ssize_t size, void *private) { struct xfs_ioend *ioend = iocb->private; struct inode *inode = file_inode(iocb->ki_filp); struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; if (XFS_FORCED_SHUTDOWN(mp)) return; /* * While the generic direct I/O code updates the inode size, it does Loading @@ -1480,22 +1465,33 @@ xfs_end_io_direct_write( * end_io handler thinks the on-disk size is outside the in-core * size. To prevent this just update it a little bit earlier here. */ if (offset + size > i_size_read(ioend->io_inode)) i_size_write(ioend->io_inode, offset + size); if (offset + size > i_size_read(inode)) i_size_write(inode, offset + size); /* * blockdev_direct_IO can return an error even after the I/O * completion handler was called. Thus we need to protect * against double-freeing. * For direct I/O we do not know if we need to allocate blocks or not, * so we can't preallocate an append transaction, as that results in * nested reservations and log space deadlocks. Hence allocate the * transaction here. While this is sub-optimal and can block IO * completion for some time, we're stuck with doing it this way until * we can pass the ioend to the direct IO allocation callbacks and * avoid nesting that way. */ iocb->private = NULL; if (private && size > 0) { xfs_iomap_write_unwritten(ip, offset, size); } else if (offset + size > ip->i_d.di_size) { struct xfs_trans *tp; int error; ioend->io_offset = offset; ioend->io_size = size; if (private && size > 0) ioend->io_type = XFS_IO_UNWRITTEN; tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_fsyncts, 0, 0); if (error) { xfs_trans_cancel(tp, 0); return; } xfs_finish_ioend_sync(ioend); xfs_setfilesize(ip, tp, offset, size); } } STATIC ssize_t Loading @@ -1507,41 +1503,18 @@ 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) { size_t size = iov_iter_count(iter); /* * We cannot preallocate a size update transaction here as we * don't know whether allocation is necessary or not. Hence we * can only tell IO completion that one is necessary if we are * not doing unwritten extent conversion. */ iocb->private = ioend = xfs_alloc_ioend(inode, XFS_IO_DIRECT); if (offset + size > XFS_I(inode)->i_d.di_size) ioend->io_isdirect = 1; ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iter, return __blockdev_direct_IO(rw, iocb, inode, bdev, iter, offset, xfs_get_blocks_direct, xfs_end_io_direct_write, NULL, DIO_ASYNC_EXTEND); if (ret != -EIOCBQUEUED && iocb->private) goto out_destroy_ioend; } else { ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iter, } return __blockdev_direct_IO(rw, iocb, inode, bdev, iter, offset, xfs_get_blocks_direct, NULL, NULL, 0); } return ret; out_destroy_ioend: xfs_destroy_ioend(ioend); return ret; } /* * Punch out the delalloc blocks we have already allocated. * Loading
fs/xfs/xfs_aops.h +0 −3 Original line number Diff line number Diff line Loading @@ -24,14 +24,12 @@ extern mempool_t *xfs_ioend_pool; * Types of I/O for bmap clustering and I/O completion tracking. */ enum { XFS_IO_DIRECT = 0, /* special case for direct I/O ioends */ XFS_IO_DELALLOC, /* covers delalloc region */ XFS_IO_UNWRITTEN, /* covers allocated but uninitialized data */ XFS_IO_OVERWRITE, /* covers already allocated extent */ }; #define XFS_IO_TYPES \ { 0, "" }, \ { XFS_IO_DELALLOC, "delalloc" }, \ { XFS_IO_UNWRITTEN, "unwritten" }, \ { XFS_IO_OVERWRITE, "overwrite" } Loading @@ -45,7 +43,6 @@ typedef struct xfs_ioend { unsigned int io_type; /* delalloc / unwritten */ int io_error; /* I/O error code */ atomic_t io_remaining; /* hold count */ 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 */ Loading
fs/xfs/xfs_file.c +42 −22 Original line number Diff line number Diff line Loading @@ -127,6 +127,42 @@ xfs_iozero( return (-status); } int xfs_update_prealloc_flags( struct xfs_inode *ip, enum xfs_prealloc_flags flags) { struct xfs_trans *tp; int error; tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_WRITEID); error = xfs_trans_reserve(tp, &M_RES(ip->i_mount)->tr_writeid, 0, 0); if (error) { xfs_trans_cancel(tp, 0); return error; } xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); if (!(flags & XFS_PREALLOC_INVISIBLE)) { ip->i_d.di_mode &= ~S_ISUID; if (ip->i_d.di_mode & S_IXGRP) ip->i_d.di_mode &= ~S_ISGID; xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); } if (flags & XFS_PREALLOC_SET) ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; if (flags & XFS_PREALLOC_CLEAR) ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); if (flags & XFS_PREALLOC_SYNC) xfs_trans_set_sync(tp); return xfs_trans_commit(tp, 0); } /* * Fsync operations on directories are much simpler than on regular files, * as there is no file data to flush, and thus also no need for explicit Loading Loading @@ -784,8 +820,8 @@ xfs_file_fallocate( { struct inode *inode = file_inode(file); struct xfs_inode *ip = XFS_I(inode); struct xfs_trans *tp; long error; enum xfs_prealloc_flags flags = 0; loff_t new_size = 0; if (!S_ISREG(inode->i_mode)) Loading Loading @@ -822,6 +858,8 @@ xfs_file_fallocate( if (error) goto out_unlock; } else { flags |= XFS_PREALLOC_SET; if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > i_size_read(inode)) { new_size = offset + len; Loading @@ -839,28 +877,10 @@ xfs_file_fallocate( goto out_unlock; } tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_WRITEID); error = xfs_trans_reserve(tp, &M_RES(ip->i_mount)->tr_writeid, 0, 0); if (error) { xfs_trans_cancel(tp, 0); goto out_unlock; } xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); ip->i_d.di_mode &= ~S_ISUID; if (ip->i_d.di_mode & S_IXGRP) ip->i_d.di_mode &= ~S_ISGID; if (!(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE))) ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); if (file->f_flags & O_DSYNC) xfs_trans_set_sync(tp); error = xfs_trans_commit(tp, 0); flags |= XFS_PREALLOC_SYNC; error = xfs_update_prealloc_flags(ip, flags); if (error) goto out_unlock; Loading