diff options
author | David Howells <dhowells@redhat.com> | 2006-08-29 14:05:54 -0400 |
---|---|---|
committer | Jens Axboe <axboe@nelson.home.kernel.dk> | 2006-09-30 14:31:19 -0400 |
commit | cf9a2ae8d49948f861b56e5333530e491a9da190 (patch) | |
tree | 21f0b0d781b3e60cc60464d39b6d95681201b37e | |
parent | 4090959aee403817ff386415f9bc602c1a0882ef (diff) |
[PATCH] BLOCK: Move functions out of buffer code [try #6]
Move some functions out of the buffering code that aren't strictly buffering
specific. This is a precursor to being able to disable the block layer.
(*) Moved some stuff out of fs/buffer.c:
(*) The file sync and general sync stuff moved to fs/sync.c.
(*) The superblock sync stuff moved to fs/super.c.
(*) do_invalidatepage() moved to mm/truncate.c.
(*) try_to_release_page() moved to mm/filemap.c.
(*) Moved some related declarations between header files:
(*) declarations for do_invalidatepage() and try_to_release_page() moved
to linux/mm.h.
(*) __set_page_dirty_buffers() moved to linux/buffer_head.h.
Signed-Off-By: David Howells <dhowells@redhat.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r-- | fs/buffer.c | 174 | ||||
-rw-r--r-- | fs/super.c | 31 | ||||
-rw-r--r-- | fs/sync.c | 113 | ||||
-rw-r--r-- | include/linux/buffer_head.h | 3 | ||||
-rw-r--r-- | include/linux/fs.h | 1 | ||||
-rw-r--r-- | include/linux/mm.h | 4 | ||||
-rw-r--r-- | mm/filemap.c | 30 | ||||
-rw-r--r-- | mm/page-writeback.c | 1 | ||||
-rw-r--r-- | mm/truncate.c | 24 |
9 files changed, 204 insertions, 177 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index 3b6d701073e7..16cfbcd254f1 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -159,31 +159,6 @@ int sync_blockdev(struct block_device *bdev) | |||
159 | } | 159 | } |
160 | EXPORT_SYMBOL(sync_blockdev); | 160 | EXPORT_SYMBOL(sync_blockdev); |
161 | 161 | ||
162 | static void __fsync_super(struct super_block *sb) | ||
163 | { | ||
164 | sync_inodes_sb(sb, 0); | ||
165 | DQUOT_SYNC(sb); | ||
166 | lock_super(sb); | ||
167 | if (sb->s_dirt && sb->s_op->write_super) | ||
168 | sb->s_op->write_super(sb); | ||
169 | unlock_super(sb); | ||
170 | if (sb->s_op->sync_fs) | ||
171 | sb->s_op->sync_fs(sb, 1); | ||
172 | sync_blockdev(sb->s_bdev); | ||
173 | sync_inodes_sb(sb, 1); | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * Write out and wait upon all dirty data associated with this | ||
178 | * superblock. Filesystem data as well as the underlying block | ||
179 | * device. Takes the superblock lock. | ||
180 | */ | ||
181 | int fsync_super(struct super_block *sb) | ||
182 | { | ||
183 | __fsync_super(sb); | ||
184 | return sync_blockdev(sb->s_bdev); | ||
185 | } | ||
186 | |||
187 | /* | 162 | /* |
188 | * Write out and wait upon all dirty data associated with this | 163 | * Write out and wait upon all dirty data associated with this |
189 | * device. Filesystem data as well as the underlying block | 164 | * device. Filesystem data as well as the underlying block |
@@ -260,118 +235,6 @@ void thaw_bdev(struct block_device *bdev, struct super_block *sb) | |||
260 | EXPORT_SYMBOL(thaw_bdev); | 235 | EXPORT_SYMBOL(thaw_bdev); |
261 | 236 | ||
262 | /* | 237 | /* |
263 | * sync everything. Start out by waking pdflush, because that writes back | ||
264 | * all queues in parallel. | ||
265 | */ | ||
266 | static void do_sync(unsigned long wait) | ||
267 | { | ||
268 | wakeup_pdflush(0); | ||
269 | sync_inodes(0); /* All mappings, inodes and their blockdevs */ | ||
270 | DQUOT_SYNC(NULL); | ||
271 | sync_supers(); /* Write the superblocks */ | ||
272 | sync_filesystems(0); /* Start syncing the filesystems */ | ||
273 | sync_filesystems(wait); /* Waitingly sync the filesystems */ | ||
274 | sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */ | ||
275 | if (!wait) | ||
276 | printk("Emergency Sync complete\n"); | ||
277 | if (unlikely(laptop_mode)) | ||
278 | laptop_sync_completion(); | ||
279 | } | ||
280 | |||
281 | asmlinkage long sys_sync(void) | ||
282 | { | ||
283 | do_sync(1); | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | void emergency_sync(void) | ||
288 | { | ||
289 | pdflush_operation(do_sync, 0); | ||
290 | } | ||
291 | |||
292 | /* | ||
293 | * Generic function to fsync a file. | ||
294 | * | ||
295 | * filp may be NULL if called via the msync of a vma. | ||
296 | */ | ||
297 | |||
298 | int file_fsync(struct file *filp, struct dentry *dentry, int datasync) | ||
299 | { | ||
300 | struct inode * inode = dentry->d_inode; | ||
301 | struct super_block * sb; | ||
302 | int ret, err; | ||
303 | |||
304 | /* sync the inode to buffers */ | ||
305 | ret = write_inode_now(inode, 0); | ||
306 | |||
307 | /* sync the superblock to buffers */ | ||
308 | sb = inode->i_sb; | ||
309 | lock_super(sb); | ||
310 | if (sb->s_op->write_super) | ||
311 | sb->s_op->write_super(sb); | ||
312 | unlock_super(sb); | ||
313 | |||
314 | /* .. finally sync the buffers to disk */ | ||
315 | err = sync_blockdev(sb->s_bdev); | ||
316 | if (!ret) | ||
317 | ret = err; | ||
318 | return ret; | ||
319 | } | ||
320 | |||
321 | long do_fsync(struct file *file, int datasync) | ||
322 | { | ||
323 | int ret; | ||
324 | int err; | ||
325 | struct address_space *mapping = file->f_mapping; | ||
326 | |||
327 | if (!file->f_op || !file->f_op->fsync) { | ||
328 | /* Why? We can still call filemap_fdatawrite */ | ||
329 | ret = -EINVAL; | ||
330 | goto out; | ||
331 | } | ||
332 | |||
333 | ret = filemap_fdatawrite(mapping); | ||
334 | |||
335 | /* | ||
336 | * We need to protect against concurrent writers, which could cause | ||
337 | * livelocks in fsync_buffers_list(). | ||
338 | */ | ||
339 | mutex_lock(&mapping->host->i_mutex); | ||
340 | err = file->f_op->fsync(file, file->f_dentry, datasync); | ||
341 | if (!ret) | ||
342 | ret = err; | ||
343 | mutex_unlock(&mapping->host->i_mutex); | ||
344 | err = filemap_fdatawait(mapping); | ||
345 | if (!ret) | ||
346 | ret = err; | ||
347 | out: | ||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | static long __do_fsync(unsigned int fd, int datasync) | ||
352 | { | ||
353 | struct file *file; | ||
354 | int ret = -EBADF; | ||
355 | |||
356 | file = fget(fd); | ||
357 | if (file) { | ||
358 | ret = do_fsync(file, datasync); | ||
359 | fput(file); | ||
360 | } | ||
361 | return ret; | ||
362 | } | ||
363 | |||
364 | asmlinkage long sys_fsync(unsigned int fd) | ||
365 | { | ||
366 | return __do_fsync(fd, 0); | ||
367 | } | ||
368 | |||
369 | asmlinkage long sys_fdatasync(unsigned int fd) | ||
370 | { | ||
371 | return __do_fsync(fd, 1); | ||
372 | } | ||
373 | |||
374 | /* | ||
375 | * Various filesystems appear to want __find_get_block to be non-blocking. | 238 | * Various filesystems appear to want __find_get_block to be non-blocking. |
376 | * But it's the page lock which protects the buffers. To get around this, | 239 | * But it's the page lock which protects the buffers. To get around this, |
377 | * we get exclusion from try_to_free_buffers with the blockdev mapping's | 240 | * we get exclusion from try_to_free_buffers with the blockdev mapping's |
@@ -1551,35 +1414,6 @@ static void discard_buffer(struct buffer_head * bh) | |||
1551 | } | 1414 | } |
1552 | 1415 | ||
1553 | /** | 1416 | /** |
1554 | * try_to_release_page() - release old fs-specific metadata on a page | ||
1555 | * | ||
1556 | * @page: the page which the kernel is trying to free | ||
1557 | * @gfp_mask: memory allocation flags (and I/O mode) | ||
1558 | * | ||
1559 | * The address_space is to try to release any data against the page | ||
1560 | * (presumably at page->private). If the release was successful, return `1'. | ||
1561 | * Otherwise return zero. | ||
1562 | * | ||
1563 | * The @gfp_mask argument specifies whether I/O may be performed to release | ||
1564 | * this page (__GFP_IO), and whether the call may block (__GFP_WAIT). | ||
1565 | * | ||
1566 | * NOTE: @gfp_mask may go away, and this function may become non-blocking. | ||
1567 | */ | ||
1568 | int try_to_release_page(struct page *page, gfp_t gfp_mask) | ||
1569 | { | ||
1570 | struct address_space * const mapping = page->mapping; | ||
1571 | |||
1572 | BUG_ON(!PageLocked(page)); | ||
1573 | if (PageWriteback(page)) | ||
1574 | return 0; | ||
1575 | |||
1576 | if (mapping && mapping->a_ops->releasepage) | ||
1577 | return mapping->a_ops->releasepage(page, gfp_mask); | ||
1578 | return try_to_free_buffers(page); | ||
1579 | } | ||
1580 | EXPORT_SYMBOL(try_to_release_page); | ||
1581 | |||
1582 | /** | ||
1583 | * block_invalidatepage - invalidate part of all of a buffer-backed page | 1417 | * block_invalidatepage - invalidate part of all of a buffer-backed page |
1584 | * | 1418 | * |
1585 | * @page: the page which is affected | 1419 | * @page: the page which is affected |
@@ -1630,14 +1464,6 @@ out: | |||
1630 | } | 1464 | } |
1631 | EXPORT_SYMBOL(block_invalidatepage); | 1465 | EXPORT_SYMBOL(block_invalidatepage); |
1632 | 1466 | ||
1633 | void do_invalidatepage(struct page *page, unsigned long offset) | ||
1634 | { | ||
1635 | void (*invalidatepage)(struct page *, unsigned long); | ||
1636 | invalidatepage = page->mapping->a_ops->invalidatepage ? : | ||
1637 | block_invalidatepage; | ||
1638 | (*invalidatepage)(page, offset); | ||
1639 | } | ||
1640 | |||
1641 | /* | 1467 | /* |
1642 | * We attach and possibly dirty the buffers atomically wrt | 1468 | * We attach and possibly dirty the buffers atomically wrt |
1643 | * __set_page_dirty_buffers() via private_lock. try_to_free_buffers | 1469 | * __set_page_dirty_buffers() via private_lock. try_to_free_buffers |
diff --git a/fs/super.c b/fs/super.c index 6987824d0dce..15671cd048b1 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -220,6 +220,37 @@ static int grab_super(struct super_block *s) __releases(sb_lock) | |||
220 | return 0; | 220 | return 0; |
221 | } | 221 | } |
222 | 222 | ||
223 | /* | ||
224 | * Write out and wait upon all dirty data associated with this | ||
225 | * superblock. Filesystem data as well as the underlying block | ||
226 | * device. Takes the superblock lock. Requires a second blkdev | ||
227 | * flush by the caller to complete the operation. | ||
228 | */ | ||
229 | void __fsync_super(struct super_block *sb) | ||
230 | { | ||
231 | sync_inodes_sb(sb, 0); | ||
232 | DQUOT_SYNC(sb); | ||
233 | lock_super(sb); | ||
234 | if (sb->s_dirt && sb->s_op->write_super) | ||
235 | sb->s_op->write_super(sb); | ||
236 | unlock_super(sb); | ||
237 | if (sb->s_op->sync_fs) | ||
238 | sb->s_op->sync_fs(sb, 1); | ||
239 | sync_blockdev(sb->s_bdev); | ||
240 | sync_inodes_sb(sb, 1); | ||
241 | } | ||
242 | |||
243 | /* | ||
244 | * Write out and wait upon all dirty data associated with this | ||
245 | * superblock. Filesystem data as well as the underlying block | ||
246 | * device. Takes the superblock lock. | ||
247 | */ | ||
248 | int fsync_super(struct super_block *sb) | ||
249 | { | ||
250 | __fsync_super(sb); | ||
251 | return sync_blockdev(sb->s_bdev); | ||
252 | } | ||
253 | |||
223 | /** | 254 | /** |
224 | * generic_shutdown_super - common helper for ->kill_sb() | 255 | * generic_shutdown_super - common helper for ->kill_sb() |
225 | * @sb: superblock to kill | 256 | * @sb: superblock to kill |
@@ -10,11 +10,124 @@ | |||
10 | #include <linux/syscalls.h> | 10 | #include <linux/syscalls.h> |
11 | #include <linux/linkage.h> | 11 | #include <linux/linkage.h> |
12 | #include <linux/pagemap.h> | 12 | #include <linux/pagemap.h> |
13 | #include <linux/quotaops.h> | ||
14 | #include <linux/buffer_head.h> | ||
13 | 15 | ||
14 | #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ | 16 | #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ |
15 | SYNC_FILE_RANGE_WAIT_AFTER) | 17 | SYNC_FILE_RANGE_WAIT_AFTER) |
16 | 18 | ||
17 | /* | 19 | /* |
20 | * sync everything. Start out by waking pdflush, because that writes back | ||
21 | * all queues in parallel. | ||
22 | */ | ||
23 | static void do_sync(unsigned long wait) | ||
24 | { | ||
25 | wakeup_pdflush(0); | ||
26 | sync_inodes(0); /* All mappings, inodes and their blockdevs */ | ||
27 | DQUOT_SYNC(NULL); | ||
28 | sync_supers(); /* Write the superblocks */ | ||
29 | sync_filesystems(0); /* Start syncing the filesystems */ | ||
30 | sync_filesystems(wait); /* Waitingly sync the filesystems */ | ||
31 | sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */ | ||
32 | if (!wait) | ||
33 | printk("Emergency Sync complete\n"); | ||
34 | if (unlikely(laptop_mode)) | ||
35 | laptop_sync_completion(); | ||
36 | } | ||
37 | |||
38 | asmlinkage long sys_sync(void) | ||
39 | { | ||
40 | do_sync(1); | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | void emergency_sync(void) | ||
45 | { | ||
46 | pdflush_operation(do_sync, 0); | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | * Generic function to fsync a file. | ||
51 | * | ||
52 | * filp may be NULL if called via the msync of a vma. | ||
53 | */ | ||
54 | int file_fsync(struct file *filp, struct dentry *dentry, int datasync) | ||
55 | { | ||
56 | struct inode * inode = dentry->d_inode; | ||
57 | struct super_block * sb; | ||
58 | int ret, err; | ||
59 | |||
60 | /* sync the inode to buffers */ | ||
61 | ret = write_inode_now(inode, 0); | ||
62 | |||
63 | /* sync the superblock to buffers */ | ||
64 | sb = inode->i_sb; | ||
65 | lock_super(sb); | ||
66 | if (sb->s_op->write_super) | ||
67 | sb->s_op->write_super(sb); | ||
68 | unlock_super(sb); | ||
69 | |||
70 | /* .. finally sync the buffers to disk */ | ||
71 | err = sync_blockdev(sb->s_bdev); | ||
72 | if (!ret) | ||
73 | ret = err; | ||
74 | return ret; | ||
75 | } | ||
76 | |||
77 | long do_fsync(struct file *file, int datasync) | ||
78 | { | ||
79 | int ret; | ||
80 | int err; | ||
81 | struct address_space *mapping = file->f_mapping; | ||
82 | |||
83 | if (!file->f_op || !file->f_op->fsync) { | ||
84 | /* Why? We can still call filemap_fdatawrite */ | ||
85 | ret = -EINVAL; | ||
86 | goto out; | ||
87 | } | ||
88 | |||
89 | ret = filemap_fdatawrite(mapping); | ||
90 | |||
91 | /* | ||
92 | * We need to protect against concurrent writers, which could cause | ||
93 | * livelocks in fsync_buffers_list(). | ||
94 | */ | ||
95 | mutex_lock(&mapping->host->i_mutex); | ||
96 | err = file->f_op->fsync(file, file->f_dentry, datasync); | ||
97 | if (!ret) | ||
98 | ret = err; | ||
99 | mutex_unlock(&mapping->host->i_mutex); | ||
100 | err = filemap_fdatawait(mapping); | ||
101 | if (!ret) | ||
102 | ret = err; | ||
103 | out: | ||
104 | return ret; | ||
105 | } | ||
106 | |||
107 | static long __do_fsync(unsigned int fd, int datasync) | ||
108 | { | ||
109 | struct file *file; | ||
110 | int ret = -EBADF; | ||
111 | |||
112 | file = fget(fd); | ||
113 | if (file) { | ||
114 | ret = do_fsync(file, datasync); | ||
115 | fput(file); | ||
116 | } | ||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | asmlinkage long sys_fsync(unsigned int fd) | ||
121 | { | ||
122 | return __do_fsync(fd, 0); | ||
123 | } | ||
124 | |||
125 | asmlinkage long sys_fdatasync(unsigned int fd) | ||
126 | { | ||
127 | return __do_fsync(fd, 1); | ||
128 | } | ||
129 | |||
130 | /* | ||
18 | * sys_sync_file_range() permits finely controlled syncing over a segment of | 131 | * sys_sync_file_range() permits finely controlled syncing over a segment of |
19 | * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is | 132 | * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is |
20 | * zero then sys_sync_file_range() will operate from offset out to EOF. | 133 | * zero then sys_sync_file_range() will operate from offset out to EOF. |
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 737e407d0cd1..64b508e35d2a 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h | |||
@@ -190,9 +190,7 @@ extern int buffer_heads_over_limit; | |||
190 | * Generic address_space_operations implementations for buffer_head-backed | 190 | * Generic address_space_operations implementations for buffer_head-backed |
191 | * address_spaces. | 191 | * address_spaces. |
192 | */ | 192 | */ |
193 | int try_to_release_page(struct page * page, gfp_t gfp_mask); | ||
194 | void block_invalidatepage(struct page *page, unsigned long offset); | 193 | void block_invalidatepage(struct page *page, unsigned long offset); |
195 | void do_invalidatepage(struct page *page, unsigned long offset); | ||
196 | int block_write_full_page(struct page *page, get_block_t *get_block, | 194 | int block_write_full_page(struct page *page, get_block_t *get_block, |
197 | struct writeback_control *wbc); | 195 | struct writeback_control *wbc); |
198 | int block_read_full_page(struct page*, get_block_t*); | 196 | int block_read_full_page(struct page*, get_block_t*); |
@@ -302,4 +300,5 @@ static inline void lock_buffer(struct buffer_head *bh) | |||
302 | __lock_buffer(bh); | 300 | __lock_buffer(bh); |
303 | } | 301 | } |
304 | 302 | ||
303 | extern int __set_page_dirty_buffers(struct page *page); | ||
305 | #endif /* _LINUX_BUFFER_HEAD_H */ | 304 | #endif /* _LINUX_BUFFER_HEAD_H */ |
diff --git a/include/linux/fs.h b/include/linux/fs.h index d68c37af4dfb..1728142ec4b6 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1546,6 +1546,7 @@ extern int __filemap_fdatawrite_range(struct address_space *mapping, | |||
1546 | extern long do_fsync(struct file *file, int datasync); | 1546 | extern long do_fsync(struct file *file, int datasync); |
1547 | extern void sync_supers(void); | 1547 | extern void sync_supers(void); |
1548 | extern void sync_filesystems(int wait); | 1548 | extern void sync_filesystems(int wait); |
1549 | extern void __fsync_super(struct super_block *sb); | ||
1549 | extern void emergency_sync(void); | 1550 | extern void emergency_sync(void); |
1550 | extern void emergency_remount(void); | 1551 | extern void emergency_remount(void); |
1551 | extern int do_remount_sb(struct super_block *sb, int flags, | 1552 | extern int do_remount_sb(struct super_block *sb, int flags, |
diff --git a/include/linux/mm.h b/include/linux/mm.h index 7b703b6d4358..4edf1934e5ca 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -743,7 +743,9 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long | |||
743 | int len, int write, int force, struct page **pages, struct vm_area_struct **vmas); | 743 | int len, int write, int force, struct page **pages, struct vm_area_struct **vmas); |
744 | void print_bad_pte(struct vm_area_struct *, pte_t, unsigned long); | 744 | void print_bad_pte(struct vm_area_struct *, pte_t, unsigned long); |
745 | 745 | ||
746 | int __set_page_dirty_buffers(struct page *page); | 746 | extern int try_to_release_page(struct page * page, gfp_t gfp_mask); |
747 | extern void do_invalidatepage(struct page *page, unsigned long offset); | ||
748 | |||
747 | int __set_page_dirty_nobuffers(struct page *page); | 749 | int __set_page_dirty_nobuffers(struct page *page); |
748 | int redirty_page_for_writepage(struct writeback_control *wbc, | 750 | int redirty_page_for_writepage(struct writeback_control *wbc, |
749 | struct page *page); | 751 | struct page *page); |
diff --git a/mm/filemap.c b/mm/filemap.c index 3277f3b23524..d6846de08887 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -2491,3 +2491,33 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
2491 | } | 2491 | } |
2492 | return retval; | 2492 | return retval; |
2493 | } | 2493 | } |
2494 | |||
2495 | /** | ||
2496 | * try_to_release_page() - release old fs-specific metadata on a page | ||
2497 | * | ||
2498 | * @page: the page which the kernel is trying to free | ||
2499 | * @gfp_mask: memory allocation flags (and I/O mode) | ||
2500 | * | ||
2501 | * The address_space is to try to release any data against the page | ||
2502 | * (presumably at page->private). If the release was successful, return `1'. | ||
2503 | * Otherwise return zero. | ||
2504 | * | ||
2505 | * The @gfp_mask argument specifies whether I/O may be performed to release | ||
2506 | * this page (__GFP_IO), and whether the call may block (__GFP_WAIT). | ||
2507 | * | ||
2508 | * NOTE: @gfp_mask may go away, and this function may become non-blocking. | ||
2509 | */ | ||
2510 | int try_to_release_page(struct page *page, gfp_t gfp_mask) | ||
2511 | { | ||
2512 | struct address_space * const mapping = page->mapping; | ||
2513 | |||
2514 | BUG_ON(!PageLocked(page)); | ||
2515 | if (PageWriteback(page)) | ||
2516 | return 0; | ||
2517 | |||
2518 | if (mapping && mapping->a_ops->releasepage) | ||
2519 | return mapping->a_ops->releasepage(page, gfp_mask); | ||
2520 | return try_to_free_buffers(page); | ||
2521 | } | ||
2522 | |||
2523 | EXPORT_SYMBOL(try_to_release_page); | ||
diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 488b7088557c..9fdcc7903956 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/sysctl.h> | 30 | #include <linux/sysctl.h> |
31 | #include <linux/cpu.h> | 31 | #include <linux/cpu.h> |
32 | #include <linux/syscalls.h> | 32 | #include <linux/syscalls.h> |
33 | #include <linux/buffer_head.h> | ||
33 | 34 | ||
34 | /* | 35 | /* |
35 | * The maximum number of pages to writeout in a single bdflush/kupdate | 36 | * The maximum number of pages to writeout in a single bdflush/kupdate |
diff --git a/mm/truncate.c b/mm/truncate.c index a654928323dc..cd3e34b816db 100644 --- a/mm/truncate.c +++ b/mm/truncate.c | |||
@@ -17,6 +17,30 @@ | |||
17 | do_invalidatepage */ | 17 | do_invalidatepage */ |
18 | 18 | ||
19 | 19 | ||
20 | /** | ||
21 | * do_invalidatepage - invalidate part of all of a page | ||
22 | * @page: the page which is affected | ||
23 | * @offset: the index of the truncation point | ||
24 | * | ||
25 | * do_invalidatepage() is called when all or part of the page has become | ||
26 | * invalidated by a truncate operation. | ||
27 | * | ||
28 | * do_invalidatepage() does not have to release all buffers, but it must | ||
29 | * ensure that no dirty buffer is left outside @offset and that no I/O | ||
30 | * is underway against any of the blocks which are outside the truncation | ||
31 | * point. Because the caller is about to free (and possibly reuse) those | ||
32 | * blocks on-disk. | ||
33 | */ | ||
34 | void do_invalidatepage(struct page *page, unsigned long offset) | ||
35 | { | ||
36 | void (*invalidatepage)(struct page *, unsigned long); | ||
37 | invalidatepage = page->mapping->a_ops->invalidatepage; | ||
38 | if (!invalidatepage) | ||
39 | invalidatepage = block_invalidatepage; | ||
40 | if (invalidatepage) | ||
41 | (*invalidatepage)(page, offset); | ||
42 | } | ||
43 | |||
20 | static inline void truncate_partial_page(struct page *page, unsigned partial) | 44 | static inline void truncate_partial_page(struct page *page, unsigned partial) |
21 | { | 45 | { |
22 | memclear_highpage_flush(page, partial, PAGE_CACHE_SIZE-partial); | 46 | memclear_highpage_flush(page, partial, PAGE_CACHE_SIZE-partial); |