diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-08 14:59:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-08 14:59:33 -0400 |
commit | 60c9b2746f589b0b809582b0471cf30ad3ae439f (patch) | |
tree | deb0169acb7f7b5b5ef721650de1e0c6f139823c /fs/xfs/linux-2.6 | |
parent | 4750def52cb2c21732dda9aa1d43a07db37b0186 (diff) | |
parent | f7c66ce3f70d8417de0cfb481ca4e5430382ec5d (diff) |
Merge git://oss.sgi.com:8090/xfs/xfs-2.6
* git://oss.sgi.com:8090/xfs/xfs-2.6:
[XFS] Add lockdep support for XFS
[XFS] Fix race in xfs_write() b/w dmapi callout and direct I/O checks.
[XFS] Get rid of redundant "required" in msg.
[XFS] Export via a function xfs_buftarg_list for use by kdb/xfsidbg.
[XFS] Remove unused ilen variable and references.
[XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
[XFS] Fix race condition in xfs_write().
[XFS] Fix uquota and oquota enforcement problems.
[XFS] propogate return codes from flush routines
[XFS] Fix quotaon syscall failures for group enforcement requests.
[XFS] Invalidate quotacheck when mounting without a quota type.
[XFS] reducing the number of random number functions.
[XFS] remove more misc. unused args
[XFS] the "aendp" arg to xfs_dir2_data_freescan is always NULL, remove it.
[XFS] The last argument "lsn" of xfs_trans_commit() is always called with
Diffstat (limited to 'fs/xfs/linux-2.6')
-rw-r--r-- | fs/xfs/linux-2.6/mrlock.h | 12 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.c | 89 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_buf.c | 10 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_buf.h | 3 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_fs_subr.c | 21 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_fs_subr.h | 2 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_lrw.c | 163 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_vnode.h | 2 |
8 files changed, 212 insertions, 90 deletions
diff --git a/fs/xfs/linux-2.6/mrlock.h b/fs/xfs/linux-2.6/mrlock.h index af168a1a98c1..c110bb002665 100644 --- a/fs/xfs/linux-2.6/mrlock.h +++ b/fs/xfs/linux-2.6/mrlock.h | |||
@@ -43,6 +43,18 @@ static inline void mrupdate(mrlock_t *mrp) | |||
43 | mrp->mr_writer = 1; | 43 | mrp->mr_writer = 1; |
44 | } | 44 | } |
45 | 45 | ||
46 | static inline void mraccess_nested(mrlock_t *mrp, int subclass) | ||
47 | { | ||
48 | down_read_nested(&mrp->mr_lock, subclass); | ||
49 | } | ||
50 | |||
51 | static inline void mrupdate_nested(mrlock_t *mrp, int subclass) | ||
52 | { | ||
53 | down_write_nested(&mrp->mr_lock, subclass); | ||
54 | mrp->mr_writer = 1; | ||
55 | } | ||
56 | |||
57 | |||
46 | static inline int mrtryaccess(mrlock_t *mrp) | 58 | static inline int mrtryaccess(mrlock_t *mrp) |
47 | { | 59 | { |
48 | return down_read_trylock(&mrp->mr_lock); | 60 | return down_read_trylock(&mrp->mr_lock); |
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 143ffc851c9d..4475588e973a 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
@@ -141,9 +141,46 @@ xfs_destroy_ioend( | |||
141 | } | 141 | } |
142 | 142 | ||
143 | /* | 143 | /* |
144 | * Update on-disk file size now that data has been written to disk. | ||
145 | * The current in-memory file size is i_size. If a write is beyond | ||
146 | * eof io_new_size will be the intended file size until i_size is | ||
147 | * updated. If this write does not extend all the way to the valid | ||
148 | * file size then restrict this update to the end of the write. | ||
149 | */ | ||
150 | STATIC void | ||
151 | xfs_setfilesize( | ||
152 | xfs_ioend_t *ioend) | ||
153 | { | ||
154 | xfs_inode_t *ip; | ||
155 | xfs_fsize_t isize; | ||
156 | xfs_fsize_t bsize; | ||
157 | |||
158 | ip = xfs_vtoi(ioend->io_vnode); | ||
159 | |||
160 | ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG); | ||
161 | ASSERT(ioend->io_type != IOMAP_READ); | ||
162 | |||
163 | if (unlikely(ioend->io_error)) | ||
164 | return; | ||
165 | |||
166 | bsize = ioend->io_offset + ioend->io_size; | ||
167 | |||
168 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
169 | |||
170 | isize = MAX(ip->i_size, ip->i_iocore.io_new_size); | ||
171 | isize = MIN(isize, bsize); | ||
172 | |||
173 | if (ip->i_d.di_size < isize) { | ||
174 | ip->i_d.di_size = isize; | ||
175 | ip->i_update_core = 1; | ||
176 | ip->i_update_size = 1; | ||
177 | } | ||
178 | |||
179 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
180 | } | ||
181 | |||
182 | /* | ||
144 | * Buffered IO write completion for delayed allocate extents. | 183 | * Buffered IO write completion for delayed allocate extents. |
145 | * TODO: Update ondisk isize now that we know the file data | ||
146 | * has been flushed (i.e. the notorious "NULL file" problem). | ||
147 | */ | 184 | */ |
148 | STATIC void | 185 | STATIC void |
149 | xfs_end_bio_delalloc( | 186 | xfs_end_bio_delalloc( |
@@ -152,6 +189,7 @@ xfs_end_bio_delalloc( | |||
152 | xfs_ioend_t *ioend = | 189 | xfs_ioend_t *ioend = |
153 | container_of(work, xfs_ioend_t, io_work); | 190 | container_of(work, xfs_ioend_t, io_work); |
154 | 191 | ||
192 | xfs_setfilesize(ioend); | ||
155 | xfs_destroy_ioend(ioend); | 193 | xfs_destroy_ioend(ioend); |
156 | } | 194 | } |
157 | 195 | ||
@@ -165,6 +203,7 @@ xfs_end_bio_written( | |||
165 | xfs_ioend_t *ioend = | 203 | xfs_ioend_t *ioend = |
166 | container_of(work, xfs_ioend_t, io_work); | 204 | container_of(work, xfs_ioend_t, io_work); |
167 | 205 | ||
206 | xfs_setfilesize(ioend); | ||
168 | xfs_destroy_ioend(ioend); | 207 | xfs_destroy_ioend(ioend); |
169 | } | 208 | } |
170 | 209 | ||
@@ -184,8 +223,23 @@ xfs_end_bio_unwritten( | |||
184 | xfs_off_t offset = ioend->io_offset; | 223 | xfs_off_t offset = ioend->io_offset; |
185 | size_t size = ioend->io_size; | 224 | size_t size = ioend->io_size; |
186 | 225 | ||
187 | if (likely(!ioend->io_error)) | 226 | if (likely(!ioend->io_error)) { |
188 | bhv_vop_bmap(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL); | 227 | bhv_vop_bmap(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL); |
228 | xfs_setfilesize(ioend); | ||
229 | } | ||
230 | xfs_destroy_ioend(ioend); | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * IO read completion for regular, written extents. | ||
235 | */ | ||
236 | STATIC void | ||
237 | xfs_end_bio_read( | ||
238 | struct work_struct *work) | ||
239 | { | ||
240 | xfs_ioend_t *ioend = | ||
241 | container_of(work, xfs_ioend_t, io_work); | ||
242 | |||
189 | xfs_destroy_ioend(ioend); | 243 | xfs_destroy_ioend(ioend); |
190 | } | 244 | } |
191 | 245 | ||
@@ -224,6 +278,8 @@ xfs_alloc_ioend( | |||
224 | INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten); | 278 | INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten); |
225 | else if (type == IOMAP_DELAY) | 279 | else if (type == IOMAP_DELAY) |
226 | INIT_WORK(&ioend->io_work, xfs_end_bio_delalloc); | 280 | INIT_WORK(&ioend->io_work, xfs_end_bio_delalloc); |
281 | else if (type == IOMAP_READ) | ||
282 | INIT_WORK(&ioend->io_work, xfs_end_bio_read); | ||
227 | else | 283 | else |
228 | INIT_WORK(&ioend->io_work, xfs_end_bio_written); | 284 | INIT_WORK(&ioend->io_work, xfs_end_bio_written); |
229 | 285 | ||
@@ -913,7 +969,7 @@ xfs_page_state_convert( | |||
913 | bh = head = page_buffers(page); | 969 | bh = head = page_buffers(page); |
914 | offset = page_offset(page); | 970 | offset = page_offset(page); |
915 | flags = -1; | 971 | flags = -1; |
916 | type = 0; | 972 | type = IOMAP_READ; |
917 | 973 | ||
918 | /* TODO: cleanup count and page_dirty */ | 974 | /* TODO: cleanup count and page_dirty */ |
919 | 975 | ||
@@ -999,7 +1055,7 @@ xfs_page_state_convert( | |||
999 | * That means it must already have extents allocated | 1055 | * That means it must already have extents allocated |
1000 | * underneath it. Map the extent by reading it. | 1056 | * underneath it. Map the extent by reading it. |
1001 | */ | 1057 | */ |
1002 | if (!iomap_valid || type != 0) { | 1058 | if (!iomap_valid || type != IOMAP_READ) { |
1003 | flags = BMAPI_READ; | 1059 | flags = BMAPI_READ; |
1004 | size = xfs_probe_cluster(inode, page, bh, | 1060 | size = xfs_probe_cluster(inode, page, bh, |
1005 | head, 1); | 1061 | head, 1); |
@@ -1010,7 +1066,7 @@ xfs_page_state_convert( | |||
1010 | iomap_valid = xfs_iomap_valid(&iomap, offset); | 1066 | iomap_valid = xfs_iomap_valid(&iomap, offset); |
1011 | } | 1067 | } |
1012 | 1068 | ||
1013 | type = 0; | 1069 | type = IOMAP_READ; |
1014 | if (!test_and_set_bit(BH_Lock, &bh->b_state)) { | 1070 | if (!test_and_set_bit(BH_Lock, &bh->b_state)) { |
1015 | ASSERT(buffer_mapped(bh)); | 1071 | ASSERT(buffer_mapped(bh)); |
1016 | if (iomap_valid) | 1072 | if (iomap_valid) |
@@ -1356,12 +1412,21 @@ xfs_end_io_direct( | |||
1356 | * completion handler in the future, in which case all this can | 1412 | * completion handler in the future, in which case all this can |
1357 | * go away. | 1413 | * go away. |
1358 | */ | 1414 | */ |
1359 | if (private && size > 0) { | 1415 | ioend->io_offset = offset; |
1360 | ioend->io_offset = offset; | 1416 | ioend->io_size = size; |
1361 | ioend->io_size = size; | 1417 | if (ioend->io_type == IOMAP_READ) { |
1418 | xfs_finish_ioend(ioend); | ||
1419 | } else if (private && size > 0) { | ||
1362 | xfs_finish_ioend(ioend); | 1420 | xfs_finish_ioend(ioend); |
1363 | } else { | 1421 | } else { |
1364 | xfs_destroy_ioend(ioend); | 1422 | /* |
1423 | * A direct I/O write ioend starts it's life in unwritten | ||
1424 | * state in case they map an unwritten extent. This write | ||
1425 | * didn't map an unwritten extent so switch it's completion | ||
1426 | * handler. | ||
1427 | */ | ||
1428 | INIT_WORK(&ioend->io_work, xfs_end_bio_written); | ||
1429 | xfs_finish_ioend(ioend); | ||
1365 | } | 1430 | } |
1366 | 1431 | ||
1367 | /* | 1432 | /* |
@@ -1392,15 +1457,15 @@ xfs_vm_direct_IO( | |||
1392 | if (error) | 1457 | if (error) |
1393 | return -error; | 1458 | return -error; |
1394 | 1459 | ||
1395 | iocb->private = xfs_alloc_ioend(inode, IOMAP_UNWRITTEN); | ||
1396 | |||
1397 | if (rw == WRITE) { | 1460 | if (rw == WRITE) { |
1461 | iocb->private = xfs_alloc_ioend(inode, IOMAP_UNWRITTEN); | ||
1398 | ret = blockdev_direct_IO_own_locking(rw, iocb, inode, | 1462 | ret = blockdev_direct_IO_own_locking(rw, iocb, inode, |
1399 | iomap.iomap_target->bt_bdev, | 1463 | iomap.iomap_target->bt_bdev, |
1400 | iov, offset, nr_segs, | 1464 | iov, offset, nr_segs, |
1401 | xfs_get_blocks_direct, | 1465 | xfs_get_blocks_direct, |
1402 | xfs_end_io_direct); | 1466 | xfs_end_io_direct); |
1403 | } else { | 1467 | } else { |
1468 | iocb->private = xfs_alloc_ioend(inode, IOMAP_READ); | ||
1404 | ret = blockdev_direct_IO_no_locking(rw, iocb, inode, | 1469 | ret = blockdev_direct_IO_no_locking(rw, iocb, inode, |
1405 | iomap.iomap_target->bt_bdev, | 1470 | iomap.iomap_target->bt_bdev, |
1406 | iov, offset, nr_segs, | 1471 | iov, offset, nr_segs, |
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 69e9e80735d2..fe4f66a5af14 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c | |||
@@ -1426,7 +1426,7 @@ xfs_free_bufhash( | |||
1426 | /* | 1426 | /* |
1427 | * buftarg list for delwrite queue processing | 1427 | * buftarg list for delwrite queue processing |
1428 | */ | 1428 | */ |
1429 | LIST_HEAD(xfs_buftarg_list); | 1429 | static LIST_HEAD(xfs_buftarg_list); |
1430 | static DEFINE_SPINLOCK(xfs_buftarg_lock); | 1430 | static DEFINE_SPINLOCK(xfs_buftarg_lock); |
1431 | 1431 | ||
1432 | STATIC void | 1432 | STATIC void |
@@ -1867,3 +1867,11 @@ xfs_buf_terminate(void) | |||
1867 | ktrace_free(xfs_buf_trace_buf); | 1867 | ktrace_free(xfs_buf_trace_buf); |
1868 | #endif | 1868 | #endif |
1869 | } | 1869 | } |
1870 | |||
1871 | #ifdef CONFIG_KDB_MODULES | ||
1872 | struct list_head * | ||
1873 | xfs_get_buftarg_list(void) | ||
1874 | { | ||
1875 | return &xfs_buftarg_list; | ||
1876 | } | ||
1877 | #endif | ||
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index 9e8ef8fef39f..b6241f6201a5 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h | |||
@@ -411,6 +411,9 @@ extern void xfs_free_buftarg(xfs_buftarg_t *, int); | |||
411 | extern void xfs_wait_buftarg(xfs_buftarg_t *); | 411 | extern void xfs_wait_buftarg(xfs_buftarg_t *); |
412 | extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); | 412 | extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); |
413 | extern int xfs_flush_buftarg(xfs_buftarg_t *, int); | 413 | extern int xfs_flush_buftarg(xfs_buftarg_t *, int); |
414 | #ifdef CONFIG_KDB_MODULES | ||
415 | extern struct list_head *xfs_get_buftarg_list(void); | ||
416 | #endif | ||
414 | 417 | ||
415 | #define xfs_getsize_buftarg(buftarg) block_size((buftarg)->bt_bdev) | 418 | #define xfs_getsize_buftarg(buftarg) block_size((buftarg)->bt_bdev) |
416 | #define xfs_readonly_buftarg(buftarg) bdev_read_only((buftarg)->bt_bdev) | 419 | #define xfs_readonly_buftarg(buftarg) bdev_read_only((buftarg)->bt_bdev) |
diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.c b/fs/xfs/linux-2.6/xfs_fs_subr.c index dc0562828e76..2eb87cd082af 100644 --- a/fs/xfs/linux-2.6/xfs_fs_subr.c +++ b/fs/xfs/linux-2.6/xfs_fs_subr.c | |||
@@ -35,7 +35,7 @@ fs_tosspages( | |||
35 | truncate_inode_pages(ip->i_mapping, first); | 35 | truncate_inode_pages(ip->i_mapping, first); |
36 | } | 36 | } |
37 | 37 | ||
38 | void | 38 | int |
39 | fs_flushinval_pages( | 39 | fs_flushinval_pages( |
40 | bhv_desc_t *bdp, | 40 | bhv_desc_t *bdp, |
41 | xfs_off_t first, | 41 | xfs_off_t first, |
@@ -44,13 +44,16 @@ fs_flushinval_pages( | |||
44 | { | 44 | { |
45 | bhv_vnode_t *vp = BHV_TO_VNODE(bdp); | 45 | bhv_vnode_t *vp = BHV_TO_VNODE(bdp); |
46 | struct inode *ip = vn_to_inode(vp); | 46 | struct inode *ip = vn_to_inode(vp); |
47 | int ret = 0; | ||
47 | 48 | ||
48 | if (VN_CACHED(vp)) { | 49 | if (VN_CACHED(vp)) { |
49 | if (VN_TRUNC(vp)) | 50 | if (VN_TRUNC(vp)) |
50 | VUNTRUNCATE(vp); | 51 | VUNTRUNCATE(vp); |
51 | filemap_write_and_wait(ip->i_mapping); | 52 | ret = filemap_write_and_wait(ip->i_mapping); |
52 | truncate_inode_pages(ip->i_mapping, first); | 53 | if (!ret) |
54 | truncate_inode_pages(ip->i_mapping, first); | ||
53 | } | 55 | } |
56 | return ret; | ||
54 | } | 57 | } |
55 | 58 | ||
56 | int | 59 | int |
@@ -63,14 +66,18 @@ fs_flush_pages( | |||
63 | { | 66 | { |
64 | bhv_vnode_t *vp = BHV_TO_VNODE(bdp); | 67 | bhv_vnode_t *vp = BHV_TO_VNODE(bdp); |
65 | struct inode *ip = vn_to_inode(vp); | 68 | struct inode *ip = vn_to_inode(vp); |
69 | int ret = 0; | ||
70 | int ret2; | ||
66 | 71 | ||
67 | if (VN_DIRTY(vp)) { | 72 | if (VN_DIRTY(vp)) { |
68 | if (VN_TRUNC(vp)) | 73 | if (VN_TRUNC(vp)) |
69 | VUNTRUNCATE(vp); | 74 | VUNTRUNCATE(vp); |
70 | filemap_fdatawrite(ip->i_mapping); | 75 | ret = filemap_fdatawrite(ip->i_mapping); |
71 | if (flags & XFS_B_ASYNC) | 76 | if (flags & XFS_B_ASYNC) |
72 | return 0; | 77 | return ret; |
73 | filemap_fdatawait(ip->i_mapping); | 78 | ret2 = filemap_fdatawait(ip->i_mapping); |
79 | if (!ret) | ||
80 | ret = ret2; | ||
74 | } | 81 | } |
75 | return 0; | 82 | return ret; |
76 | } | 83 | } |
diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.h b/fs/xfs/linux-2.6/xfs_fs_subr.h index aee9ccdd18f7..c1b53118a303 100644 --- a/fs/xfs/linux-2.6/xfs_fs_subr.h +++ b/fs/xfs/linux-2.6/xfs_fs_subr.h | |||
@@ -23,7 +23,7 @@ extern int fs_noerr(void); | |||
23 | extern int fs_nosys(void); | 23 | extern int fs_nosys(void); |
24 | extern void fs_noval(void); | 24 | extern void fs_noval(void); |
25 | extern void fs_tosspages(bhv_desc_t *, xfs_off_t, xfs_off_t, int); | 25 | extern void fs_tosspages(bhv_desc_t *, xfs_off_t, xfs_off_t, int); |
26 | extern void fs_flushinval_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, int); | 26 | extern int fs_flushinval_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, int); |
27 | extern int fs_flush_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, uint64_t, int); | 27 | extern int fs_flush_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, uint64_t, int); |
28 | 28 | ||
29 | #endif /* __XFS_FS_SUBR_H__ */ | 29 | #endif /* __XFS_FS_SUBR_H__ */ |
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 558076dd0752..86fb671a8bcc 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c | |||
@@ -191,7 +191,7 @@ xfs_read( | |||
191 | struct file *file = iocb->ki_filp; | 191 | struct file *file = iocb->ki_filp; |
192 | struct inode *inode = file->f_mapping->host; | 192 | struct inode *inode = file->f_mapping->host; |
193 | size_t size = 0; | 193 | size_t size = 0; |
194 | ssize_t ret; | 194 | ssize_t ret = 0; |
195 | xfs_fsize_t n; | 195 | xfs_fsize_t n; |
196 | xfs_inode_t *ip; | 196 | xfs_inode_t *ip; |
197 | xfs_mount_t *mp; | 197 | xfs_mount_t *mp; |
@@ -224,7 +224,7 @@ xfs_read( | |||
224 | mp->m_rtdev_targp : mp->m_ddev_targp; | 224 | mp->m_rtdev_targp : mp->m_ddev_targp; |
225 | if ((*offset & target->bt_smask) || | 225 | if ((*offset & target->bt_smask) || |
226 | (size & target->bt_smask)) { | 226 | (size & target->bt_smask)) { |
227 | if (*offset == ip->i_d.di_size) { | 227 | if (*offset == ip->i_size) { |
228 | return (0); | 228 | return (0); |
229 | } | 229 | } |
230 | return -XFS_ERROR(EINVAL); | 230 | return -XFS_ERROR(EINVAL); |
@@ -263,9 +263,13 @@ xfs_read( | |||
263 | 263 | ||
264 | if (unlikely(ioflags & IO_ISDIRECT)) { | 264 | if (unlikely(ioflags & IO_ISDIRECT)) { |
265 | if (VN_CACHED(vp)) | 265 | if (VN_CACHED(vp)) |
266 | bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)), | 266 | ret = bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)), |
267 | -1, FI_REMAPF_LOCKED); | 267 | -1, FI_REMAPF_LOCKED); |
268 | mutex_unlock(&inode->i_mutex); | 268 | mutex_unlock(&inode->i_mutex); |
269 | if (ret) { | ||
270 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); | ||
271 | return ret; | ||
272 | } | ||
269 | } | 273 | } |
270 | 274 | ||
271 | xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore, | 275 | xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore, |
@@ -383,9 +387,10 @@ xfs_splice_write( | |||
383 | { | 387 | { |
384 | xfs_inode_t *ip = XFS_BHVTOI(bdp); | 388 | xfs_inode_t *ip = XFS_BHVTOI(bdp); |
385 | xfs_mount_t *mp = ip->i_mount; | 389 | xfs_mount_t *mp = ip->i_mount; |
390 | xfs_iocore_t *io = &ip->i_iocore; | ||
386 | ssize_t ret; | 391 | ssize_t ret; |
387 | struct inode *inode = outfilp->f_mapping->host; | 392 | struct inode *inode = outfilp->f_mapping->host; |
388 | xfs_fsize_t isize; | 393 | xfs_fsize_t isize, new_size; |
389 | 394 | ||
390 | XFS_STATS_INC(xs_write_calls); | 395 | XFS_STATS_INC(xs_write_calls); |
391 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) | 396 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) |
@@ -406,6 +411,14 @@ xfs_splice_write( | |||
406 | return -error; | 411 | return -error; |
407 | } | 412 | } |
408 | } | 413 | } |
414 | |||
415 | new_size = *ppos + count; | ||
416 | |||
417 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
418 | if (new_size > ip->i_size) | ||
419 | io->io_new_size = new_size; | ||
420 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
421 | |||
409 | xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, &ip->i_iocore, | 422 | xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, &ip->i_iocore, |
410 | pipe, count, *ppos, ioflags); | 423 | pipe, count, *ppos, ioflags); |
411 | ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags); | 424 | ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags); |
@@ -416,14 +429,18 @@ xfs_splice_write( | |||
416 | if (unlikely(ret < 0 && ret != -EFAULT && *ppos > isize)) | 429 | if (unlikely(ret < 0 && ret != -EFAULT && *ppos > isize)) |
417 | *ppos = isize; | 430 | *ppos = isize; |
418 | 431 | ||
419 | if (*ppos > ip->i_d.di_size) { | 432 | if (*ppos > ip->i_size) { |
420 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 433 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
421 | if (*ppos > ip->i_d.di_size) { | 434 | if (*ppos > ip->i_size) |
422 | ip->i_d.di_size = *ppos; | 435 | ip->i_size = *ppos; |
423 | i_size_write(inode, *ppos); | 436 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
424 | ip->i_update_core = 1; | 437 | } |
425 | ip->i_update_size = 1; | 438 | |
426 | } | 439 | if (io->io_new_size) { |
440 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
441 | io->io_new_size = 0; | ||
442 | if (ip->i_d.di_size > ip->i_size) | ||
443 | ip->i_d.di_size = ip->i_size; | ||
427 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 444 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
428 | } | 445 | } |
429 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 446 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
@@ -644,7 +661,7 @@ xfs_write( | |||
644 | bhv_vrwlock_t locktype; | 661 | bhv_vrwlock_t locktype; |
645 | size_t ocount = 0, count; | 662 | size_t ocount = 0, count; |
646 | loff_t pos; | 663 | loff_t pos; |
647 | int need_i_mutex = 1, need_flush = 0; | 664 | int need_i_mutex; |
648 | 665 | ||
649 | XFS_STATS_INC(xs_write_calls); | 666 | XFS_STATS_INC(xs_write_calls); |
650 | 667 | ||
@@ -669,39 +686,20 @@ xfs_write( | |||
669 | if (XFS_FORCED_SHUTDOWN(mp)) | 686 | if (XFS_FORCED_SHUTDOWN(mp)) |
670 | return -EIO; | 687 | return -EIO; |
671 | 688 | ||
672 | if (ioflags & IO_ISDIRECT) { | ||
673 | xfs_buftarg_t *target = | ||
674 | (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? | ||
675 | mp->m_rtdev_targp : mp->m_ddev_targp; | ||
676 | |||
677 | if ((pos & target->bt_smask) || (count & target->bt_smask)) | ||
678 | return XFS_ERROR(-EINVAL); | ||
679 | |||
680 | if (!VN_CACHED(vp) && pos < i_size_read(inode)) | ||
681 | need_i_mutex = 0; | ||
682 | |||
683 | if (VN_CACHED(vp)) | ||
684 | need_flush = 1; | ||
685 | } | ||
686 | |||
687 | relock: | 689 | relock: |
688 | if (need_i_mutex) { | 690 | if (ioflags & IO_ISDIRECT) { |
691 | iolock = XFS_IOLOCK_SHARED; | ||
692 | locktype = VRWLOCK_WRITE_DIRECT; | ||
693 | need_i_mutex = 0; | ||
694 | } else { | ||
689 | iolock = XFS_IOLOCK_EXCL; | 695 | iolock = XFS_IOLOCK_EXCL; |
690 | locktype = VRWLOCK_WRITE; | 696 | locktype = VRWLOCK_WRITE; |
691 | 697 | need_i_mutex = 1; | |
692 | mutex_lock(&inode->i_mutex); | 698 | mutex_lock(&inode->i_mutex); |
693 | } else { | ||
694 | iolock = XFS_IOLOCK_SHARED; | ||
695 | locktype = VRWLOCK_WRITE_DIRECT; | ||
696 | } | 699 | } |
697 | 700 | ||
698 | xfs_ilock(xip, XFS_ILOCK_EXCL|iolock); | 701 | xfs_ilock(xip, XFS_ILOCK_EXCL|iolock); |
699 | 702 | ||
700 | isize = i_size_read(inode); | ||
701 | |||
702 | if (file->f_flags & O_APPEND) | ||
703 | *offset = isize; | ||
704 | |||
705 | start: | 703 | start: |
706 | error = -generic_write_checks(file, &pos, &count, | 704 | error = -generic_write_checks(file, &pos, &count, |
707 | S_ISBLK(inode->i_mode)); | 705 | S_ISBLK(inode->i_mode)); |
@@ -710,13 +708,8 @@ start: | |||
710 | goto out_unlock_mutex; | 708 | goto out_unlock_mutex; |
711 | } | 709 | } |
712 | 710 | ||
713 | new_size = pos + count; | ||
714 | if (new_size > isize) | ||
715 | io->io_new_size = new_size; | ||
716 | |||
717 | if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) && | 711 | if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) && |
718 | !(ioflags & IO_INVIS) && !eventsent)) { | 712 | !(ioflags & IO_INVIS) && !eventsent)) { |
719 | loff_t savedsize = pos; | ||
720 | int dmflags = FILP_DELAY_FLAG(file); | 713 | int dmflags = FILP_DELAY_FLAG(file); |
721 | 714 | ||
722 | if (need_i_mutex) | 715 | if (need_i_mutex) |
@@ -727,8 +720,7 @@ start: | |||
727 | pos, count, | 720 | pos, count, |
728 | dmflags, &locktype); | 721 | dmflags, &locktype); |
729 | if (error) { | 722 | if (error) { |
730 | xfs_iunlock(xip, iolock); | 723 | goto out_unlock_internal; |
731 | goto out_unlock_mutex; | ||
732 | } | 724 | } |
733 | xfs_ilock(xip, XFS_ILOCK_EXCL); | 725 | xfs_ilock(xip, XFS_ILOCK_EXCL); |
734 | eventsent = 1; | 726 | eventsent = 1; |
@@ -740,12 +732,35 @@ start: | |||
740 | * event prevents another call to XFS_SEND_DATA, which is | 732 | * event prevents another call to XFS_SEND_DATA, which is |
741 | * what allows the size to change in the first place. | 733 | * what allows the size to change in the first place. |
742 | */ | 734 | */ |
743 | if ((file->f_flags & O_APPEND) && savedsize != isize) { | 735 | if ((file->f_flags & O_APPEND) && pos != xip->i_size) |
744 | pos = isize = xip->i_d.di_size; | 736 | goto start; |
737 | } | ||
738 | |||
739 | if (ioflags & IO_ISDIRECT) { | ||
740 | xfs_buftarg_t *target = | ||
741 | (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? | ||
742 | mp->m_rtdev_targp : mp->m_ddev_targp; | ||
743 | |||
744 | if ((pos & target->bt_smask) || (count & target->bt_smask)) { | ||
745 | xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); | ||
746 | return XFS_ERROR(-EINVAL); | ||
747 | } | ||
748 | |||
749 | if (!need_i_mutex && (VN_CACHED(vp) || pos > xip->i_size)) { | ||
750 | xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); | ||
751 | iolock = XFS_IOLOCK_EXCL; | ||
752 | locktype = VRWLOCK_WRITE; | ||
753 | need_i_mutex = 1; | ||
754 | mutex_lock(&inode->i_mutex); | ||
755 | xfs_ilock(xip, XFS_ILOCK_EXCL|iolock); | ||
745 | goto start; | 756 | goto start; |
746 | } | 757 | } |
747 | } | 758 | } |
748 | 759 | ||
760 | new_size = pos + count; | ||
761 | if (new_size > xip->i_size) | ||
762 | io->io_new_size = new_size; | ||
763 | |||
749 | if (likely(!(ioflags & IO_INVIS))) { | 764 | if (likely(!(ioflags & IO_INVIS))) { |
750 | file_update_time(file); | 765 | file_update_time(file); |
751 | xfs_ichgtime_fast(xip, inode, | 766 | xfs_ichgtime_fast(xip, inode, |
@@ -761,11 +776,11 @@ start: | |||
761 | * to zero it out up to the new size. | 776 | * to zero it out up to the new size. |
762 | */ | 777 | */ |
763 | 778 | ||
764 | if (pos > isize) { | 779 | if (pos > xip->i_size) { |
765 | error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, isize); | 780 | error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, xip->i_size); |
766 | if (error) { | 781 | if (error) { |
767 | xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); | 782 | xfs_iunlock(xip, XFS_ILOCK_EXCL); |
768 | goto out_unlock_mutex; | 783 | goto out_unlock_internal; |
769 | } | 784 | } |
770 | } | 785 | } |
771 | xfs_iunlock(xip, XFS_ILOCK_EXCL); | 786 | xfs_iunlock(xip, XFS_ILOCK_EXCL); |
@@ -785,8 +800,7 @@ start: | |||
785 | if (likely(!error)) | 800 | if (likely(!error)) |
786 | error = -remove_suid(file->f_path.dentry); | 801 | error = -remove_suid(file->f_path.dentry); |
787 | if (unlikely(error)) { | 802 | if (unlikely(error)) { |
788 | xfs_iunlock(xip, iolock); | 803 | goto out_unlock_internal; |
789 | goto out_unlock_mutex; | ||
790 | } | 804 | } |
791 | } | 805 | } |
792 | 806 | ||
@@ -795,11 +809,14 @@ retry: | |||
795 | current->backing_dev_info = mapping->backing_dev_info; | 809 | current->backing_dev_info = mapping->backing_dev_info; |
796 | 810 | ||
797 | if ((ioflags & IO_ISDIRECT)) { | 811 | if ((ioflags & IO_ISDIRECT)) { |
798 | if (need_flush) { | 812 | if (VN_CACHED(vp)) { |
813 | WARN_ON(need_i_mutex == 0); | ||
799 | xfs_inval_cached_trace(io, pos, -1, | 814 | xfs_inval_cached_trace(io, pos, -1, |
800 | ctooff(offtoct(pos)), -1); | 815 | ctooff(offtoct(pos)), -1); |
801 | bhv_vop_flushinval_pages(vp, ctooff(offtoct(pos)), | 816 | error = bhv_vop_flushinval_pages(vp, ctooff(offtoct(pos)), |
802 | -1, FI_REMAPF_LOCKED); | 817 | -1, FI_REMAPF_LOCKED); |
818 | if (error) | ||
819 | goto out_unlock_internal; | ||
803 | } | 820 | } |
804 | 821 | ||
805 | if (need_i_mutex) { | 822 | if (need_i_mutex) { |
@@ -827,7 +844,6 @@ retry: | |||
827 | pos += ret; | 844 | pos += ret; |
828 | count -= ret; | 845 | count -= ret; |
829 | 846 | ||
830 | need_i_mutex = 1; | ||
831 | ioflags &= ~IO_ISDIRECT; | 847 | ioflags &= ~IO_ISDIRECT; |
832 | xfs_iunlock(xip, iolock); | 848 | xfs_iunlock(xip, iolock); |
833 | goto relock; | 849 | goto relock; |
@@ -854,12 +870,12 @@ retry: | |||
854 | error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, vp, | 870 | error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, vp, |
855 | DM_RIGHT_NULL, vp, DM_RIGHT_NULL, NULL, NULL, | 871 | DM_RIGHT_NULL, vp, DM_RIGHT_NULL, NULL, NULL, |
856 | 0, 0, 0); /* Delay flag intentionally unused */ | 872 | 0, 0, 0); /* Delay flag intentionally unused */ |
857 | if (error) | ||
858 | goto out_nounlocks; | ||
859 | if (need_i_mutex) | 873 | if (need_i_mutex) |
860 | mutex_lock(&inode->i_mutex); | 874 | mutex_lock(&inode->i_mutex); |
861 | xfs_rwlock(bdp, locktype); | 875 | xfs_rwlock(bdp, locktype); |
862 | pos = xip->i_d.di_size; | 876 | if (error) |
877 | goto out_unlock_internal; | ||
878 | pos = xip->i_size; | ||
863 | ret = 0; | 879 | ret = 0; |
864 | goto retry; | 880 | goto retry; |
865 | } | 881 | } |
@@ -868,14 +884,10 @@ retry: | |||
868 | if (unlikely(ret < 0 && ret != -EFAULT && *offset > isize)) | 884 | if (unlikely(ret < 0 && ret != -EFAULT && *offset > isize)) |
869 | *offset = isize; | 885 | *offset = isize; |
870 | 886 | ||
871 | if (*offset > xip->i_d.di_size) { | 887 | if (*offset > xip->i_size) { |
872 | xfs_ilock(xip, XFS_ILOCK_EXCL); | 888 | xfs_ilock(xip, XFS_ILOCK_EXCL); |
873 | if (*offset > xip->i_d.di_size) { | 889 | if (*offset > xip->i_size) |
874 | xip->i_d.di_size = *offset; | 890 | xip->i_size = *offset; |
875 | i_size_write(inode, *offset); | ||
876 | xip->i_update_core = 1; | ||
877 | xip->i_update_size = 1; | ||
878 | } | ||
879 | xfs_iunlock(xip, XFS_ILOCK_EXCL); | 891 | xfs_iunlock(xip, XFS_ILOCK_EXCL); |
880 | } | 892 | } |
881 | 893 | ||
@@ -897,16 +909,31 @@ retry: | |||
897 | 909 | ||
898 | error = sync_page_range(inode, mapping, pos, ret); | 910 | error = sync_page_range(inode, mapping, pos, ret); |
899 | if (!error) | 911 | if (!error) |
900 | error = ret; | 912 | error = -ret; |
901 | return error; | 913 | if (need_i_mutex) |
914 | mutex_lock(&inode->i_mutex); | ||
915 | xfs_rwlock(bdp, locktype); | ||
902 | } | 916 | } |
903 | 917 | ||
904 | out_unlock_internal: | 918 | out_unlock_internal: |
919 | if (io->io_new_size) { | ||
920 | xfs_ilock(xip, XFS_ILOCK_EXCL); | ||
921 | io->io_new_size = 0; | ||
922 | /* | ||
923 | * If this was a direct or synchronous I/O that failed (such | ||
924 | * as ENOSPC) then part of the I/O may have been written to | ||
925 | * disk before the error occured. In this case the on-disk | ||
926 | * file size may have been adjusted beyond the in-memory file | ||
927 | * size and now needs to be truncated back. | ||
928 | */ | ||
929 | if (xip->i_d.di_size > xip->i_size) | ||
930 | xip->i_d.di_size = xip->i_size; | ||
931 | xfs_iunlock(xip, XFS_ILOCK_EXCL); | ||
932 | } | ||
905 | xfs_rwunlock(bdp, locktype); | 933 | xfs_rwunlock(bdp, locktype); |
906 | out_unlock_mutex: | 934 | out_unlock_mutex: |
907 | if (need_i_mutex) | 935 | if (need_i_mutex) |
908 | mutex_unlock(&inode->i_mutex); | 936 | mutex_unlock(&inode->i_mutex); |
909 | out_nounlocks: | ||
910 | return -error; | 937 | return -error; |
911 | } | 938 | } |
912 | 939 | ||
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index b76118cf4897..d1b2d01843d1 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h | |||
@@ -194,7 +194,7 @@ typedef int (*vop_attr_list_t)(bhv_desc_t *, char *, int, int, | |||
194 | typedef void (*vop_link_removed_t)(bhv_desc_t *, bhv_vnode_t *, int); | 194 | typedef void (*vop_link_removed_t)(bhv_desc_t *, bhv_vnode_t *, int); |
195 | typedef void (*vop_vnode_change_t)(bhv_desc_t *, bhv_vchange_t, __psint_t); | 195 | typedef void (*vop_vnode_change_t)(bhv_desc_t *, bhv_vchange_t, __psint_t); |
196 | typedef void (*vop_ptossvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); | 196 | typedef void (*vop_ptossvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); |
197 | typedef void (*vop_pflushinvalvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); | 197 | typedef int (*vop_pflushinvalvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); |
198 | typedef int (*vop_pflushvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, | 198 | typedef int (*vop_pflushvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, |
199 | uint64_t, int); | 199 | uint64_t, int); |
200 | typedef int (*vop_iflush_t)(bhv_desc_t *, int); | 200 | typedef int (*vop_iflush_t)(bhv_desc_t *, int); |