diff options
Diffstat (limited to 'fs/logfs/segment.c')
-rw-r--r-- | fs/logfs/segment.c | 70 |
1 files changed, 38 insertions, 32 deletions
diff --git a/fs/logfs/segment.c b/fs/logfs/segment.c index 1a14f9910d55..a9657afb70ad 100644 --- a/fs/logfs/segment.c +++ b/fs/logfs/segment.c | |||
@@ -10,6 +10,7 @@ | |||
10 | * three kinds of objects: inodes, dentries and blocks, both data and indirect. | 10 | * three kinds of objects: inodes, dentries and blocks, both data and indirect. |
11 | */ | 11 | */ |
12 | #include "logfs.h" | 12 | #include "logfs.h" |
13 | #include <linux/slab.h> | ||
13 | 14 | ||
14 | static int logfs_mark_segment_bad(struct super_block *sb, u32 segno) | 15 | static int logfs_mark_segment_bad(struct super_block *sb, u32 segno) |
15 | { | 16 | { |
@@ -66,7 +67,7 @@ static struct page *get_mapping_page(struct super_block *sb, pgoff_t index, | |||
66 | return page; | 67 | return page; |
67 | } | 68 | } |
68 | 69 | ||
69 | void __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, | 70 | int __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, |
70 | int use_filler) | 71 | int use_filler) |
71 | { | 72 | { |
72 | pgoff_t index = ofs >> PAGE_SHIFT; | 73 | pgoff_t index = ofs >> PAGE_SHIFT; |
@@ -80,8 +81,10 @@ void __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, | |||
80 | copylen = min((ulong)len, PAGE_SIZE - offset); | 81 | copylen = min((ulong)len, PAGE_SIZE - offset); |
81 | 82 | ||
82 | page = get_mapping_page(area->a_sb, index, use_filler); | 83 | page = get_mapping_page(area->a_sb, index, use_filler); |
83 | SetPageUptodate(page); | 84 | if (IS_ERR(page)) |
85 | return PTR_ERR(page); | ||
84 | BUG_ON(!page); /* FIXME: reserve a pool */ | 86 | BUG_ON(!page); /* FIXME: reserve a pool */ |
87 | SetPageUptodate(page); | ||
85 | memcpy(page_address(page) + offset, buf, copylen); | 88 | memcpy(page_address(page) + offset, buf, copylen); |
86 | SetPagePrivate(page); | 89 | SetPagePrivate(page); |
87 | page_cache_release(page); | 90 | page_cache_release(page); |
@@ -91,52 +94,61 @@ void __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, | |||
91 | offset = 0; | 94 | offset = 0; |
92 | index++; | 95 | index++; |
93 | } while (len); | 96 | } while (len); |
97 | return 0; | ||
94 | } | 98 | } |
95 | 99 | ||
96 | /* | 100 | static void pad_partial_page(struct logfs_area *area) |
97 | * bdev_writeseg will write full pages. Memset the tail to prevent data leaks. | ||
98 | */ | ||
99 | static void pad_wbuf(struct logfs_area *area, int final) | ||
100 | { | 101 | { |
101 | struct super_block *sb = area->a_sb; | 102 | struct super_block *sb = area->a_sb; |
102 | struct logfs_super *super = logfs_super(sb); | ||
103 | struct page *page; | 103 | struct page *page; |
104 | u64 ofs = dev_ofs(sb, area->a_segno, area->a_used_bytes); | 104 | u64 ofs = dev_ofs(sb, area->a_segno, area->a_used_bytes); |
105 | pgoff_t index = ofs >> PAGE_SHIFT; | 105 | pgoff_t index = ofs >> PAGE_SHIFT; |
106 | long offset = ofs & (PAGE_SIZE-1); | 106 | long offset = ofs & (PAGE_SIZE-1); |
107 | u32 len = PAGE_SIZE - offset; | 107 | u32 len = PAGE_SIZE - offset; |
108 | 108 | ||
109 | if (len == PAGE_SIZE) { | 109 | if (len % PAGE_SIZE) { |
110 | /* The math in this function can surely use some love */ | 110 | page = get_mapping_page(sb, index, 0); |
111 | len = 0; | ||
112 | } | ||
113 | if (len) { | ||
114 | BUG_ON(area->a_used_bytes >= super->s_segsize); | ||
115 | |||
116 | page = get_mapping_page(area->a_sb, index, 0); | ||
117 | BUG_ON(!page); /* FIXME: reserve a pool */ | 111 | BUG_ON(!page); /* FIXME: reserve a pool */ |
118 | memset(page_address(page) + offset, 0xff, len); | 112 | memset(page_address(page) + offset, 0xff, len); |
119 | SetPagePrivate(page); | 113 | SetPagePrivate(page); |
120 | page_cache_release(page); | 114 | page_cache_release(page); |
121 | } | 115 | } |
116 | } | ||
122 | 117 | ||
123 | if (!final) | 118 | static void pad_full_pages(struct logfs_area *area) |
124 | return; | 119 | { |
120 | struct super_block *sb = area->a_sb; | ||
121 | struct logfs_super *super = logfs_super(sb); | ||
122 | u64 ofs = dev_ofs(sb, area->a_segno, area->a_used_bytes); | ||
123 | u32 len = super->s_segsize - area->a_used_bytes; | ||
124 | pgoff_t index = PAGE_CACHE_ALIGN(ofs) >> PAGE_CACHE_SHIFT; | ||
125 | pgoff_t no_indizes = len >> PAGE_CACHE_SHIFT; | ||
126 | struct page *page; | ||
125 | 127 | ||
126 | area->a_used_bytes += len; | 128 | while (no_indizes) { |
127 | for ( ; area->a_used_bytes < super->s_segsize; | 129 | page = get_mapping_page(sb, index, 0); |
128 | area->a_used_bytes += PAGE_SIZE) { | ||
129 | /* Memset another page */ | ||
130 | index++; | ||
131 | page = get_mapping_page(area->a_sb, index, 0); | ||
132 | BUG_ON(!page); /* FIXME: reserve a pool */ | 130 | BUG_ON(!page); /* FIXME: reserve a pool */ |
133 | memset(page_address(page), 0xff, PAGE_SIZE); | 131 | SetPageUptodate(page); |
132 | memset(page_address(page), 0xff, PAGE_CACHE_SIZE); | ||
134 | SetPagePrivate(page); | 133 | SetPagePrivate(page); |
135 | page_cache_release(page); | 134 | page_cache_release(page); |
135 | index++; | ||
136 | no_indizes--; | ||
136 | } | 137 | } |
137 | } | 138 | } |
138 | 139 | ||
139 | /* | 140 | /* |
141 | * bdev_writeseg will write full pages. Memset the tail to prevent data leaks. | ||
142 | * Also make sure we allocate (and memset) all pages for final writeout. | ||
143 | */ | ||
144 | static void pad_wbuf(struct logfs_area *area, int final) | ||
145 | { | ||
146 | pad_partial_page(area); | ||
147 | if (final) | ||
148 | pad_full_pages(area); | ||
149 | } | ||
150 | |||
151 | /* | ||
140 | * We have to be careful with the alias tree. Since lookup is done by bix, | 152 | * We have to be careful with the alias tree. Since lookup is done by bix, |
141 | * it needs to be normalized, so 14, 15, 16, etc. all match when dealing with | 153 | * it needs to be normalized, so 14, 15, 16, etc. all match when dealing with |
142 | * indirect blocks. So always use it through accessor functions. | 154 | * indirect blocks. So always use it through accessor functions. |
@@ -174,14 +186,8 @@ static int btree_write_alias(struct super_block *sb, struct logfs_block *block, | |||
174 | return 0; | 186 | return 0; |
175 | } | 187 | } |
176 | 188 | ||
177 | static gc_level_t btree_block_level(struct logfs_block *block) | ||
178 | { | ||
179 | return expand_level(block->ino, block->level); | ||
180 | } | ||
181 | |||
182 | static struct logfs_block_ops btree_block_ops = { | 189 | static struct logfs_block_ops btree_block_ops = { |
183 | .write_block = btree_write_block, | 190 | .write_block = btree_write_block, |
184 | .block_level = btree_block_level, | ||
185 | .free_block = __free_block, | 191 | .free_block = __free_block, |
186 | .write_alias = btree_write_alias, | 192 | .write_alias = btree_write_alias, |
187 | }; | 193 | }; |
@@ -683,7 +689,7 @@ int logfs_segment_delete(struct inode *inode, struct logfs_shadow *shadow) | |||
683 | return 0; | 689 | return 0; |
684 | } | 690 | } |
685 | 691 | ||
686 | static void freeseg(struct super_block *sb, u32 segno) | 692 | void freeseg(struct super_block *sb, u32 segno) |
687 | { | 693 | { |
688 | struct logfs_super *super = logfs_super(sb); | 694 | struct logfs_super *super = logfs_super(sb); |
689 | struct address_space *mapping = super->s_mapping_inode->i_mapping; | 695 | struct address_space *mapping = super->s_mapping_inode->i_mapping; |
@@ -910,7 +916,7 @@ err: | |||
910 | for (i--; i >= 0; i--) | 916 | for (i--; i >= 0; i--) |
911 | free_area(super->s_area[i]); | 917 | free_area(super->s_area[i]); |
912 | free_area(super->s_journal_area); | 918 | free_area(super->s_journal_area); |
913 | mempool_destroy(super->s_alias_pool); | 919 | logfs_mempool_destroy(super->s_alias_pool); |
914 | return -ENOMEM; | 920 | return -ENOMEM; |
915 | } | 921 | } |
916 | 922 | ||