diff options
author | Dave Chinner <david@fromorbit.com> | 2015-02-01 18:03:18 -0500 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2015-02-01 18:03:18 -0500 |
commit | 3fd1b0d158b6b98d9561e2f7f9c6970d95cf71d6 (patch) | |
tree | 3a32490a8db83ca2ed6da6701af20e3cd6adff2c | |
parent | 438c3c8d2bb910966db6fc4140e62d67b3c5f2a8 (diff) | |
parent | 2ba66237029d1ad6c1a5e2241b0ffbbfff55f750 (diff) |
Merge branch 'xfs-misc-fixes-for-3.20-3' into for-next
-rw-r--r-- | fs/xfs/kmem.c | 10 | ||||
-rw-r--r-- | fs/xfs/kmem.h | 5 | ||||
-rw-r--r-- | fs/xfs/xfs_aops.c | 149 | ||||
-rw-r--r-- | fs/xfs/xfs_aops.h | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_file.c | 64 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.h | 9 | ||||
-rw-r--r-- | fs/xfs/xfs_ioctl.c | 50 | ||||
-rw-r--r-- | fs/xfs/xfs_ioctl32.c | 2 |
8 files changed, 129 insertions, 163 deletions
diff --git a/fs/xfs/kmem.c b/fs/xfs/kmem.c index 53e95b2a1369..a7a3a63bb360 100644 --- a/fs/xfs/kmem.c +++ b/fs/xfs/kmem.c | |||
@@ -91,16 +91,6 @@ kmem_zalloc_large(size_t size, xfs_km_flags_t flags) | |||
91 | return ptr; | 91 | return ptr; |
92 | } | 92 | } |
93 | 93 | ||
94 | void | ||
95 | kmem_free(const void *ptr) | ||
96 | { | ||
97 | if (!is_vmalloc_addr(ptr)) { | ||
98 | kfree(ptr); | ||
99 | } else { | ||
100 | vfree(ptr); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | void * | 94 | void * |
105 | kmem_realloc(const void *ptr, size_t newsize, size_t oldsize, | 95 | kmem_realloc(const void *ptr, size_t newsize, size_t oldsize, |
106 | xfs_km_flags_t flags) | 96 | xfs_km_flags_t flags) |
diff --git a/fs/xfs/kmem.h b/fs/xfs/kmem.h index 64db0e53edea..cc6b768fc068 100644 --- a/fs/xfs/kmem.h +++ b/fs/xfs/kmem.h | |||
@@ -63,7 +63,10 @@ kmem_flags_convert(xfs_km_flags_t flags) | |||
63 | extern void *kmem_alloc(size_t, xfs_km_flags_t); | 63 | extern void *kmem_alloc(size_t, xfs_km_flags_t); |
64 | extern void *kmem_zalloc_large(size_t size, xfs_km_flags_t); | 64 | extern void *kmem_zalloc_large(size_t size, xfs_km_flags_t); |
65 | extern void *kmem_realloc(const void *, size_t, size_t, xfs_km_flags_t); | 65 | extern void *kmem_realloc(const void *, size_t, size_t, xfs_km_flags_t); |
66 | extern void kmem_free(const void *); | 66 | static inline void kmem_free(const void *ptr) |
67 | { | ||
68 | kvfree(ptr); | ||
69 | } | ||
67 | 70 | ||
68 | 71 | ||
69 | extern void *kmem_zalloc_greedy(size_t *, size_t, size_t); | 72 | extern void *kmem_zalloc_greedy(size_t *, size_t, size_t); |
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 18e2f3bbae5e..3a9b7a1b8704 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c | |||
@@ -135,30 +135,22 @@ xfs_setfilesize_trans_alloc( | |||
135 | */ | 135 | */ |
136 | STATIC int | 136 | STATIC int |
137 | xfs_setfilesize( | 137 | xfs_setfilesize( |
138 | struct xfs_ioend *ioend) | 138 | struct xfs_inode *ip, |
139 | struct xfs_trans *tp, | ||
140 | xfs_off_t offset, | ||
141 | size_t size) | ||
139 | { | 142 | { |
140 | struct xfs_inode *ip = XFS_I(ioend->io_inode); | ||
141 | struct xfs_trans *tp = ioend->io_append_trans; | ||
142 | xfs_fsize_t isize; | 143 | xfs_fsize_t isize; |
143 | 144 | ||
144 | /* | ||
145 | * The transaction may have been allocated in the I/O submission thread, | ||
146 | * thus we need to mark ourselves as beeing in a transaction manually. | ||
147 | * Similarly for freeze protection. | ||
148 | */ | ||
149 | current_set_flags_nested(&tp->t_pflags, PF_FSTRANS); | ||
150 | rwsem_acquire_read(&VFS_I(ip)->i_sb->s_writers.lock_map[SB_FREEZE_FS-1], | ||
151 | 0, 1, _THIS_IP_); | ||
152 | |||
153 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 145 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
154 | isize = xfs_new_eof(ip, ioend->io_offset + ioend->io_size); | 146 | isize = xfs_new_eof(ip, offset + size); |
155 | if (!isize) { | 147 | if (!isize) { |
156 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 148 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
157 | xfs_trans_cancel(tp, 0); | 149 | xfs_trans_cancel(tp, 0); |
158 | return 0; | 150 | return 0; |
159 | } | 151 | } |
160 | 152 | ||
161 | trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size); | 153 | trace_xfs_setfilesize(ip, offset, size); |
162 | 154 | ||
163 | ip->i_d.di_size = isize; | 155 | ip->i_d.di_size = isize; |
164 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | 156 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); |
@@ -167,6 +159,25 @@ xfs_setfilesize( | |||
167 | return xfs_trans_commit(tp, 0); | 159 | return xfs_trans_commit(tp, 0); |
168 | } | 160 | } |
169 | 161 | ||
162 | STATIC int | ||
163 | xfs_setfilesize_ioend( | ||
164 | struct xfs_ioend *ioend) | ||
165 | { | ||
166 | struct xfs_inode *ip = XFS_I(ioend->io_inode); | ||
167 | struct xfs_trans *tp = ioend->io_append_trans; | ||
168 | |||
169 | /* | ||
170 | * The transaction may have been allocated in the I/O submission thread, | ||
171 | * thus we need to mark ourselves as being in a transaction manually. | ||
172 | * Similarly for freeze protection. | ||
173 | */ | ||
174 | current_set_flags_nested(&tp->t_pflags, PF_FSTRANS); | ||
175 | rwsem_acquire_read(&VFS_I(ip)->i_sb->s_writers.lock_map[SB_FREEZE_FS-1], | ||
176 | 0, 1, _THIS_IP_); | ||
177 | |||
178 | return xfs_setfilesize(ip, tp, ioend->io_offset, ioend->io_size); | ||
179 | } | ||
180 | |||
170 | /* | 181 | /* |
171 | * Schedule IO completion handling on the final put of an ioend. | 182 | * Schedule IO completion handling on the final put of an ioend. |
172 | * | 183 | * |
@@ -182,8 +193,7 @@ xfs_finish_ioend( | |||
182 | 193 | ||
183 | if (ioend->io_type == XFS_IO_UNWRITTEN) | 194 | if (ioend->io_type == XFS_IO_UNWRITTEN) |
184 | queue_work(mp->m_unwritten_workqueue, &ioend->io_work); | 195 | queue_work(mp->m_unwritten_workqueue, &ioend->io_work); |
185 | else if (ioend->io_append_trans || | 196 | else if (ioend->io_append_trans) |
186 | (ioend->io_isdirect && xfs_ioend_is_append(ioend))) | ||
187 | queue_work(mp->m_data_workqueue, &ioend->io_work); | 197 | queue_work(mp->m_data_workqueue, &ioend->io_work); |
188 | else | 198 | else |
189 | xfs_destroy_ioend(ioend); | 199 | xfs_destroy_ioend(ioend); |
@@ -215,22 +225,8 @@ xfs_end_io( | |||
215 | if (ioend->io_type == XFS_IO_UNWRITTEN) { | 225 | if (ioend->io_type == XFS_IO_UNWRITTEN) { |
216 | error = xfs_iomap_write_unwritten(ip, ioend->io_offset, | 226 | error = xfs_iomap_write_unwritten(ip, ioend->io_offset, |
217 | ioend->io_size); | 227 | ioend->io_size); |
218 | } else if (ioend->io_isdirect && xfs_ioend_is_append(ioend)) { | ||
219 | /* | ||
220 | * For direct I/O we do not know if we need to allocate blocks | ||
221 | * or not so we can't preallocate an append transaction as that | ||
222 | * results in nested reservations and log space deadlocks. Hence | ||
223 | * allocate the transaction here. While this is sub-optimal and | ||
224 | * can block IO completion for some time, we're stuck with doing | ||
225 | * it this way until we can pass the ioend to the direct IO | ||
226 | * allocation callbacks and avoid nesting that way. | ||
227 | */ | ||
228 | error = xfs_setfilesize_trans_alloc(ioend); | ||
229 | if (error) | ||
230 | goto done; | ||
231 | error = xfs_setfilesize(ioend); | ||
232 | } else if (ioend->io_append_trans) { | 228 | } else if (ioend->io_append_trans) { |
233 | error = xfs_setfilesize(ioend); | 229 | error = xfs_setfilesize_ioend(ioend); |
234 | } else { | 230 | } else { |
235 | ASSERT(!xfs_ioend_is_append(ioend)); | 231 | ASSERT(!xfs_ioend_is_append(ioend)); |
236 | } | 232 | } |
@@ -242,17 +238,6 @@ done: | |||
242 | } | 238 | } |
243 | 239 | ||
244 | /* | 240 | /* |
245 | * Call IO completion handling in caller context on the final put of an ioend. | ||
246 | */ | ||
247 | STATIC void | ||
248 | xfs_finish_ioend_sync( | ||
249 | struct xfs_ioend *ioend) | ||
250 | { | ||
251 | if (atomic_dec_and_test(&ioend->io_remaining)) | ||
252 | xfs_end_io(&ioend->io_work); | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * Allocate and initialise an IO completion structure. | 241 | * Allocate and initialise an IO completion structure. |
257 | * We need to track unwritten extent write completion here initially. | 242 | * We need to track unwritten extent write completion here initially. |
258 | * We'll need to extend this for updating the ondisk inode size later | 243 | * We'll need to extend this for updating the ondisk inode size later |
@@ -273,7 +258,6 @@ xfs_alloc_ioend( | |||
273 | * all the I/O from calling the completion routine too early. | 258 | * all the I/O from calling the completion routine too early. |
274 | */ | 259 | */ |
275 | atomic_set(&ioend->io_remaining, 1); | 260 | atomic_set(&ioend->io_remaining, 1); |
276 | ioend->io_isdirect = 0; | ||
277 | ioend->io_error = 0; | 261 | ioend->io_error = 0; |
278 | ioend->io_list = NULL; | 262 | ioend->io_list = NULL; |
279 | ioend->io_type = type; | 263 | ioend->io_type = type; |
@@ -1459,11 +1443,7 @@ xfs_get_blocks_direct( | |||
1459 | * | 1443 | * |
1460 | * If the private argument is non-NULL __xfs_get_blocks signals us that we | 1444 | * If the private argument is non-NULL __xfs_get_blocks signals us that we |
1461 | * need to issue a transaction to convert the range from unwritten to written | 1445 | * need to issue a transaction to convert the range from unwritten to written |
1462 | * extents. In case this is regular synchronous I/O we just call xfs_end_io | 1446 | * extents. |
1463 | * to do this and we are done. But in case this was a successful AIO | ||
1464 | * request this handler is called from interrupt context, from which we | ||
1465 | * can't start transactions. In that case offload the I/O completion to | ||
1466 | * the workqueues we also use for buffered I/O completion. | ||
1467 | */ | 1447 | */ |
1468 | STATIC void | 1448 | STATIC void |
1469 | xfs_end_io_direct_write( | 1449 | xfs_end_io_direct_write( |
@@ -1472,7 +1452,12 @@ xfs_end_io_direct_write( | |||
1472 | ssize_t size, | 1452 | ssize_t size, |
1473 | void *private) | 1453 | void *private) |
1474 | { | 1454 | { |
1475 | struct xfs_ioend *ioend = iocb->private; | 1455 | struct inode *inode = file_inode(iocb->ki_filp); |
1456 | struct xfs_inode *ip = XFS_I(inode); | ||
1457 | struct xfs_mount *mp = ip->i_mount; | ||
1458 | |||
1459 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
1460 | return; | ||
1476 | 1461 | ||
1477 | /* | 1462 | /* |
1478 | * While the generic direct I/O code updates the inode size, it does | 1463 | * While the generic direct I/O code updates the inode size, it does |
@@ -1480,22 +1465,33 @@ xfs_end_io_direct_write( | |||
1480 | * end_io handler thinks the on-disk size is outside the in-core | 1465 | * end_io handler thinks the on-disk size is outside the in-core |
1481 | * size. To prevent this just update it a little bit earlier here. | 1466 | * size. To prevent this just update it a little bit earlier here. |
1482 | */ | 1467 | */ |
1483 | if (offset + size > i_size_read(ioend->io_inode)) | 1468 | if (offset + size > i_size_read(inode)) |
1484 | i_size_write(ioend->io_inode, offset + size); | 1469 | i_size_write(inode, offset + size); |
1485 | 1470 | ||
1486 | /* | 1471 | /* |
1487 | * blockdev_direct_IO can return an error even after the I/O | 1472 | * For direct I/O we do not know if we need to allocate blocks or not, |
1488 | * completion handler was called. Thus we need to protect | 1473 | * so we can't preallocate an append transaction, as that results in |
1489 | * against double-freeing. | 1474 | * nested reservations and log space deadlocks. Hence allocate the |
1475 | * transaction here. While this is sub-optimal and can block IO | ||
1476 | * completion for some time, we're stuck with doing it this way until | ||
1477 | * we can pass the ioend to the direct IO allocation callbacks and | ||
1478 | * avoid nesting that way. | ||
1490 | */ | 1479 | */ |
1491 | iocb->private = NULL; | 1480 | if (private && size > 0) { |
1492 | 1481 | xfs_iomap_write_unwritten(ip, offset, size); | |
1493 | ioend->io_offset = offset; | 1482 | } else if (offset + size > ip->i_d.di_size) { |
1494 | ioend->io_size = size; | 1483 | struct xfs_trans *tp; |
1495 | if (private && size > 0) | 1484 | int error; |
1496 | ioend->io_type = XFS_IO_UNWRITTEN; | 1485 | |
1486 | tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS); | ||
1487 | error = xfs_trans_reserve(tp, &M_RES(mp)->tr_fsyncts, 0, 0); | ||
1488 | if (error) { | ||
1489 | xfs_trans_cancel(tp, 0); | ||
1490 | return; | ||
1491 | } | ||
1497 | 1492 | ||
1498 | xfs_finish_ioend_sync(ioend); | 1493 | xfs_setfilesize(ip, tp, offset, size); |
1494 | } | ||
1499 | } | 1495 | } |
1500 | 1496 | ||
1501 | STATIC ssize_t | 1497 | STATIC ssize_t |
@@ -1507,39 +1503,16 @@ xfs_vm_direct_IO( | |||
1507 | { | 1503 | { |
1508 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 1504 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
1509 | struct block_device *bdev = xfs_find_bdev_for_inode(inode); | 1505 | struct block_device *bdev = xfs_find_bdev_for_inode(inode); |
1510 | struct xfs_ioend *ioend = NULL; | ||
1511 | ssize_t ret; | ||
1512 | 1506 | ||
1513 | if (rw & WRITE) { | 1507 | if (rw & WRITE) { |
1514 | size_t size = iov_iter_count(iter); | 1508 | return __blockdev_direct_IO(rw, iocb, inode, bdev, iter, |
1515 | |||
1516 | /* | ||
1517 | * We cannot preallocate a size update transaction here as we | ||
1518 | * don't know whether allocation is necessary or not. Hence we | ||
1519 | * can only tell IO completion that one is necessary if we are | ||
1520 | * not doing unwritten extent conversion. | ||
1521 | */ | ||
1522 | iocb->private = ioend = xfs_alloc_ioend(inode, XFS_IO_DIRECT); | ||
1523 | if (offset + size > XFS_I(inode)->i_d.di_size) | ||
1524 | ioend->io_isdirect = 1; | ||
1525 | |||
1526 | ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iter, | ||
1527 | offset, xfs_get_blocks_direct, | 1509 | offset, xfs_get_blocks_direct, |
1528 | xfs_end_io_direct_write, NULL, | 1510 | xfs_end_io_direct_write, NULL, |
1529 | DIO_ASYNC_EXTEND); | 1511 | DIO_ASYNC_EXTEND); |
1530 | if (ret != -EIOCBQUEUED && iocb->private) | ||
1531 | goto out_destroy_ioend; | ||
1532 | } else { | ||
1533 | ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iter, | ||
1534 | offset, xfs_get_blocks_direct, | ||
1535 | NULL, NULL, 0); | ||
1536 | } | 1512 | } |
1537 | 1513 | return __blockdev_direct_IO(rw, iocb, inode, bdev, iter, | |
1538 | return ret; | 1514 | offset, xfs_get_blocks_direct, |
1539 | 1515 | NULL, NULL, 0); | |
1540 | out_destroy_ioend: | ||
1541 | xfs_destroy_ioend(ioend); | ||
1542 | return ret; | ||
1543 | } | 1516 | } |
1544 | 1517 | ||
1545 | /* | 1518 | /* |
diff --git a/fs/xfs/xfs_aops.h b/fs/xfs/xfs_aops.h index f94dd459dff9..ac644e0137a4 100644 --- a/fs/xfs/xfs_aops.h +++ b/fs/xfs/xfs_aops.h | |||
@@ -24,14 +24,12 @@ extern mempool_t *xfs_ioend_pool; | |||
24 | * Types of I/O for bmap clustering and I/O completion tracking. | 24 | * Types of I/O for bmap clustering and I/O completion tracking. |
25 | */ | 25 | */ |
26 | enum { | 26 | enum { |
27 | XFS_IO_DIRECT = 0, /* special case for direct I/O ioends */ | ||
28 | XFS_IO_DELALLOC, /* covers delalloc region */ | 27 | XFS_IO_DELALLOC, /* covers delalloc region */ |
29 | XFS_IO_UNWRITTEN, /* covers allocated but uninitialized data */ | 28 | XFS_IO_UNWRITTEN, /* covers allocated but uninitialized data */ |
30 | XFS_IO_OVERWRITE, /* covers already allocated extent */ | 29 | XFS_IO_OVERWRITE, /* covers already allocated extent */ |
31 | }; | 30 | }; |
32 | 31 | ||
33 | #define XFS_IO_TYPES \ | 32 | #define XFS_IO_TYPES \ |
34 | { 0, "" }, \ | ||
35 | { XFS_IO_DELALLOC, "delalloc" }, \ | 33 | { XFS_IO_DELALLOC, "delalloc" }, \ |
36 | { XFS_IO_UNWRITTEN, "unwritten" }, \ | 34 | { XFS_IO_UNWRITTEN, "unwritten" }, \ |
37 | { XFS_IO_OVERWRITE, "overwrite" } | 35 | { XFS_IO_OVERWRITE, "overwrite" } |
@@ -45,7 +43,6 @@ typedef struct xfs_ioend { | |||
45 | unsigned int io_type; /* delalloc / unwritten */ | 43 | unsigned int io_type; /* delalloc / unwritten */ |
46 | int io_error; /* I/O error code */ | 44 | int io_error; /* I/O error code */ |
47 | atomic_t io_remaining; /* hold count */ | 45 | atomic_t io_remaining; /* hold count */ |
48 | unsigned int io_isdirect : 1;/* direct I/O */ | ||
49 | struct inode *io_inode; /* file being written to */ | 46 | struct inode *io_inode; /* file being written to */ |
50 | struct buffer_head *io_buffer_head;/* buffer linked list head */ | 47 | struct buffer_head *io_buffer_head;/* buffer linked list head */ |
51 | struct buffer_head *io_buffer_tail;/* buffer linked list tail */ | 48 | struct buffer_head *io_buffer_tail;/* buffer linked list tail */ |
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 13e974e6a889..712d312d8e3e 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -127,6 +127,42 @@ xfs_iozero( | |||
127 | return (-status); | 127 | return (-status); |
128 | } | 128 | } |
129 | 129 | ||
130 | int | ||
131 | xfs_update_prealloc_flags( | ||
132 | struct xfs_inode *ip, | ||
133 | enum xfs_prealloc_flags flags) | ||
134 | { | ||
135 | struct xfs_trans *tp; | ||
136 | int error; | ||
137 | |||
138 | tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_WRITEID); | ||
139 | error = xfs_trans_reserve(tp, &M_RES(ip->i_mount)->tr_writeid, 0, 0); | ||
140 | if (error) { | ||
141 | xfs_trans_cancel(tp, 0); | ||
142 | return error; | ||
143 | } | ||
144 | |||
145 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
146 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | ||
147 | |||
148 | if (!(flags & XFS_PREALLOC_INVISIBLE)) { | ||
149 | ip->i_d.di_mode &= ~S_ISUID; | ||
150 | if (ip->i_d.di_mode & S_IXGRP) | ||
151 | ip->i_d.di_mode &= ~S_ISGID; | ||
152 | xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | ||
153 | } | ||
154 | |||
155 | if (flags & XFS_PREALLOC_SET) | ||
156 | ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; | ||
157 | if (flags & XFS_PREALLOC_CLEAR) | ||
158 | ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC; | ||
159 | |||
160 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
161 | if (flags & XFS_PREALLOC_SYNC) | ||
162 | xfs_trans_set_sync(tp); | ||
163 | return xfs_trans_commit(tp, 0); | ||
164 | } | ||
165 | |||
130 | /* | 166 | /* |
131 | * Fsync operations on directories are much simpler than on regular files, | 167 | * Fsync operations on directories are much simpler than on regular files, |
132 | * as there is no file data to flush, and thus also no need for explicit | 168 | * as there is no file data to flush, and thus also no need for explicit |
@@ -784,8 +820,8 @@ xfs_file_fallocate( | |||
784 | { | 820 | { |
785 | struct inode *inode = file_inode(file); | 821 | struct inode *inode = file_inode(file); |
786 | struct xfs_inode *ip = XFS_I(inode); | 822 | struct xfs_inode *ip = XFS_I(inode); |
787 | struct xfs_trans *tp; | ||
788 | long error; | 823 | long error; |
824 | enum xfs_prealloc_flags flags = 0; | ||
789 | loff_t new_size = 0; | 825 | loff_t new_size = 0; |
790 | 826 | ||
791 | if (!S_ISREG(inode->i_mode)) | 827 | if (!S_ISREG(inode->i_mode)) |
@@ -822,6 +858,8 @@ xfs_file_fallocate( | |||
822 | if (error) | 858 | if (error) |
823 | goto out_unlock; | 859 | goto out_unlock; |
824 | } else { | 860 | } else { |
861 | flags |= XFS_PREALLOC_SET; | ||
862 | |||
825 | if (!(mode & FALLOC_FL_KEEP_SIZE) && | 863 | if (!(mode & FALLOC_FL_KEEP_SIZE) && |
826 | offset + len > i_size_read(inode)) { | 864 | offset + len > i_size_read(inode)) { |
827 | new_size = offset + len; | 865 | new_size = offset + len; |
@@ -839,28 +877,10 @@ xfs_file_fallocate( | |||
839 | goto out_unlock; | 877 | goto out_unlock; |
840 | } | 878 | } |
841 | 879 | ||
842 | tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_WRITEID); | ||
843 | error = xfs_trans_reserve(tp, &M_RES(ip->i_mount)->tr_writeid, 0, 0); | ||
844 | if (error) { | ||
845 | xfs_trans_cancel(tp, 0); | ||
846 | goto out_unlock; | ||
847 | } | ||
848 | |||
849 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
850 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | ||
851 | ip->i_d.di_mode &= ~S_ISUID; | ||
852 | if (ip->i_d.di_mode & S_IXGRP) | ||
853 | ip->i_d.di_mode &= ~S_ISGID; | ||
854 | |||
855 | if (!(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE))) | ||
856 | ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; | ||
857 | |||
858 | xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | ||
859 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
860 | |||
861 | if (file->f_flags & O_DSYNC) | 880 | if (file->f_flags & O_DSYNC) |
862 | xfs_trans_set_sync(tp); | 881 | flags |= XFS_PREALLOC_SYNC; |
863 | error = xfs_trans_commit(tp, 0); | 882 | |
883 | error = xfs_update_prealloc_flags(ip, flags); | ||
864 | if (error) | 884 | if (error) |
865 | goto out_unlock; | 885 | goto out_unlock; |
866 | 886 | ||
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index f7722960b69c..86cd6b39bed7 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
@@ -377,6 +377,15 @@ int xfs_droplink(struct xfs_trans *, struct xfs_inode *); | |||
377 | int xfs_bumplink(struct xfs_trans *, struct xfs_inode *); | 377 | int xfs_bumplink(struct xfs_trans *, struct xfs_inode *); |
378 | 378 | ||
379 | /* from xfs_file.c */ | 379 | /* from xfs_file.c */ |
380 | enum xfs_prealloc_flags { | ||
381 | XFS_PREALLOC_SET = (1 << 1), | ||
382 | XFS_PREALLOC_CLEAR = (1 << 2), | ||
383 | XFS_PREALLOC_SYNC = (1 << 3), | ||
384 | XFS_PREALLOC_INVISIBLE = (1 << 4), | ||
385 | }; | ||
386 | |||
387 | int xfs_update_prealloc_flags(struct xfs_inode *, | ||
388 | enum xfs_prealloc_flags); | ||
380 | int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t); | 389 | int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t); |
381 | int xfs_iozero(struct xfs_inode *, loff_t, size_t); | 390 | int xfs_iozero(struct xfs_inode *, loff_t, size_t); |
382 | 391 | ||
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index a1831980a68e..d58bcd28f5f8 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c | |||
@@ -606,11 +606,8 @@ xfs_ioc_space( | |||
606 | unsigned int cmd, | 606 | unsigned int cmd, |
607 | xfs_flock64_t *bf) | 607 | xfs_flock64_t *bf) |
608 | { | 608 | { |
609 | struct xfs_mount *mp = ip->i_mount; | ||
610 | struct xfs_trans *tp; | ||
611 | struct iattr iattr; | 609 | struct iattr iattr; |
612 | bool setprealloc = false; | 610 | enum xfs_prealloc_flags flags = 0; |
613 | bool clrprealloc = false; | ||
614 | int error; | 611 | int error; |
615 | 612 | ||
616 | /* | 613 | /* |
@@ -630,6 +627,11 @@ xfs_ioc_space( | |||
630 | if (!S_ISREG(inode->i_mode)) | 627 | if (!S_ISREG(inode->i_mode)) |
631 | return -EINVAL; | 628 | return -EINVAL; |
632 | 629 | ||
630 | if (filp->f_flags & O_DSYNC) | ||
631 | flags |= XFS_PREALLOC_SYNC; | ||
632 | if (ioflags & XFS_IO_INVIS) | ||
633 | flags |= XFS_PREALLOC_INVISIBLE; | ||
634 | |||
633 | error = mnt_want_write_file(filp); | 635 | error = mnt_want_write_file(filp); |
634 | if (error) | 636 | if (error) |
635 | return error; | 637 | return error; |
@@ -673,25 +675,23 @@ xfs_ioc_space( | |||
673 | } | 675 | } |
674 | 676 | ||
675 | if (bf->l_start < 0 || | 677 | if (bf->l_start < 0 || |
676 | bf->l_start > mp->m_super->s_maxbytes || | 678 | bf->l_start > inode->i_sb->s_maxbytes || |
677 | bf->l_start + bf->l_len < 0 || | 679 | bf->l_start + bf->l_len < 0 || |
678 | bf->l_start + bf->l_len >= mp->m_super->s_maxbytes) { | 680 | bf->l_start + bf->l_len >= inode->i_sb->s_maxbytes) { |
679 | error = -EINVAL; | 681 | error = -EINVAL; |
680 | goto out_unlock; | 682 | goto out_unlock; |
681 | } | 683 | } |
682 | 684 | ||
683 | switch (cmd) { | 685 | switch (cmd) { |
684 | case XFS_IOC_ZERO_RANGE: | 686 | case XFS_IOC_ZERO_RANGE: |
687 | flags |= XFS_PREALLOC_SET; | ||
685 | error = xfs_zero_file_space(ip, bf->l_start, bf->l_len); | 688 | error = xfs_zero_file_space(ip, bf->l_start, bf->l_len); |
686 | if (!error) | ||
687 | setprealloc = true; | ||
688 | break; | 689 | break; |
689 | case XFS_IOC_RESVSP: | 690 | case XFS_IOC_RESVSP: |
690 | case XFS_IOC_RESVSP64: | 691 | case XFS_IOC_RESVSP64: |
692 | flags |= XFS_PREALLOC_SET; | ||
691 | error = xfs_alloc_file_space(ip, bf->l_start, bf->l_len, | 693 | error = xfs_alloc_file_space(ip, bf->l_start, bf->l_len, |
692 | XFS_BMAPI_PREALLOC); | 694 | XFS_BMAPI_PREALLOC); |
693 | if (!error) | ||
694 | setprealloc = true; | ||
695 | break; | 695 | break; |
696 | case XFS_IOC_UNRESVSP: | 696 | case XFS_IOC_UNRESVSP: |
697 | case XFS_IOC_UNRESVSP64: | 697 | case XFS_IOC_UNRESVSP64: |
@@ -701,6 +701,7 @@ xfs_ioc_space( | |||
701 | case XFS_IOC_ALLOCSP64: | 701 | case XFS_IOC_ALLOCSP64: |
702 | case XFS_IOC_FREESP: | 702 | case XFS_IOC_FREESP: |
703 | case XFS_IOC_FREESP64: | 703 | case XFS_IOC_FREESP64: |
704 | flags |= XFS_PREALLOC_CLEAR; | ||
704 | if (bf->l_start > XFS_ISIZE(ip)) { | 705 | if (bf->l_start > XFS_ISIZE(ip)) { |
705 | error = xfs_alloc_file_space(ip, XFS_ISIZE(ip), | 706 | error = xfs_alloc_file_space(ip, XFS_ISIZE(ip), |
706 | bf->l_start - XFS_ISIZE(ip), 0); | 707 | bf->l_start - XFS_ISIZE(ip), 0); |
@@ -712,8 +713,6 @@ xfs_ioc_space( | |||
712 | iattr.ia_size = bf->l_start; | 713 | iattr.ia_size = bf->l_start; |
713 | 714 | ||
714 | error = xfs_setattr_size(ip, &iattr); | 715 | error = xfs_setattr_size(ip, &iattr); |
715 | if (!error) | ||
716 | clrprealloc = true; | ||
717 | break; | 716 | break; |
718 | default: | 717 | default: |
719 | ASSERT(0); | 718 | ASSERT(0); |
@@ -723,32 +722,7 @@ xfs_ioc_space( | |||
723 | if (error) | 722 | if (error) |
724 | goto out_unlock; | 723 | goto out_unlock; |
725 | 724 | ||
726 | tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID); | 725 | error = xfs_update_prealloc_flags(ip, flags); |
727 | error = xfs_trans_reserve(tp, &M_RES(mp)->tr_writeid, 0, 0); | ||
728 | if (error) { | ||
729 | xfs_trans_cancel(tp, 0); | ||
730 | goto out_unlock; | ||
731 | } | ||
732 | |||
733 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
734 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | ||
735 | |||
736 | if (!(ioflags & XFS_IO_INVIS)) { | ||
737 | ip->i_d.di_mode &= ~S_ISUID; | ||
738 | if (ip->i_d.di_mode & S_IXGRP) | ||
739 | ip->i_d.di_mode &= ~S_ISGID; | ||
740 | xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | ||
741 | } | ||
742 | |||
743 | if (setprealloc) | ||
744 | ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; | ||
745 | else if (clrprealloc) | ||
746 | ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC; | ||
747 | |||
748 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
749 | if (filp->f_flags & O_DSYNC) | ||
750 | xfs_trans_set_sync(tp); | ||
751 | error = xfs_trans_commit(tp, 0); | ||
752 | 726 | ||
753 | out_unlock: | 727 | out_unlock: |
754 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 728 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c index ec6772866f3d..bfc7c7c8a0c8 100644 --- a/fs/xfs/xfs_ioctl32.c +++ b/fs/xfs/xfs_ioctl32.c | |||
@@ -423,7 +423,7 @@ xfs_compat_attrmulti_by_handle( | |||
423 | 423 | ||
424 | ops = memdup_user(compat_ptr(am_hreq.ops), size); | 424 | ops = memdup_user(compat_ptr(am_hreq.ops), size); |
425 | if (IS_ERR(ops)) { | 425 | if (IS_ERR(ops)) { |
426 | error = -PTR_ERR(ops); | 426 | error = PTR_ERR(ops); |
427 | goto out_dput; | 427 | goto out_dput; |
428 | } | 428 | } |
429 | 429 | ||