aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/Locking13
-rw-r--r--Documentation/filesystems/vfs.txt12
-rw-r--r--include/linux/fs.h4
-rw-r--r--include/linux/swap.h2
-rw-r--r--mm/page_io.c52
-rw-r--r--mm/swap_state.c2
-rw-r--r--mm/swapfile.c23
7 files changed, 105 insertions, 3 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index e0cce2a5f820..2db1900d7538 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -206,6 +206,8 @@ prototypes:
206 int (*launder_page)(struct page *); 206 int (*launder_page)(struct page *);
207 int (*is_partially_uptodate)(struct page *, read_descriptor_t *, unsigned long); 207 int (*is_partially_uptodate)(struct page *, read_descriptor_t *, unsigned long);
208 int (*error_remove_page)(struct address_space *, struct page *); 208 int (*error_remove_page)(struct address_space *, struct page *);
209 int (*swap_activate)(struct file *);
210 int (*swap_deactivate)(struct file *);
209 211
210locking rules: 212locking rules:
211 All except set_page_dirty and freepage may block 213 All except set_page_dirty and freepage may block
@@ -229,6 +231,8 @@ migratepage: yes (both)
229launder_page: yes 231launder_page: yes
230is_partially_uptodate: yes 232is_partially_uptodate: yes
231error_remove_page: yes 233error_remove_page: yes
234swap_activate: no
235swap_deactivate: no
232 236
233 ->write_begin(), ->write_end(), ->sync_page() and ->readpage() 237 ->write_begin(), ->write_end(), ->sync_page() and ->readpage()
234may be called from the request handler (/dev/loop). 238may be called from the request handler (/dev/loop).
@@ -330,6 +334,15 @@ cleaned, or an error value if not. Note that in order to prevent the page
330getting mapped back in and redirtied, it needs to be kept locked 334getting mapped back in and redirtied, it needs to be kept locked
331across the entire operation. 335across the entire operation.
332 336
337 ->swap_activate will be called with a non-zero argument on
338files backing (non block device backed) swapfiles. A return value
339of zero indicates success, in which case this file can be used for
340backing swapspace. The swapspace operations will be proxied to the
341address space operations.
342
343 ->swap_deactivate() will be called in the sys_swapoff()
344path after ->swap_activate() returned success.
345
333----------------------- file_lock_operations ------------------------------ 346----------------------- file_lock_operations ------------------------------
334prototypes: 347prototypes:
335 void (*fl_copy_lock)(struct file_lock *, struct file_lock *); 348 void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index aa754e01464e..065aa2dc0835 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -592,6 +592,8 @@ struct address_space_operations {
592 int (*migratepage) (struct page *, struct page *); 592 int (*migratepage) (struct page *, struct page *);
593 int (*launder_page) (struct page *); 593 int (*launder_page) (struct page *);
594 int (*error_remove_page) (struct mapping *mapping, struct page *page); 594 int (*error_remove_page) (struct mapping *mapping, struct page *page);
595 int (*swap_activate)(struct file *);
596 int (*swap_deactivate)(struct file *);
595}; 597};
596 598
597 writepage: called by the VM to write a dirty page to backing store. 599 writepage: called by the VM to write a dirty page to backing store.
@@ -760,6 +762,16 @@ struct address_space_operations {
760 Setting this implies you deal with pages going away under you, 762 Setting this implies you deal with pages going away under you,
761 unless you have them locked or reference counts increased. 763 unless you have them locked or reference counts increased.
762 764
765 swap_activate: Called when swapon is used on a file to allocate
766 space if necessary and pin the block lookup information in
767 memory. A return value of zero indicates success,
768 in which case this file can be used to back swapspace. The
769 swapspace operations will be proxied to this address space's
770 ->swap_{out,in} methods.
771
772 swap_deactivate: Called during swapoff on files where swap_activate
773 was successful.
774
763 775
764The File Object 776The File Object
765=============== 777===============
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 9d77309da153..38356ab827c9 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -638,6 +638,10 @@ struct address_space_operations {
638 int (*is_partially_uptodate) (struct page *, read_descriptor_t *, 638 int (*is_partially_uptodate) (struct page *, read_descriptor_t *,
639 unsigned long); 639 unsigned long);
640 int (*error_remove_page)(struct address_space *, struct page *); 640 int (*error_remove_page)(struct address_space *, struct page *);
641
642 /* swapfile support */
643 int (*swap_activate)(struct file *file);
644 int (*swap_deactivate)(struct file *file);
641}; 645};
642 646
643extern const struct address_space_operations empty_aops; 647extern const struct address_space_operations empty_aops;
diff --git a/include/linux/swap.h b/include/linux/swap.h
index e62425ded2ed..ab230b1ebf61 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -151,6 +151,7 @@ enum {
151 SWP_SOLIDSTATE = (1 << 4), /* blkdev seeks are cheap */ 151 SWP_SOLIDSTATE = (1 << 4), /* blkdev seeks are cheap */
152 SWP_CONTINUED = (1 << 5), /* swap_map has count continuation */ 152 SWP_CONTINUED = (1 << 5), /* swap_map has count continuation */
153 SWP_BLKDEV = (1 << 6), /* its a block device */ 153 SWP_BLKDEV = (1 << 6), /* its a block device */
154 SWP_FILE = (1 << 7), /* set after swap_activate success */
154 /* add others here before... */ 155 /* add others here before... */
155 SWP_SCANNING = (1 << 8), /* refcount in scan_swap_map */ 156 SWP_SCANNING = (1 << 8), /* refcount in scan_swap_map */
156}; 157};
@@ -320,6 +321,7 @@ static inline void mem_cgroup_uncharge_swap(swp_entry_t ent)
320/* linux/mm/page_io.c */ 321/* linux/mm/page_io.c */
321extern int swap_readpage(struct page *); 322extern int swap_readpage(struct page *);
322extern int swap_writepage(struct page *page, struct writeback_control *wbc); 323extern int swap_writepage(struct page *page, struct writeback_control *wbc);
324extern int swap_set_page_dirty(struct page *page);
323extern void end_swap_bio_read(struct bio *bio, int err); 325extern void end_swap_bio_read(struct bio *bio, int err);
324 326
325/* linux/mm/swap_state.c */ 327/* linux/mm/swap_state.c */
diff --git a/mm/page_io.c b/mm/page_io.c
index 34f02923744c..307a3e795290 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -17,6 +17,7 @@
17#include <linux/swap.h> 17#include <linux/swap.h>
18#include <linux/bio.h> 18#include <linux/bio.h>
19#include <linux/swapops.h> 19#include <linux/swapops.h>
20#include <linux/buffer_head.h>
20#include <linux/writeback.h> 21#include <linux/writeback.h>
21#include <linux/frontswap.h> 22#include <linux/frontswap.h>
22#include <asm/pgtable.h> 23#include <asm/pgtable.h>
@@ -94,6 +95,7 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
94{ 95{
95 struct bio *bio; 96 struct bio *bio;
96 int ret = 0, rw = WRITE; 97 int ret = 0, rw = WRITE;
98 struct swap_info_struct *sis = page_swap_info(page);
97 99
98 if (try_to_free_swap(page)) { 100 if (try_to_free_swap(page)) {
99 unlock_page(page); 101 unlock_page(page);
@@ -105,6 +107,32 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
105 end_page_writeback(page); 107 end_page_writeback(page);
106 goto out; 108 goto out;
107 } 109 }
110
111 if (sis->flags & SWP_FILE) {
112 struct kiocb kiocb;
113 struct file *swap_file = sis->swap_file;
114 struct address_space *mapping = swap_file->f_mapping;
115 struct iovec iov = {
116 .iov_base = page_address(page),
117 .iov_len = PAGE_SIZE,
118 };
119
120 init_sync_kiocb(&kiocb, swap_file);
121 kiocb.ki_pos = page_file_offset(page);
122 kiocb.ki_left = PAGE_SIZE;
123 kiocb.ki_nbytes = PAGE_SIZE;
124
125 unlock_page(page);
126 ret = mapping->a_ops->direct_IO(KERNEL_WRITE,
127 &kiocb, &iov,
128 kiocb.ki_pos, 1);
129 if (ret == PAGE_SIZE) {
130 count_vm_event(PSWPOUT);
131 ret = 0;
132 }
133 return ret;
134 }
135
108 bio = get_swap_bio(GFP_NOIO, page, end_swap_bio_write); 136 bio = get_swap_bio(GFP_NOIO, page, end_swap_bio_write);
109 if (bio == NULL) { 137 if (bio == NULL) {
110 set_page_dirty(page); 138 set_page_dirty(page);
@@ -126,6 +154,7 @@ int swap_readpage(struct page *page)
126{ 154{
127 struct bio *bio; 155 struct bio *bio;
128 int ret = 0; 156 int ret = 0;
157 struct swap_info_struct *sis = page_swap_info(page);
129 158
130 VM_BUG_ON(!PageLocked(page)); 159 VM_BUG_ON(!PageLocked(page));
131 VM_BUG_ON(PageUptodate(page)); 160 VM_BUG_ON(PageUptodate(page));
@@ -134,6 +163,17 @@ int swap_readpage(struct page *page)
134 unlock_page(page); 163 unlock_page(page);
135 goto out; 164 goto out;
136 } 165 }
166
167 if (sis->flags & SWP_FILE) {
168 struct file *swap_file = sis->swap_file;
169 struct address_space *mapping = swap_file->f_mapping;
170
171 ret = mapping->a_ops->readpage(swap_file, page);
172 if (!ret)
173 count_vm_event(PSWPIN);
174 return ret;
175 }
176
137 bio = get_swap_bio(GFP_KERNEL, page, end_swap_bio_read); 177 bio = get_swap_bio(GFP_KERNEL, page, end_swap_bio_read);
138 if (bio == NULL) { 178 if (bio == NULL) {
139 unlock_page(page); 179 unlock_page(page);
@@ -145,3 +185,15 @@ int swap_readpage(struct page *page)
145out: 185out:
146 return ret; 186 return ret;
147} 187}
188
189int swap_set_page_dirty(struct page *page)
190{
191 struct swap_info_struct *sis = page_swap_info(page);
192
193 if (sis->flags & SWP_FILE) {
194 struct address_space *mapping = sis->swap_file->f_mapping;
195 return mapping->a_ops->set_page_dirty(page);
196 } else {
197 return __set_page_dirty_no_writeback(page);
198 }
199}
diff --git a/mm/swap_state.c b/mm/swap_state.c
index c85b5590cccd..0cb36fb1f61c 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -27,7 +27,7 @@
27 */ 27 */
28static const struct address_space_operations swap_aops = { 28static const struct address_space_operations swap_aops = {
29 .writepage = swap_writepage, 29 .writepage = swap_writepage,
30 .set_page_dirty = __set_page_dirty_no_writeback, 30 .set_page_dirty = swap_set_page_dirty,
31 .migratepage = migrate_page, 31 .migratepage = migrate_page,
32}; 32};
33 33
diff --git a/mm/swapfile.c b/mm/swapfile.c
index f89af5ba2eb2..6ffc87602f4a 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1329,6 +1329,14 @@ static void destroy_swap_extents(struct swap_info_struct *sis)
1329 list_del(&se->list); 1329 list_del(&se->list);
1330 kfree(se); 1330 kfree(se);
1331 } 1331 }
1332
1333 if (sis->flags & SWP_FILE) {
1334 struct file *swap_file = sis->swap_file;
1335 struct address_space *mapping = swap_file->f_mapping;
1336
1337 sis->flags &= ~SWP_FILE;
1338 mapping->a_ops->swap_deactivate(swap_file);
1339 }
1332} 1340}
1333 1341
1334/* 1342/*
@@ -1410,7 +1418,9 @@ add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
1410 */ 1418 */
1411static int setup_swap_extents(struct swap_info_struct *sis, sector_t *span) 1419static int setup_swap_extents(struct swap_info_struct *sis, sector_t *span)
1412{ 1420{
1413 struct inode *inode; 1421 struct file *swap_file = sis->swap_file;
1422 struct address_space *mapping = swap_file->f_mapping;
1423 struct inode *inode = mapping->host;
1414 unsigned blocks_per_page; 1424 unsigned blocks_per_page;
1415 unsigned long page_no; 1425 unsigned long page_no;
1416 unsigned blkbits; 1426 unsigned blkbits;
@@ -1421,13 +1431,22 @@ static int setup_swap_extents(struct swap_info_struct *sis, sector_t *span)
1421 int nr_extents = 0; 1431 int nr_extents = 0;
1422 int ret; 1432 int ret;
1423 1433
1424 inode = sis->swap_file->f_mapping->host;
1425 if (S_ISBLK(inode->i_mode)) { 1434 if (S_ISBLK(inode->i_mode)) {
1426 ret = add_swap_extent(sis, 0, sis->max, 0); 1435 ret = add_swap_extent(sis, 0, sis->max, 0);
1427 *span = sis->pages; 1436 *span = sis->pages;
1428 goto out; 1437 goto out;
1429 } 1438 }
1430 1439
1440 if (mapping->a_ops->swap_activate) {
1441 ret = mapping->a_ops->swap_activate(swap_file);
1442 if (!ret) {
1443 sis->flags |= SWP_FILE;
1444 ret = add_swap_extent(sis, 0, sis->max, 0);
1445 *span = sis->pages;
1446 }
1447 goto out;
1448 }
1449
1431 blkbits = inode->i_blkbits; 1450 blkbits = inode->i_blkbits;
1432 blocks_per_page = PAGE_SIZE >> blkbits; 1451 blocks_per_page = PAGE_SIZE >> blkbits;
1433 1452