Commit 9421502b4fc894cc477be8fc49776830e37ca157
1 parent
5c564c2a04
Exists in
master
and in
7 other branches
[LogFS] Fix bdev erases
Erases for block devices were always just emulated by writing 0xff. Some time back the write was removed and only the page cache was changed to 0xff. Superficialy a good idea with two problems: 1. Touching the page cache isn't necessary either. 2. However, writing out 0xff _is_ necessary for the journal. As the journal is scanned linearly, an old non-overwritten commit entry can be used on next mount and cause havoc. This should fix both aspects.
Showing 6 changed files with 97 additions and 20 deletions Inline Diff
fs/logfs/dev_bdev.c
1 | /* | 1 | /* |
2 | * fs/logfs/dev_bdev.c - Device access methods for block devices | 2 | * fs/logfs/dev_bdev.c - Device access methods for block devices |
3 | * | 3 | * |
4 | * As should be obvious for Linux kernel code, license is GPLv2 | 4 | * As should be obvious for Linux kernel code, license is GPLv2 |
5 | * | 5 | * |
6 | * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org> | 6 | * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org> |
7 | */ | 7 | */ |
8 | #include "logfs.h" | 8 | #include "logfs.h" |
9 | #include <linux/bio.h> | 9 | #include <linux/bio.h> |
10 | #include <linux/blkdev.h> | 10 | #include <linux/blkdev.h> |
11 | #include <linux/buffer_head.h> | 11 | #include <linux/buffer_head.h> |
12 | 12 | ||
13 | #define PAGE_OFS(ofs) ((ofs) & (PAGE_SIZE-1)) | 13 | #define PAGE_OFS(ofs) ((ofs) & (PAGE_SIZE-1)) |
14 | 14 | ||
15 | static void request_complete(struct bio *bio, int err) | 15 | static void request_complete(struct bio *bio, int err) |
16 | { | 16 | { |
17 | complete((struct completion *)bio->bi_private); | 17 | complete((struct completion *)bio->bi_private); |
18 | } | 18 | } |
19 | 19 | ||
20 | static int sync_request(struct page *page, struct block_device *bdev, int rw) | 20 | static int sync_request(struct page *page, struct block_device *bdev, int rw) |
21 | { | 21 | { |
22 | struct bio bio; | 22 | struct bio bio; |
23 | struct bio_vec bio_vec; | 23 | struct bio_vec bio_vec; |
24 | struct completion complete; | 24 | struct completion complete; |
25 | 25 | ||
26 | bio_init(&bio); | 26 | bio_init(&bio); |
27 | bio.bi_io_vec = &bio_vec; | 27 | bio.bi_io_vec = &bio_vec; |
28 | bio_vec.bv_page = page; | 28 | bio_vec.bv_page = page; |
29 | bio_vec.bv_len = PAGE_SIZE; | 29 | bio_vec.bv_len = PAGE_SIZE; |
30 | bio_vec.bv_offset = 0; | 30 | bio_vec.bv_offset = 0; |
31 | bio.bi_vcnt = 1; | 31 | bio.bi_vcnt = 1; |
32 | bio.bi_idx = 0; | 32 | bio.bi_idx = 0; |
33 | bio.bi_size = PAGE_SIZE; | 33 | bio.bi_size = PAGE_SIZE; |
34 | bio.bi_bdev = bdev; | 34 | bio.bi_bdev = bdev; |
35 | bio.bi_sector = page->index * (PAGE_SIZE >> 9); | 35 | bio.bi_sector = page->index * (PAGE_SIZE >> 9); |
36 | init_completion(&complete); | 36 | init_completion(&complete); |
37 | bio.bi_private = &complete; | 37 | bio.bi_private = &complete; |
38 | bio.bi_end_io = request_complete; | 38 | bio.bi_end_io = request_complete; |
39 | 39 | ||
40 | submit_bio(rw, &bio); | 40 | submit_bio(rw, &bio); |
41 | generic_unplug_device(bdev_get_queue(bdev)); | 41 | generic_unplug_device(bdev_get_queue(bdev)); |
42 | wait_for_completion(&complete); | 42 | wait_for_completion(&complete); |
43 | return test_bit(BIO_UPTODATE, &bio.bi_flags) ? 0 : -EIO; | 43 | return test_bit(BIO_UPTODATE, &bio.bi_flags) ? 0 : -EIO; |
44 | } | 44 | } |
45 | 45 | ||
46 | static int bdev_readpage(void *_sb, struct page *page) | 46 | static int bdev_readpage(void *_sb, struct page *page) |
47 | { | 47 | { |
48 | struct super_block *sb = _sb; | 48 | struct super_block *sb = _sb; |
49 | struct block_device *bdev = logfs_super(sb)->s_bdev; | 49 | struct block_device *bdev = logfs_super(sb)->s_bdev; |
50 | int err; | 50 | int err; |
51 | 51 | ||
52 | err = sync_request(page, bdev, READ); | 52 | err = sync_request(page, bdev, READ); |
53 | if (err) { | 53 | if (err) { |
54 | ClearPageUptodate(page); | 54 | ClearPageUptodate(page); |
55 | SetPageError(page); | 55 | SetPageError(page); |
56 | } else { | 56 | } else { |
57 | SetPageUptodate(page); | 57 | SetPageUptodate(page); |
58 | ClearPageError(page); | 58 | ClearPageError(page); |
59 | } | 59 | } |
60 | unlock_page(page); | 60 | unlock_page(page); |
61 | return err; | 61 | return err; |
62 | } | 62 | } |
63 | 63 | ||
64 | static DECLARE_WAIT_QUEUE_HEAD(wq); | 64 | static DECLARE_WAIT_QUEUE_HEAD(wq); |
65 | 65 | ||
66 | static void writeseg_end_io(struct bio *bio, int err) | 66 | static void writeseg_end_io(struct bio *bio, int err) |
67 | { | 67 | { |
68 | const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); | 68 | const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); |
69 | struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; | 69 | struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; |
70 | struct super_block *sb = bio->bi_private; | 70 | struct super_block *sb = bio->bi_private; |
71 | struct logfs_super *super = logfs_super(sb); | 71 | struct logfs_super *super = logfs_super(sb); |
72 | struct page *page; | 72 | struct page *page; |
73 | 73 | ||
74 | BUG_ON(!uptodate); /* FIXME: Retry io or write elsewhere */ | 74 | BUG_ON(!uptodate); /* FIXME: Retry io or write elsewhere */ |
75 | BUG_ON(err); | 75 | BUG_ON(err); |
76 | BUG_ON(bio->bi_vcnt == 0); | 76 | BUG_ON(bio->bi_vcnt == 0); |
77 | do { | 77 | do { |
78 | page = bvec->bv_page; | 78 | page = bvec->bv_page; |
79 | if (--bvec >= bio->bi_io_vec) | 79 | if (--bvec >= bio->bi_io_vec) |
80 | prefetchw(&bvec->bv_page->flags); | 80 | prefetchw(&bvec->bv_page->flags); |
81 | 81 | ||
82 | end_page_writeback(page); | 82 | end_page_writeback(page); |
83 | } while (bvec >= bio->bi_io_vec); | 83 | } while (bvec >= bio->bi_io_vec); |
84 | bio_put(bio); | 84 | bio_put(bio); |
85 | if (atomic_dec_and_test(&super->s_pending_writes)) | 85 | if (atomic_dec_and_test(&super->s_pending_writes)) |
86 | wake_up(&wq); | 86 | wake_up(&wq); |
87 | } | 87 | } |
88 | 88 | ||
89 | static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, | 89 | static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, |
90 | size_t nr_pages) | 90 | size_t nr_pages) |
91 | { | 91 | { |
92 | struct logfs_super *super = logfs_super(sb); | 92 | struct logfs_super *super = logfs_super(sb); |
93 | struct address_space *mapping = super->s_mapping_inode->i_mapping; | 93 | struct address_space *mapping = super->s_mapping_inode->i_mapping; |
94 | struct bio *bio; | 94 | struct bio *bio; |
95 | struct page *page; | 95 | struct page *page; |
96 | struct request_queue *q = bdev_get_queue(sb->s_bdev); | 96 | struct request_queue *q = bdev_get_queue(sb->s_bdev); |
97 | unsigned int max_pages = queue_max_hw_sectors(q) >> (PAGE_SHIFT - 9); | 97 | unsigned int max_pages = queue_max_hw_sectors(q) >> (PAGE_SHIFT - 9); |
98 | int i; | 98 | int i; |
99 | 99 | ||
100 | bio = bio_alloc(GFP_NOFS, max_pages); | 100 | bio = bio_alloc(GFP_NOFS, max_pages); |
101 | BUG_ON(!bio); /* FIXME: handle this */ | 101 | BUG_ON(!bio); /* FIXME: handle this */ |
102 | 102 | ||
103 | for (i = 0; i < nr_pages; i++) { | 103 | for (i = 0; i < nr_pages; i++) { |
104 | if (i >= max_pages) { | 104 | if (i >= max_pages) { |
105 | /* Block layer cannot split bios :( */ | 105 | /* Block layer cannot split bios :( */ |
106 | bio->bi_vcnt = i; | 106 | bio->bi_vcnt = i; |
107 | bio->bi_idx = 0; | 107 | bio->bi_idx = 0; |
108 | bio->bi_size = i * PAGE_SIZE; | 108 | bio->bi_size = i * PAGE_SIZE; |
109 | bio->bi_bdev = super->s_bdev; | 109 | bio->bi_bdev = super->s_bdev; |
110 | bio->bi_sector = ofs >> 9; | 110 | bio->bi_sector = ofs >> 9; |
111 | bio->bi_private = sb; | 111 | bio->bi_private = sb; |
112 | bio->bi_end_io = writeseg_end_io; | 112 | bio->bi_end_io = writeseg_end_io; |
113 | atomic_inc(&super->s_pending_writes); | 113 | atomic_inc(&super->s_pending_writes); |
114 | submit_bio(WRITE, bio); | 114 | submit_bio(WRITE, bio); |
115 | 115 | ||
116 | ofs += i * PAGE_SIZE; | 116 | ofs += i * PAGE_SIZE; |
117 | index += i; | 117 | index += i; |
118 | nr_pages -= i; | 118 | nr_pages -= i; |
119 | i = 0; | 119 | i = 0; |
120 | 120 | ||
121 | bio = bio_alloc(GFP_NOFS, max_pages); | 121 | bio = bio_alloc(GFP_NOFS, max_pages); |
122 | BUG_ON(!bio); | 122 | BUG_ON(!bio); |
123 | } | 123 | } |
124 | page = find_lock_page(mapping, index + i); | 124 | page = find_lock_page(mapping, index + i); |
125 | BUG_ON(!page); | 125 | BUG_ON(!page); |
126 | bio->bi_io_vec[i].bv_page = page; | 126 | bio->bi_io_vec[i].bv_page = page; |
127 | bio->bi_io_vec[i].bv_len = PAGE_SIZE; | 127 | bio->bi_io_vec[i].bv_len = PAGE_SIZE; |
128 | bio->bi_io_vec[i].bv_offset = 0; | 128 | bio->bi_io_vec[i].bv_offset = 0; |
129 | 129 | ||
130 | BUG_ON(PageWriteback(page)); | 130 | BUG_ON(PageWriteback(page)); |
131 | set_page_writeback(page); | 131 | set_page_writeback(page); |
132 | unlock_page(page); | 132 | unlock_page(page); |
133 | } | 133 | } |
134 | bio->bi_vcnt = nr_pages; | 134 | bio->bi_vcnt = nr_pages; |
135 | bio->bi_idx = 0; | 135 | bio->bi_idx = 0; |
136 | bio->bi_size = nr_pages * PAGE_SIZE; | 136 | bio->bi_size = nr_pages * PAGE_SIZE; |
137 | bio->bi_bdev = super->s_bdev; | 137 | bio->bi_bdev = super->s_bdev; |
138 | bio->bi_sector = ofs >> 9; | 138 | bio->bi_sector = ofs >> 9; |
139 | bio->bi_private = sb; | 139 | bio->bi_private = sb; |
140 | bio->bi_end_io = writeseg_end_io; | 140 | bio->bi_end_io = writeseg_end_io; |
141 | atomic_inc(&super->s_pending_writes); | 141 | atomic_inc(&super->s_pending_writes); |
142 | submit_bio(WRITE, bio); | 142 | submit_bio(WRITE, bio); |
143 | return 0; | 143 | return 0; |
144 | } | 144 | } |
145 | 145 | ||
146 | static void bdev_writeseg(struct super_block *sb, u64 ofs, size_t len) | 146 | static void bdev_writeseg(struct super_block *sb, u64 ofs, size_t len) |
147 | { | 147 | { |
148 | struct logfs_super *super = logfs_super(sb); | 148 | struct logfs_super *super = logfs_super(sb); |
149 | int head; | 149 | int head; |
150 | 150 | ||
151 | BUG_ON(super->s_flags & LOGFS_SB_FLAG_RO); | 151 | BUG_ON(super->s_flags & LOGFS_SB_FLAG_RO); |
152 | 152 | ||
153 | if (len == 0) { | 153 | if (len == 0) { |
154 | /* This can happen when the object fit perfectly into a | 154 | /* This can happen when the object fit perfectly into a |
155 | * segment, the segment gets written per sync and subsequently | 155 | * segment, the segment gets written per sync and subsequently |
156 | * closed. | 156 | * closed. |
157 | */ | 157 | */ |
158 | return; | 158 | return; |
159 | } | 159 | } |
160 | head = ofs & (PAGE_SIZE - 1); | 160 | head = ofs & (PAGE_SIZE - 1); |
161 | if (head) { | 161 | if (head) { |
162 | ofs -= head; | 162 | ofs -= head; |
163 | len += head; | 163 | len += head; |
164 | } | 164 | } |
165 | len = PAGE_ALIGN(len); | 165 | len = PAGE_ALIGN(len); |
166 | __bdev_writeseg(sb, ofs, ofs >> PAGE_SHIFT, len >> PAGE_SHIFT); | 166 | __bdev_writeseg(sb, ofs, ofs >> PAGE_SHIFT, len >> PAGE_SHIFT); |
167 | generic_unplug_device(bdev_get_queue(logfs_super(sb)->s_bdev)); | 167 | generic_unplug_device(bdev_get_queue(logfs_super(sb)->s_bdev)); |
168 | } | 168 | } |
169 | 169 | ||
170 | static int bdev_erase(struct super_block *sb, loff_t to, size_t len) | 170 | |
171 | static void erase_end_io(struct bio *bio, int err) | ||
172 | { | ||
173 | const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); | ||
174 | struct super_block *sb = bio->bi_private; | ||
175 | struct logfs_super *super = logfs_super(sb); | ||
176 | |||
177 | BUG_ON(!uptodate); /* FIXME: Retry io or write elsewhere */ | ||
178 | BUG_ON(err); | ||
179 | BUG_ON(bio->bi_vcnt == 0); | ||
180 | bio_put(bio); | ||
181 | if (atomic_dec_and_test(&super->s_pending_writes)) | ||
182 | wake_up(&wq); | ||
183 | } | ||
184 | |||
185 | static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index, | ||
186 | size_t nr_pages) | ||
171 | { | 187 | { |
172 | struct logfs_super *super = logfs_super(sb); | 188 | struct logfs_super *super = logfs_super(sb); |
173 | struct address_space *mapping = super->s_mapping_inode->i_mapping; | 189 | struct bio *bio; |
174 | struct page *page; | 190 | struct request_queue *q = bdev_get_queue(sb->s_bdev); |
175 | pgoff_t index = to >> PAGE_SHIFT; | 191 | unsigned int max_pages = queue_max_hw_sectors(q) >> (PAGE_SHIFT - 9); |
176 | int i, nr_pages = len >> PAGE_SHIFT; | 192 | int i; |
177 | 193 | ||
194 | bio = bio_alloc(GFP_NOFS, max_pages); | ||
195 | BUG_ON(!bio); /* FIXME: handle this */ | ||
196 | |||
197 | for (i = 0; i < nr_pages; i++) { | ||
198 | if (i >= max_pages) { | ||
199 | /* Block layer cannot split bios :( */ | ||
200 | bio->bi_vcnt = i; | ||
201 | bio->bi_idx = 0; | ||
202 | bio->bi_size = i * PAGE_SIZE; | ||
203 | bio->bi_bdev = super->s_bdev; | ||
204 | bio->bi_sector = ofs >> 9; | ||
205 | bio->bi_private = sb; | ||
206 | bio->bi_end_io = erase_end_io; | ||
207 | atomic_inc(&super->s_pending_writes); | ||
208 | submit_bio(WRITE, bio); | ||
209 | |||
210 | ofs += i * PAGE_SIZE; | ||
211 | index += i; | ||
212 | nr_pages -= i; | ||
213 | i = 0; | ||
214 | |||
215 | bio = bio_alloc(GFP_NOFS, max_pages); | ||
216 | BUG_ON(!bio); | ||
217 | } | ||
218 | bio->bi_io_vec[i].bv_page = super->s_erase_page; | ||
219 | bio->bi_io_vec[i].bv_len = PAGE_SIZE; | ||
220 | bio->bi_io_vec[i].bv_offset = 0; | ||
221 | } | ||
222 | bio->bi_vcnt = nr_pages; | ||
223 | bio->bi_idx = 0; | ||
224 | bio->bi_size = nr_pages * PAGE_SIZE; | ||
225 | bio->bi_bdev = super->s_bdev; | ||
226 | bio->bi_sector = ofs >> 9; | ||
227 | bio->bi_private = sb; | ||
228 | bio->bi_end_io = erase_end_io; | ||
229 | atomic_inc(&super->s_pending_writes); | ||
230 | submit_bio(WRITE, bio); | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int bdev_erase(struct super_block *sb, loff_t to, size_t len, | ||
235 | int ensure_write) | ||
236 | { | ||
237 | struct logfs_super *super = logfs_super(sb); | ||
238 | |||
178 | BUG_ON(to & (PAGE_SIZE - 1)); | 239 | BUG_ON(to & (PAGE_SIZE - 1)); |
179 | BUG_ON(len & (PAGE_SIZE - 1)); | 240 | BUG_ON(len & (PAGE_SIZE - 1)); |
180 | 241 | ||
181 | if (logfs_super(sb)->s_flags & LOGFS_SB_FLAG_RO) | 242 | if (super->s_flags & LOGFS_SB_FLAG_RO) |
182 | return -EROFS; | 243 | return -EROFS; |
183 | 244 | ||
184 | for (i = 0; i < nr_pages; i++) { | 245 | if (ensure_write) { |
185 | page = find_get_page(mapping, index + i); | 246 | /* |
186 | if (page) { | 247 | * Object store doesn't care whether erases happen or not. |
187 | memset(page_address(page), 0xFF, PAGE_SIZE); | 248 | * But for the journal they are required. Otherwise a scan |
188 | page_cache_release(page); | 249 | * can find an old commit entry and assume it is the current |
189 | } | 250 | * one, travelling back in time. |
251 | */ | ||
252 | do_erase(sb, to, to >> PAGE_SHIFT, len >> PAGE_SHIFT); | ||
190 | } | 253 | } |
254 | |||
191 | return 0; | 255 | return 0; |
192 | } | 256 | } |
193 | 257 | ||
194 | static void bdev_sync(struct super_block *sb) | 258 | static void bdev_sync(struct super_block *sb) |
195 | { | 259 | { |
196 | struct logfs_super *super = logfs_super(sb); | 260 | struct logfs_super *super = logfs_super(sb); |
197 | 261 | ||
198 | wait_event(wq, atomic_read(&super->s_pending_writes) == 0); | 262 | wait_event(wq, atomic_read(&super->s_pending_writes) == 0); |
199 | } | 263 | } |
200 | 264 | ||
201 | static struct page *bdev_find_first_sb(struct super_block *sb, u64 *ofs) | 265 | static struct page *bdev_find_first_sb(struct super_block *sb, u64 *ofs) |
202 | { | 266 | { |
203 | struct logfs_super *super = logfs_super(sb); | 267 | struct logfs_super *super = logfs_super(sb); |
204 | struct address_space *mapping = super->s_mapping_inode->i_mapping; | 268 | struct address_space *mapping = super->s_mapping_inode->i_mapping; |
205 | filler_t *filler = bdev_readpage; | 269 | filler_t *filler = bdev_readpage; |
206 | 270 | ||
207 | *ofs = 0; | 271 | *ofs = 0; |
208 | return read_cache_page(mapping, 0, filler, sb); | 272 | return read_cache_page(mapping, 0, filler, sb); |
209 | } | 273 | } |
210 | 274 | ||
211 | static struct page *bdev_find_last_sb(struct super_block *sb, u64 *ofs) | 275 | static struct page *bdev_find_last_sb(struct super_block *sb, u64 *ofs) |
212 | { | 276 | { |
213 | struct logfs_super *super = logfs_super(sb); | 277 | struct logfs_super *super = logfs_super(sb); |
214 | struct address_space *mapping = super->s_mapping_inode->i_mapping; | 278 | struct address_space *mapping = super->s_mapping_inode->i_mapping; |
215 | filler_t *filler = bdev_readpage; | 279 | filler_t *filler = bdev_readpage; |
216 | u64 pos = (super->s_bdev->bd_inode->i_size & ~0xfffULL) - 0x1000; | 280 | u64 pos = (super->s_bdev->bd_inode->i_size & ~0xfffULL) - 0x1000; |
217 | pgoff_t index = pos >> PAGE_SHIFT; | 281 | pgoff_t index = pos >> PAGE_SHIFT; |
218 | 282 | ||
219 | *ofs = pos; | 283 | *ofs = pos; |
220 | return read_cache_page(mapping, index, filler, sb); | 284 | return read_cache_page(mapping, index, filler, sb); |
221 | } | 285 | } |
222 | 286 | ||
223 | static int bdev_write_sb(struct super_block *sb, struct page *page) | 287 | static int bdev_write_sb(struct super_block *sb, struct page *page) |
224 | { | 288 | { |
225 | struct block_device *bdev = logfs_super(sb)->s_bdev; | 289 | struct block_device *bdev = logfs_super(sb)->s_bdev; |
226 | 290 | ||
227 | /* Nothing special to do for block devices. */ | 291 | /* Nothing special to do for block devices. */ |
228 | return sync_request(page, bdev, WRITE); | 292 | return sync_request(page, bdev, WRITE); |
229 | } | 293 | } |
230 | 294 | ||
231 | static void bdev_put_device(struct super_block *sb) | 295 | static void bdev_put_device(struct super_block *sb) |
232 | { | 296 | { |
233 | close_bdev_exclusive(logfs_super(sb)->s_bdev, FMODE_READ|FMODE_WRITE); | 297 | close_bdev_exclusive(logfs_super(sb)->s_bdev, FMODE_READ|FMODE_WRITE); |
234 | } | 298 | } |
235 | 299 | ||
236 | static const struct logfs_device_ops bd_devops = { | 300 | static const struct logfs_device_ops bd_devops = { |
237 | .find_first_sb = bdev_find_first_sb, | 301 | .find_first_sb = bdev_find_first_sb, |
238 | .find_last_sb = bdev_find_last_sb, | 302 | .find_last_sb = bdev_find_last_sb, |
239 | .write_sb = bdev_write_sb, | 303 | .write_sb = bdev_write_sb, |
240 | .readpage = bdev_readpage, | 304 | .readpage = bdev_readpage, |
241 | .writeseg = bdev_writeseg, | 305 | .writeseg = bdev_writeseg, |
242 | .erase = bdev_erase, | 306 | .erase = bdev_erase, |
243 | .sync = bdev_sync, | 307 | .sync = bdev_sync, |
244 | .put_device = bdev_put_device, | 308 | .put_device = bdev_put_device, |
245 | }; | 309 | }; |
246 | 310 | ||
247 | int logfs_get_sb_bdev(struct file_system_type *type, int flags, | 311 | int logfs_get_sb_bdev(struct file_system_type *type, int flags, |
248 | const char *devname, struct vfsmount *mnt) | 312 | const char *devname, struct vfsmount *mnt) |
249 | { | 313 | { |
250 | struct block_device *bdev; | 314 | struct block_device *bdev; |
251 | 315 | ||
252 | bdev = open_bdev_exclusive(devname, FMODE_READ|FMODE_WRITE, type); | 316 | bdev = open_bdev_exclusive(devname, FMODE_READ|FMODE_WRITE, type); |
253 | if (IS_ERR(bdev)) | 317 | if (IS_ERR(bdev)) |
254 | return PTR_ERR(bdev); | 318 | return PTR_ERR(bdev); |
255 | 319 | ||
256 | if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) { | 320 | if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) { |
257 | int mtdnr = MINOR(bdev->bd_dev); | 321 | int mtdnr = MINOR(bdev->bd_dev); |
258 | close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE); | 322 | close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE); |
259 | return logfs_get_sb_mtd(type, flags, mtdnr, mnt); | 323 | return logfs_get_sb_mtd(type, flags, mtdnr, mnt); |
260 | } | 324 | } |
261 | 325 | ||
262 | return logfs_get_sb_device(type, flags, NULL, bdev, &bd_devops, mnt); | 326 | return logfs_get_sb_device(type, flags, NULL, bdev, &bd_devops, mnt); |
263 | } | 327 | } |
264 | 328 |
fs/logfs/dev_mtd.c
1 | /* | 1 | /* |
2 | * fs/logfs/dev_mtd.c - Device access methods for MTD | 2 | * fs/logfs/dev_mtd.c - Device access methods for MTD |
3 | * | 3 | * |
4 | * As should be obvious for Linux kernel code, license is GPLv2 | 4 | * As should be obvious for Linux kernel code, license is GPLv2 |
5 | * | 5 | * |
6 | * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org> | 6 | * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org> |
7 | */ | 7 | */ |
8 | #include "logfs.h" | 8 | #include "logfs.h" |
9 | #include <linux/completion.h> | 9 | #include <linux/completion.h> |
10 | #include <linux/mount.h> | 10 | #include <linux/mount.h> |
11 | #include <linux/sched.h> | 11 | #include <linux/sched.h> |
12 | 12 | ||
13 | #define PAGE_OFS(ofs) ((ofs) & (PAGE_SIZE-1)) | 13 | #define PAGE_OFS(ofs) ((ofs) & (PAGE_SIZE-1)) |
14 | 14 | ||
15 | static int mtd_read(struct super_block *sb, loff_t ofs, size_t len, void *buf) | 15 | static int mtd_read(struct super_block *sb, loff_t ofs, size_t len, void *buf) |
16 | { | 16 | { |
17 | struct mtd_info *mtd = logfs_super(sb)->s_mtd; | 17 | struct mtd_info *mtd = logfs_super(sb)->s_mtd; |
18 | size_t retlen; | 18 | size_t retlen; |
19 | int ret; | 19 | int ret; |
20 | 20 | ||
21 | ret = mtd->read(mtd, ofs, len, &retlen, buf); | 21 | ret = mtd->read(mtd, ofs, len, &retlen, buf); |
22 | BUG_ON(ret == -EINVAL); | 22 | BUG_ON(ret == -EINVAL); |
23 | if (ret) | 23 | if (ret) |
24 | return ret; | 24 | return ret; |
25 | 25 | ||
26 | /* Not sure if we should loop instead. */ | 26 | /* Not sure if we should loop instead. */ |
27 | if (retlen != len) | 27 | if (retlen != len) |
28 | return -EIO; | 28 | return -EIO; |
29 | 29 | ||
30 | return 0; | 30 | return 0; |
31 | } | 31 | } |
32 | 32 | ||
33 | static int mtd_write(struct super_block *sb, loff_t ofs, size_t len, void *buf) | 33 | static int mtd_write(struct super_block *sb, loff_t ofs, size_t len, void *buf) |
34 | { | 34 | { |
35 | struct logfs_super *super = logfs_super(sb); | 35 | struct logfs_super *super = logfs_super(sb); |
36 | struct mtd_info *mtd = super->s_mtd; | 36 | struct mtd_info *mtd = super->s_mtd; |
37 | size_t retlen; | 37 | size_t retlen; |
38 | loff_t page_start, page_end; | 38 | loff_t page_start, page_end; |
39 | int ret; | 39 | int ret; |
40 | 40 | ||
41 | if (super->s_flags & LOGFS_SB_FLAG_RO) | 41 | if (super->s_flags & LOGFS_SB_FLAG_RO) |
42 | return -EROFS; | 42 | return -EROFS; |
43 | 43 | ||
44 | BUG_ON((ofs >= mtd->size) || (len > mtd->size - ofs)); | 44 | BUG_ON((ofs >= mtd->size) || (len > mtd->size - ofs)); |
45 | BUG_ON(ofs != (ofs >> super->s_writeshift) << super->s_writeshift); | 45 | BUG_ON(ofs != (ofs >> super->s_writeshift) << super->s_writeshift); |
46 | BUG_ON(len > PAGE_CACHE_SIZE); | 46 | BUG_ON(len > PAGE_CACHE_SIZE); |
47 | page_start = ofs & PAGE_CACHE_MASK; | 47 | page_start = ofs & PAGE_CACHE_MASK; |
48 | page_end = PAGE_CACHE_ALIGN(ofs + len) - 1; | 48 | page_end = PAGE_CACHE_ALIGN(ofs + len) - 1; |
49 | ret = mtd->write(mtd, ofs, len, &retlen, buf); | 49 | ret = mtd->write(mtd, ofs, len, &retlen, buf); |
50 | if (ret || (retlen != len)) | 50 | if (ret || (retlen != len)) |
51 | return -EIO; | 51 | return -EIO; |
52 | 52 | ||
53 | return 0; | 53 | return 0; |
54 | } | 54 | } |
55 | 55 | ||
56 | /* | 56 | /* |
57 | * For as long as I can remember (since about 2001) mtd->erase has been an | 57 | * For as long as I can remember (since about 2001) mtd->erase has been an |
58 | * asynchronous interface lacking the first driver to actually use the | 58 | * asynchronous interface lacking the first driver to actually use the |
59 | * asynchronous properties. So just to prevent the first implementor of such | 59 | * asynchronous properties. So just to prevent the first implementor of such |
60 | * a thing from breaking logfs in 2350, we do the usual pointless dance to | 60 | * a thing from breaking logfs in 2350, we do the usual pointless dance to |
61 | * declare a completion variable and wait for completion before returning | 61 | * declare a completion variable and wait for completion before returning |
62 | * from mtd_erase(). What an excercise in futility! | 62 | * from mtd_erase(). What an excercise in futility! |
63 | */ | 63 | */ |
64 | static void logfs_erase_callback(struct erase_info *ei) | 64 | static void logfs_erase_callback(struct erase_info *ei) |
65 | { | 65 | { |
66 | complete((struct completion *)ei->priv); | 66 | complete((struct completion *)ei->priv); |
67 | } | 67 | } |
68 | 68 | ||
69 | static int mtd_erase_mapping(struct super_block *sb, loff_t ofs, size_t len) | 69 | static int mtd_erase_mapping(struct super_block *sb, loff_t ofs, size_t len) |
70 | { | 70 | { |
71 | struct logfs_super *super = logfs_super(sb); | 71 | struct logfs_super *super = logfs_super(sb); |
72 | struct address_space *mapping = super->s_mapping_inode->i_mapping; | 72 | struct address_space *mapping = super->s_mapping_inode->i_mapping; |
73 | struct page *page; | 73 | struct page *page; |
74 | pgoff_t index = ofs >> PAGE_SHIFT; | 74 | pgoff_t index = ofs >> PAGE_SHIFT; |
75 | 75 | ||
76 | for (index = ofs >> PAGE_SHIFT; index < (ofs + len) >> PAGE_SHIFT; index++) { | 76 | for (index = ofs >> PAGE_SHIFT; index < (ofs + len) >> PAGE_SHIFT; index++) { |
77 | page = find_get_page(mapping, index); | 77 | page = find_get_page(mapping, index); |
78 | if (!page) | 78 | if (!page) |
79 | continue; | 79 | continue; |
80 | memset(page_address(page), 0xFF, PAGE_SIZE); | 80 | memset(page_address(page), 0xFF, PAGE_SIZE); |
81 | page_cache_release(page); | 81 | page_cache_release(page); |
82 | } | 82 | } |
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
85 | 85 | ||
86 | static int mtd_erase(struct super_block *sb, loff_t ofs, size_t len) | 86 | static int mtd_erase(struct super_block *sb, loff_t ofs, size_t len, |
87 | int ensure_write) | ||
87 | { | 88 | { |
88 | struct mtd_info *mtd = logfs_super(sb)->s_mtd; | 89 | struct mtd_info *mtd = logfs_super(sb)->s_mtd; |
89 | struct erase_info ei; | 90 | struct erase_info ei; |
90 | DECLARE_COMPLETION_ONSTACK(complete); | 91 | DECLARE_COMPLETION_ONSTACK(complete); |
91 | int ret; | 92 | int ret; |
92 | 93 | ||
93 | BUG_ON(len % mtd->erasesize); | 94 | BUG_ON(len % mtd->erasesize); |
94 | if (logfs_super(sb)->s_flags & LOGFS_SB_FLAG_RO) | 95 | if (logfs_super(sb)->s_flags & LOGFS_SB_FLAG_RO) |
95 | return -EROFS; | 96 | return -EROFS; |
96 | 97 | ||
97 | memset(&ei, 0, sizeof(ei)); | 98 | memset(&ei, 0, sizeof(ei)); |
98 | ei.mtd = mtd; | 99 | ei.mtd = mtd; |
99 | ei.addr = ofs; | 100 | ei.addr = ofs; |
100 | ei.len = len; | 101 | ei.len = len; |
101 | ei.callback = logfs_erase_callback; | 102 | ei.callback = logfs_erase_callback; |
102 | ei.priv = (long)&complete; | 103 | ei.priv = (long)&complete; |
103 | ret = mtd->erase(mtd, &ei); | 104 | ret = mtd->erase(mtd, &ei); |
104 | if (ret) | 105 | if (ret) |
105 | return -EIO; | 106 | return -EIO; |
106 | 107 | ||
107 | wait_for_completion(&complete); | 108 | wait_for_completion(&complete); |
108 | if (ei.state != MTD_ERASE_DONE) | 109 | if (ei.state != MTD_ERASE_DONE) |
109 | return -EIO; | 110 | return -EIO; |
110 | return mtd_erase_mapping(sb, ofs, len); | 111 | return mtd_erase_mapping(sb, ofs, len); |
111 | } | 112 | } |
112 | 113 | ||
113 | static void mtd_sync(struct super_block *sb) | 114 | static void mtd_sync(struct super_block *sb) |
114 | { | 115 | { |
115 | struct mtd_info *mtd = logfs_super(sb)->s_mtd; | 116 | struct mtd_info *mtd = logfs_super(sb)->s_mtd; |
116 | 117 | ||
117 | if (mtd->sync) | 118 | if (mtd->sync) |
118 | mtd->sync(mtd); | 119 | mtd->sync(mtd); |
119 | } | 120 | } |
120 | 121 | ||
121 | static int mtd_readpage(void *_sb, struct page *page) | 122 | static int mtd_readpage(void *_sb, struct page *page) |
122 | { | 123 | { |
123 | struct super_block *sb = _sb; | 124 | struct super_block *sb = _sb; |
124 | int err; | 125 | int err; |
125 | 126 | ||
126 | err = mtd_read(sb, page->index << PAGE_SHIFT, PAGE_SIZE, | 127 | err = mtd_read(sb, page->index << PAGE_SHIFT, PAGE_SIZE, |
127 | page_address(page)); | 128 | page_address(page)); |
128 | if (err == -EUCLEAN) { | 129 | if (err == -EUCLEAN) { |
129 | err = 0; | 130 | err = 0; |
130 | /* FIXME: force GC this segment */ | 131 | /* FIXME: force GC this segment */ |
131 | } | 132 | } |
132 | if (err) { | 133 | if (err) { |
133 | ClearPageUptodate(page); | 134 | ClearPageUptodate(page); |
134 | SetPageError(page); | 135 | SetPageError(page); |
135 | } else { | 136 | } else { |
136 | SetPageUptodate(page); | 137 | SetPageUptodate(page); |
137 | ClearPageError(page); | 138 | ClearPageError(page); |
138 | } | 139 | } |
139 | unlock_page(page); | 140 | unlock_page(page); |
140 | return err; | 141 | return err; |
141 | } | 142 | } |
142 | 143 | ||
143 | static struct page *mtd_find_first_sb(struct super_block *sb, u64 *ofs) | 144 | static struct page *mtd_find_first_sb(struct super_block *sb, u64 *ofs) |
144 | { | 145 | { |
145 | struct logfs_super *super = logfs_super(sb); | 146 | struct logfs_super *super = logfs_super(sb); |
146 | struct address_space *mapping = super->s_mapping_inode->i_mapping; | 147 | struct address_space *mapping = super->s_mapping_inode->i_mapping; |
147 | filler_t *filler = mtd_readpage; | 148 | filler_t *filler = mtd_readpage; |
148 | struct mtd_info *mtd = super->s_mtd; | 149 | struct mtd_info *mtd = super->s_mtd; |
149 | 150 | ||
150 | if (!mtd->block_isbad) | 151 | if (!mtd->block_isbad) |
151 | return NULL; | 152 | return NULL; |
152 | 153 | ||
153 | *ofs = 0; | 154 | *ofs = 0; |
154 | while (mtd->block_isbad(mtd, *ofs)) { | 155 | while (mtd->block_isbad(mtd, *ofs)) { |
155 | *ofs += mtd->erasesize; | 156 | *ofs += mtd->erasesize; |
156 | if (*ofs >= mtd->size) | 157 | if (*ofs >= mtd->size) |
157 | return NULL; | 158 | return NULL; |
158 | } | 159 | } |
159 | BUG_ON(*ofs & ~PAGE_MASK); | 160 | BUG_ON(*ofs & ~PAGE_MASK); |
160 | return read_cache_page(mapping, *ofs >> PAGE_SHIFT, filler, sb); | 161 | return read_cache_page(mapping, *ofs >> PAGE_SHIFT, filler, sb); |
161 | } | 162 | } |
162 | 163 | ||
163 | static struct page *mtd_find_last_sb(struct super_block *sb, u64 *ofs) | 164 | static struct page *mtd_find_last_sb(struct super_block *sb, u64 *ofs) |
164 | { | 165 | { |
165 | struct logfs_super *super = logfs_super(sb); | 166 | struct logfs_super *super = logfs_super(sb); |
166 | struct address_space *mapping = super->s_mapping_inode->i_mapping; | 167 | struct address_space *mapping = super->s_mapping_inode->i_mapping; |
167 | filler_t *filler = mtd_readpage; | 168 | filler_t *filler = mtd_readpage; |
168 | struct mtd_info *mtd = super->s_mtd; | 169 | struct mtd_info *mtd = super->s_mtd; |
169 | 170 | ||
170 | if (!mtd->block_isbad) | 171 | if (!mtd->block_isbad) |
171 | return NULL; | 172 | return NULL; |
172 | 173 | ||
173 | *ofs = mtd->size - mtd->erasesize; | 174 | *ofs = mtd->size - mtd->erasesize; |
174 | while (mtd->block_isbad(mtd, *ofs)) { | 175 | while (mtd->block_isbad(mtd, *ofs)) { |
175 | *ofs -= mtd->erasesize; | 176 | *ofs -= mtd->erasesize; |
176 | if (*ofs <= 0) | 177 | if (*ofs <= 0) |
177 | return NULL; | 178 | return NULL; |
178 | } | 179 | } |
179 | *ofs = *ofs + mtd->erasesize - 0x1000; | 180 | *ofs = *ofs + mtd->erasesize - 0x1000; |
180 | BUG_ON(*ofs & ~PAGE_MASK); | 181 | BUG_ON(*ofs & ~PAGE_MASK); |
181 | return read_cache_page(mapping, *ofs >> PAGE_SHIFT, filler, sb); | 182 | return read_cache_page(mapping, *ofs >> PAGE_SHIFT, filler, sb); |
182 | } | 183 | } |
183 | 184 | ||
184 | static int __mtd_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, | 185 | static int __mtd_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, |
185 | size_t nr_pages) | 186 | size_t nr_pages) |
186 | { | 187 | { |
187 | struct logfs_super *super = logfs_super(sb); | 188 | struct logfs_super *super = logfs_super(sb); |
188 | struct address_space *mapping = super->s_mapping_inode->i_mapping; | 189 | struct address_space *mapping = super->s_mapping_inode->i_mapping; |
189 | struct page *page; | 190 | struct page *page; |
190 | int i, err; | 191 | int i, err; |
191 | 192 | ||
192 | for (i = 0; i < nr_pages; i++) { | 193 | for (i = 0; i < nr_pages; i++) { |
193 | page = find_lock_page(mapping, index + i); | 194 | page = find_lock_page(mapping, index + i); |
194 | BUG_ON(!page); | 195 | BUG_ON(!page); |
195 | 196 | ||
196 | err = mtd_write(sb, page->index << PAGE_SHIFT, PAGE_SIZE, | 197 | err = mtd_write(sb, page->index << PAGE_SHIFT, PAGE_SIZE, |
197 | page_address(page)); | 198 | page_address(page)); |
198 | unlock_page(page); | 199 | unlock_page(page); |
199 | page_cache_release(page); | 200 | page_cache_release(page); |
200 | if (err) | 201 | if (err) |
201 | return err; | 202 | return err; |
202 | } | 203 | } |
203 | return 0; | 204 | return 0; |
204 | } | 205 | } |
205 | 206 | ||
206 | static void mtd_writeseg(struct super_block *sb, u64 ofs, size_t len) | 207 | static void mtd_writeseg(struct super_block *sb, u64 ofs, size_t len) |
207 | { | 208 | { |
208 | struct logfs_super *super = logfs_super(sb); | 209 | struct logfs_super *super = logfs_super(sb); |
209 | int head; | 210 | int head; |
210 | 211 | ||
211 | if (super->s_flags & LOGFS_SB_FLAG_RO) | 212 | if (super->s_flags & LOGFS_SB_FLAG_RO) |
212 | return; | 213 | return; |
213 | 214 | ||
214 | if (len == 0) { | 215 | if (len == 0) { |
215 | /* This can happen when the object fit perfectly into a | 216 | /* This can happen when the object fit perfectly into a |
216 | * segment, the segment gets written per sync and subsequently | 217 | * segment, the segment gets written per sync and subsequently |
217 | * closed. | 218 | * closed. |
218 | */ | 219 | */ |
219 | return; | 220 | return; |
220 | } | 221 | } |
221 | head = ofs & (PAGE_SIZE - 1); | 222 | head = ofs & (PAGE_SIZE - 1); |
222 | if (head) { | 223 | if (head) { |
223 | ofs -= head; | 224 | ofs -= head; |
224 | len += head; | 225 | len += head; |
225 | } | 226 | } |
226 | len = PAGE_ALIGN(len); | 227 | len = PAGE_ALIGN(len); |
227 | __mtd_writeseg(sb, ofs, ofs >> PAGE_SHIFT, len >> PAGE_SHIFT); | 228 | __mtd_writeseg(sb, ofs, ofs >> PAGE_SHIFT, len >> PAGE_SHIFT); |
228 | } | 229 | } |
229 | 230 | ||
230 | static void mtd_put_device(struct super_block *sb) | 231 | static void mtd_put_device(struct super_block *sb) |
231 | { | 232 | { |
232 | put_mtd_device(logfs_super(sb)->s_mtd); | 233 | put_mtd_device(logfs_super(sb)->s_mtd); |
233 | } | 234 | } |
234 | 235 | ||
235 | static const struct logfs_device_ops mtd_devops = { | 236 | static const struct logfs_device_ops mtd_devops = { |
236 | .find_first_sb = mtd_find_first_sb, | 237 | .find_first_sb = mtd_find_first_sb, |
237 | .find_last_sb = mtd_find_last_sb, | 238 | .find_last_sb = mtd_find_last_sb, |
238 | .readpage = mtd_readpage, | 239 | .readpage = mtd_readpage, |
239 | .writeseg = mtd_writeseg, | 240 | .writeseg = mtd_writeseg, |
240 | .erase = mtd_erase, | 241 | .erase = mtd_erase, |
241 | .sync = mtd_sync, | 242 | .sync = mtd_sync, |
242 | .put_device = mtd_put_device, | 243 | .put_device = mtd_put_device, |
243 | }; | 244 | }; |
244 | 245 | ||
245 | int logfs_get_sb_mtd(struct file_system_type *type, int flags, | 246 | int logfs_get_sb_mtd(struct file_system_type *type, int flags, |
246 | int mtdnr, struct vfsmount *mnt) | 247 | int mtdnr, struct vfsmount *mnt) |
247 | { | 248 | { |
248 | struct mtd_info *mtd; | 249 | struct mtd_info *mtd; |
249 | const struct logfs_device_ops *devops = &mtd_devops; | 250 | const struct logfs_device_ops *devops = &mtd_devops; |
250 | 251 | ||
251 | mtd = get_mtd_device(NULL, mtdnr); | 252 | mtd = get_mtd_device(NULL, mtdnr); |
252 | return logfs_get_sb_device(type, flags, mtd, NULL, devops, mnt); | 253 | return logfs_get_sb_device(type, flags, mtd, NULL, devops, mnt); |
253 | } | 254 | } |
254 | 255 |
fs/logfs/journal.c
1 | /* | 1 | /* |
2 | * fs/logfs/journal.c - journal handling code | 2 | * fs/logfs/journal.c - journal handling code |
3 | * | 3 | * |
4 | * As should be obvious for Linux kernel code, license is GPLv2 | 4 | * As should be obvious for Linux kernel code, license is GPLv2 |
5 | * | 5 | * |
6 | * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org> | 6 | * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org> |
7 | */ | 7 | */ |
8 | #include "logfs.h" | 8 | #include "logfs.h" |
9 | 9 | ||
10 | static void logfs_calc_free(struct super_block *sb) | 10 | static void logfs_calc_free(struct super_block *sb) |
11 | { | 11 | { |
12 | struct logfs_super *super = logfs_super(sb); | 12 | struct logfs_super *super = logfs_super(sb); |
13 | u64 reserve, no_segs = super->s_no_segs; | 13 | u64 reserve, no_segs = super->s_no_segs; |
14 | s64 free; | 14 | s64 free; |
15 | int i; | 15 | int i; |
16 | 16 | ||
17 | /* superblock segments */ | 17 | /* superblock segments */ |
18 | no_segs -= 2; | 18 | no_segs -= 2; |
19 | super->s_no_journal_segs = 0; | 19 | super->s_no_journal_segs = 0; |
20 | /* journal */ | 20 | /* journal */ |
21 | journal_for_each(i) | 21 | journal_for_each(i) |
22 | if (super->s_journal_seg[i]) { | 22 | if (super->s_journal_seg[i]) { |
23 | no_segs--; | 23 | no_segs--; |
24 | super->s_no_journal_segs++; | 24 | super->s_no_journal_segs++; |
25 | } | 25 | } |
26 | 26 | ||
27 | /* open segments plus one extra per level for GC */ | 27 | /* open segments plus one extra per level for GC */ |
28 | no_segs -= 2 * super->s_total_levels; | 28 | no_segs -= 2 * super->s_total_levels; |
29 | 29 | ||
30 | free = no_segs * (super->s_segsize - LOGFS_SEGMENT_RESERVE); | 30 | free = no_segs * (super->s_segsize - LOGFS_SEGMENT_RESERVE); |
31 | free -= super->s_used_bytes; | 31 | free -= super->s_used_bytes; |
32 | /* just a bit extra */ | 32 | /* just a bit extra */ |
33 | free -= super->s_total_levels * 4096; | 33 | free -= super->s_total_levels * 4096; |
34 | 34 | ||
35 | /* Bad blocks are 'paid' for with speed reserve - the filesystem | 35 | /* Bad blocks are 'paid' for with speed reserve - the filesystem |
36 | * simply gets slower as bad blocks accumulate. Until the bad blocks | 36 | * simply gets slower as bad blocks accumulate. Until the bad blocks |
37 | * exceed the speed reserve - then the filesystem gets smaller. | 37 | * exceed the speed reserve - then the filesystem gets smaller. |
38 | */ | 38 | */ |
39 | reserve = super->s_bad_segments + super->s_bad_seg_reserve; | 39 | reserve = super->s_bad_segments + super->s_bad_seg_reserve; |
40 | reserve *= super->s_segsize - LOGFS_SEGMENT_RESERVE; | 40 | reserve *= super->s_segsize - LOGFS_SEGMENT_RESERVE; |
41 | reserve = max(reserve, super->s_speed_reserve); | 41 | reserve = max(reserve, super->s_speed_reserve); |
42 | free -= reserve; | 42 | free -= reserve; |
43 | if (free < 0) | 43 | if (free < 0) |
44 | free = 0; | 44 | free = 0; |
45 | 45 | ||
46 | super->s_free_bytes = free; | 46 | super->s_free_bytes = free; |
47 | } | 47 | } |
48 | 48 | ||
49 | static void reserve_sb_and_journal(struct super_block *sb) | 49 | static void reserve_sb_and_journal(struct super_block *sb) |
50 | { | 50 | { |
51 | struct logfs_super *super = logfs_super(sb); | 51 | struct logfs_super *super = logfs_super(sb); |
52 | struct btree_head32 *head = &super->s_reserved_segments; | 52 | struct btree_head32 *head = &super->s_reserved_segments; |
53 | int i, err; | 53 | int i, err; |
54 | 54 | ||
55 | err = btree_insert32(head, seg_no(sb, super->s_sb_ofs[0]), (void *)1, | 55 | err = btree_insert32(head, seg_no(sb, super->s_sb_ofs[0]), (void *)1, |
56 | GFP_KERNEL); | 56 | GFP_KERNEL); |
57 | BUG_ON(err); | 57 | BUG_ON(err); |
58 | 58 | ||
59 | err = btree_insert32(head, seg_no(sb, super->s_sb_ofs[1]), (void *)1, | 59 | err = btree_insert32(head, seg_no(sb, super->s_sb_ofs[1]), (void *)1, |
60 | GFP_KERNEL); | 60 | GFP_KERNEL); |
61 | BUG_ON(err); | 61 | BUG_ON(err); |
62 | 62 | ||
63 | journal_for_each(i) { | 63 | journal_for_each(i) { |
64 | if (!super->s_journal_seg[i]) | 64 | if (!super->s_journal_seg[i]) |
65 | continue; | 65 | continue; |
66 | err = btree_insert32(head, super->s_journal_seg[i], (void *)1, | 66 | err = btree_insert32(head, super->s_journal_seg[i], (void *)1, |
67 | GFP_KERNEL); | 67 | GFP_KERNEL); |
68 | BUG_ON(err); | 68 | BUG_ON(err); |
69 | } | 69 | } |
70 | } | 70 | } |
71 | 71 | ||
72 | static void read_dynsb(struct super_block *sb, | 72 | static void read_dynsb(struct super_block *sb, |
73 | struct logfs_je_dynsb *dynsb) | 73 | struct logfs_je_dynsb *dynsb) |
74 | { | 74 | { |
75 | struct logfs_super *super = logfs_super(sb); | 75 | struct logfs_super *super = logfs_super(sb); |
76 | 76 | ||
77 | super->s_gec = be64_to_cpu(dynsb->ds_gec); | 77 | super->s_gec = be64_to_cpu(dynsb->ds_gec); |
78 | super->s_sweeper = be64_to_cpu(dynsb->ds_sweeper); | 78 | super->s_sweeper = be64_to_cpu(dynsb->ds_sweeper); |
79 | super->s_victim_ino = be64_to_cpu(dynsb->ds_victim_ino); | 79 | super->s_victim_ino = be64_to_cpu(dynsb->ds_victim_ino); |
80 | super->s_rename_dir = be64_to_cpu(dynsb->ds_rename_dir); | 80 | super->s_rename_dir = be64_to_cpu(dynsb->ds_rename_dir); |
81 | super->s_rename_pos = be64_to_cpu(dynsb->ds_rename_pos); | 81 | super->s_rename_pos = be64_to_cpu(dynsb->ds_rename_pos); |
82 | super->s_used_bytes = be64_to_cpu(dynsb->ds_used_bytes); | 82 | super->s_used_bytes = be64_to_cpu(dynsb->ds_used_bytes); |
83 | super->s_generation = be32_to_cpu(dynsb->ds_generation); | 83 | super->s_generation = be32_to_cpu(dynsb->ds_generation); |
84 | } | 84 | } |
85 | 85 | ||
86 | static void read_anchor(struct super_block *sb, | 86 | static void read_anchor(struct super_block *sb, |
87 | struct logfs_je_anchor *da) | 87 | struct logfs_je_anchor *da) |
88 | { | 88 | { |
89 | struct logfs_super *super = logfs_super(sb); | 89 | struct logfs_super *super = logfs_super(sb); |
90 | struct inode *inode = super->s_master_inode; | 90 | struct inode *inode = super->s_master_inode; |
91 | struct logfs_inode *li = logfs_inode(inode); | 91 | struct logfs_inode *li = logfs_inode(inode); |
92 | int i; | 92 | int i; |
93 | 93 | ||
94 | super->s_last_ino = be64_to_cpu(da->da_last_ino); | 94 | super->s_last_ino = be64_to_cpu(da->da_last_ino); |
95 | li->li_flags = 0; | 95 | li->li_flags = 0; |
96 | li->li_height = da->da_height; | 96 | li->li_height = da->da_height; |
97 | i_size_write(inode, be64_to_cpu(da->da_size)); | 97 | i_size_write(inode, be64_to_cpu(da->da_size)); |
98 | li->li_used_bytes = be64_to_cpu(da->da_used_bytes); | 98 | li->li_used_bytes = be64_to_cpu(da->da_used_bytes); |
99 | 99 | ||
100 | for (i = 0; i < LOGFS_EMBEDDED_FIELDS; i++) | 100 | for (i = 0; i < LOGFS_EMBEDDED_FIELDS; i++) |
101 | li->li_data[i] = be64_to_cpu(da->da_data[i]); | 101 | li->li_data[i] = be64_to_cpu(da->da_data[i]); |
102 | } | 102 | } |
103 | 103 | ||
104 | static void read_erasecount(struct super_block *sb, | 104 | static void read_erasecount(struct super_block *sb, |
105 | struct logfs_je_journal_ec *ec) | 105 | struct logfs_je_journal_ec *ec) |
106 | { | 106 | { |
107 | struct logfs_super *super = logfs_super(sb); | 107 | struct logfs_super *super = logfs_super(sb); |
108 | int i; | 108 | int i; |
109 | 109 | ||
110 | journal_for_each(i) | 110 | journal_for_each(i) |
111 | super->s_journal_ec[i] = be32_to_cpu(ec->ec[i]); | 111 | super->s_journal_ec[i] = be32_to_cpu(ec->ec[i]); |
112 | } | 112 | } |
113 | 113 | ||
114 | static int read_area(struct super_block *sb, struct logfs_je_area *a) | 114 | static int read_area(struct super_block *sb, struct logfs_je_area *a) |
115 | { | 115 | { |
116 | struct logfs_super *super = logfs_super(sb); | 116 | struct logfs_super *super = logfs_super(sb); |
117 | struct logfs_area *area = super->s_area[a->gc_level]; | 117 | struct logfs_area *area = super->s_area[a->gc_level]; |
118 | u64 ofs; | 118 | u64 ofs; |
119 | u32 writemask = ~(super->s_writesize - 1); | 119 | u32 writemask = ~(super->s_writesize - 1); |
120 | 120 | ||
121 | if (a->gc_level >= LOGFS_NO_AREAS) | 121 | if (a->gc_level >= LOGFS_NO_AREAS) |
122 | return -EIO; | 122 | return -EIO; |
123 | if (a->vim != VIM_DEFAULT) | 123 | if (a->vim != VIM_DEFAULT) |
124 | return -EIO; /* TODO: close area and continue */ | 124 | return -EIO; /* TODO: close area and continue */ |
125 | 125 | ||
126 | area->a_used_bytes = be32_to_cpu(a->used_bytes); | 126 | area->a_used_bytes = be32_to_cpu(a->used_bytes); |
127 | area->a_written_bytes = area->a_used_bytes & writemask; | 127 | area->a_written_bytes = area->a_used_bytes & writemask; |
128 | area->a_segno = be32_to_cpu(a->segno); | 128 | area->a_segno = be32_to_cpu(a->segno); |
129 | if (area->a_segno) | 129 | if (area->a_segno) |
130 | area->a_is_open = 1; | 130 | area->a_is_open = 1; |
131 | 131 | ||
132 | ofs = dev_ofs(sb, area->a_segno, area->a_written_bytes); | 132 | ofs = dev_ofs(sb, area->a_segno, area->a_written_bytes); |
133 | if (super->s_writesize > 1) | 133 | if (super->s_writesize > 1) |
134 | logfs_buf_recover(area, ofs, a + 1, super->s_writesize); | 134 | logfs_buf_recover(area, ofs, a + 1, super->s_writesize); |
135 | else | 135 | else |
136 | logfs_buf_recover(area, ofs, NULL, 0); | 136 | logfs_buf_recover(area, ofs, NULL, 0); |
137 | return 0; | 137 | return 0; |
138 | } | 138 | } |
139 | 139 | ||
140 | static void *unpack(void *from, void *to) | 140 | static void *unpack(void *from, void *to) |
141 | { | 141 | { |
142 | struct logfs_journal_header *jh = from; | 142 | struct logfs_journal_header *jh = from; |
143 | void *data = from + sizeof(struct logfs_journal_header); | 143 | void *data = from + sizeof(struct logfs_journal_header); |
144 | int err; | 144 | int err; |
145 | size_t inlen, outlen; | 145 | size_t inlen, outlen; |
146 | 146 | ||
147 | inlen = be16_to_cpu(jh->h_len); | 147 | inlen = be16_to_cpu(jh->h_len); |
148 | outlen = be16_to_cpu(jh->h_datalen); | 148 | outlen = be16_to_cpu(jh->h_datalen); |
149 | 149 | ||
150 | if (jh->h_compr == COMPR_NONE) | 150 | if (jh->h_compr == COMPR_NONE) |
151 | memcpy(to, data, inlen); | 151 | memcpy(to, data, inlen); |
152 | else { | 152 | else { |
153 | err = logfs_uncompress(data, to, inlen, outlen); | 153 | err = logfs_uncompress(data, to, inlen, outlen); |
154 | BUG_ON(err); | 154 | BUG_ON(err); |
155 | } | 155 | } |
156 | return to; | 156 | return to; |
157 | } | 157 | } |
158 | 158 | ||
159 | static int __read_je_header(struct super_block *sb, u64 ofs, | 159 | static int __read_je_header(struct super_block *sb, u64 ofs, |
160 | struct logfs_journal_header *jh) | 160 | struct logfs_journal_header *jh) |
161 | { | 161 | { |
162 | struct logfs_super *super = logfs_super(sb); | 162 | struct logfs_super *super = logfs_super(sb); |
163 | size_t bufsize = max_t(size_t, sb->s_blocksize, super->s_writesize) | 163 | size_t bufsize = max_t(size_t, sb->s_blocksize, super->s_writesize) |
164 | + MAX_JOURNAL_HEADER; | 164 | + MAX_JOURNAL_HEADER; |
165 | u16 type, len, datalen; | 165 | u16 type, len, datalen; |
166 | int err; | 166 | int err; |
167 | 167 | ||
168 | /* read header only */ | 168 | /* read header only */ |
169 | err = wbuf_read(sb, ofs, sizeof(*jh), jh); | 169 | err = wbuf_read(sb, ofs, sizeof(*jh), jh); |
170 | if (err) | 170 | if (err) |
171 | return err; | 171 | return err; |
172 | type = be16_to_cpu(jh->h_type); | 172 | type = be16_to_cpu(jh->h_type); |
173 | len = be16_to_cpu(jh->h_len); | 173 | len = be16_to_cpu(jh->h_len); |
174 | datalen = be16_to_cpu(jh->h_datalen); | 174 | datalen = be16_to_cpu(jh->h_datalen); |
175 | if (len > sb->s_blocksize) | 175 | if (len > sb->s_blocksize) |
176 | return -EIO; | 176 | return -EIO; |
177 | if ((type < JE_FIRST) || (type > JE_LAST)) | 177 | if ((type < JE_FIRST) || (type > JE_LAST)) |
178 | return -EIO; | 178 | return -EIO; |
179 | if (datalen > bufsize) | 179 | if (datalen > bufsize) |
180 | return -EIO; | 180 | return -EIO; |
181 | return 0; | 181 | return 0; |
182 | } | 182 | } |
183 | 183 | ||
184 | static int __read_je_payload(struct super_block *sb, u64 ofs, | 184 | static int __read_je_payload(struct super_block *sb, u64 ofs, |
185 | struct logfs_journal_header *jh) | 185 | struct logfs_journal_header *jh) |
186 | { | 186 | { |
187 | u16 len; | 187 | u16 len; |
188 | int err; | 188 | int err; |
189 | 189 | ||
190 | len = be16_to_cpu(jh->h_len); | 190 | len = be16_to_cpu(jh->h_len); |
191 | err = wbuf_read(sb, ofs + sizeof(*jh), len, jh + 1); | 191 | err = wbuf_read(sb, ofs + sizeof(*jh), len, jh + 1); |
192 | if (err) | 192 | if (err) |
193 | return err; | 193 | return err; |
194 | if (jh->h_crc != logfs_crc32(jh, len + sizeof(*jh), 4)) { | 194 | if (jh->h_crc != logfs_crc32(jh, len + sizeof(*jh), 4)) { |
195 | /* Old code was confused. It forgot about the header length | 195 | /* Old code was confused. It forgot about the header length |
196 | * and stopped calculating the crc 16 bytes before the end | 196 | * and stopped calculating the crc 16 bytes before the end |
197 | * of data - ick! | 197 | * of data - ick! |
198 | * FIXME: Remove this hack once the old code is fixed. | 198 | * FIXME: Remove this hack once the old code is fixed. |
199 | */ | 199 | */ |
200 | if (jh->h_crc == logfs_crc32(jh, len, 4)) | 200 | if (jh->h_crc == logfs_crc32(jh, len, 4)) |
201 | WARN_ON_ONCE(1); | 201 | WARN_ON_ONCE(1); |
202 | else | 202 | else |
203 | return -EIO; | 203 | return -EIO; |
204 | } | 204 | } |
205 | return 0; | 205 | return 0; |
206 | } | 206 | } |
207 | 207 | ||
208 | /* | 208 | /* |
209 | * jh needs to be large enough to hold the complete entry, not just the header | 209 | * jh needs to be large enough to hold the complete entry, not just the header |
210 | */ | 210 | */ |
211 | static int __read_je(struct super_block *sb, u64 ofs, | 211 | static int __read_je(struct super_block *sb, u64 ofs, |
212 | struct logfs_journal_header *jh) | 212 | struct logfs_journal_header *jh) |
213 | { | 213 | { |
214 | int err; | 214 | int err; |
215 | 215 | ||
216 | err = __read_je_header(sb, ofs, jh); | 216 | err = __read_je_header(sb, ofs, jh); |
217 | if (err) | 217 | if (err) |
218 | return err; | 218 | return err; |
219 | return __read_je_payload(sb, ofs, jh); | 219 | return __read_je_payload(sb, ofs, jh); |
220 | } | 220 | } |
221 | 221 | ||
222 | static int read_je(struct super_block *sb, u64 ofs) | 222 | static int read_je(struct super_block *sb, u64 ofs) |
223 | { | 223 | { |
224 | struct logfs_super *super = logfs_super(sb); | 224 | struct logfs_super *super = logfs_super(sb); |
225 | struct logfs_journal_header *jh = super->s_compressed_je; | 225 | struct logfs_journal_header *jh = super->s_compressed_je; |
226 | void *scratch = super->s_je; | 226 | void *scratch = super->s_je; |
227 | u16 type, datalen; | 227 | u16 type, datalen; |
228 | int err; | 228 | int err; |
229 | 229 | ||
230 | err = __read_je(sb, ofs, jh); | 230 | err = __read_je(sb, ofs, jh); |
231 | if (err) | 231 | if (err) |
232 | return err; | 232 | return err; |
233 | type = be16_to_cpu(jh->h_type); | 233 | type = be16_to_cpu(jh->h_type); |
234 | datalen = be16_to_cpu(jh->h_datalen); | 234 | datalen = be16_to_cpu(jh->h_datalen); |
235 | 235 | ||
236 | switch (type) { | 236 | switch (type) { |
237 | case JE_DYNSB: | 237 | case JE_DYNSB: |
238 | read_dynsb(sb, unpack(jh, scratch)); | 238 | read_dynsb(sb, unpack(jh, scratch)); |
239 | break; | 239 | break; |
240 | case JE_ANCHOR: | 240 | case JE_ANCHOR: |
241 | read_anchor(sb, unpack(jh, scratch)); | 241 | read_anchor(sb, unpack(jh, scratch)); |
242 | break; | 242 | break; |
243 | case JE_ERASECOUNT: | 243 | case JE_ERASECOUNT: |
244 | read_erasecount(sb, unpack(jh, scratch)); | 244 | read_erasecount(sb, unpack(jh, scratch)); |
245 | break; | 245 | break; |
246 | case JE_AREA: | 246 | case JE_AREA: |
247 | read_area(sb, unpack(jh, scratch)); | 247 | read_area(sb, unpack(jh, scratch)); |
248 | break; | 248 | break; |
249 | case JE_OBJ_ALIAS: | 249 | case JE_OBJ_ALIAS: |
250 | err = logfs_load_object_aliases(sb, unpack(jh, scratch), | 250 | err = logfs_load_object_aliases(sb, unpack(jh, scratch), |
251 | datalen); | 251 | datalen); |
252 | break; | 252 | break; |
253 | default: | 253 | default: |
254 | WARN_ON_ONCE(1); | 254 | WARN_ON_ONCE(1); |
255 | return -EIO; | 255 | return -EIO; |
256 | } | 256 | } |
257 | return err; | 257 | return err; |
258 | } | 258 | } |
259 | 259 | ||
260 | static int logfs_read_segment(struct super_block *sb, u32 segno) | 260 | static int logfs_read_segment(struct super_block *sb, u32 segno) |
261 | { | 261 | { |
262 | struct logfs_super *super = logfs_super(sb); | 262 | struct logfs_super *super = logfs_super(sb); |
263 | struct logfs_journal_header *jh = super->s_compressed_je; | 263 | struct logfs_journal_header *jh = super->s_compressed_je; |
264 | u64 ofs, seg_ofs = dev_ofs(sb, segno, 0); | 264 | u64 ofs, seg_ofs = dev_ofs(sb, segno, 0); |
265 | u32 h_ofs, last_ofs = 0; | 265 | u32 h_ofs, last_ofs = 0; |
266 | u16 len, datalen, last_len = 0; | 266 | u16 len, datalen, last_len = 0; |
267 | int i, err; | 267 | int i, err; |
268 | 268 | ||
269 | /* search for most recent commit */ | 269 | /* search for most recent commit */ |
270 | for (h_ofs = 0; h_ofs < super->s_segsize; h_ofs += sizeof(*jh)) { | 270 | for (h_ofs = 0; h_ofs < super->s_segsize; h_ofs += sizeof(*jh)) { |
271 | ofs = seg_ofs + h_ofs; | 271 | ofs = seg_ofs + h_ofs; |
272 | err = __read_je_header(sb, ofs, jh); | 272 | err = __read_je_header(sb, ofs, jh); |
273 | if (err) | 273 | if (err) |
274 | continue; | 274 | continue; |
275 | if (jh->h_type != cpu_to_be16(JE_COMMIT)) | 275 | if (jh->h_type != cpu_to_be16(JE_COMMIT)) |
276 | continue; | 276 | continue; |
277 | err = __read_je_payload(sb, ofs, jh); | 277 | err = __read_je_payload(sb, ofs, jh); |
278 | if (err) | 278 | if (err) |
279 | continue; | 279 | continue; |
280 | len = be16_to_cpu(jh->h_len); | 280 | len = be16_to_cpu(jh->h_len); |
281 | datalen = be16_to_cpu(jh->h_datalen); | 281 | datalen = be16_to_cpu(jh->h_datalen); |
282 | if ((datalen > sizeof(super->s_je_array)) || | 282 | if ((datalen > sizeof(super->s_je_array)) || |
283 | (datalen % sizeof(__be64))) | 283 | (datalen % sizeof(__be64))) |
284 | continue; | 284 | continue; |
285 | last_ofs = h_ofs; | 285 | last_ofs = h_ofs; |
286 | last_len = datalen; | 286 | last_len = datalen; |
287 | h_ofs += ALIGN(len, sizeof(*jh)) - sizeof(*jh); | 287 | h_ofs += ALIGN(len, sizeof(*jh)) - sizeof(*jh); |
288 | } | 288 | } |
289 | /* read commit */ | 289 | /* read commit */ |
290 | if (last_ofs == 0) | 290 | if (last_ofs == 0) |
291 | return -ENOENT; | 291 | return -ENOENT; |
292 | ofs = seg_ofs + last_ofs; | 292 | ofs = seg_ofs + last_ofs; |
293 | log_journal("Read commit from %llx\n", ofs); | 293 | log_journal("Read commit from %llx\n", ofs); |
294 | err = __read_je(sb, ofs, jh); | 294 | err = __read_je(sb, ofs, jh); |
295 | BUG_ON(err); /* We should have caught it in the scan loop already */ | 295 | BUG_ON(err); /* We should have caught it in the scan loop already */ |
296 | if (err) | 296 | if (err) |
297 | return err; | 297 | return err; |
298 | /* uncompress */ | 298 | /* uncompress */ |
299 | unpack(jh, super->s_je_array); | 299 | unpack(jh, super->s_je_array); |
300 | super->s_no_je = last_len / sizeof(__be64); | 300 | super->s_no_je = last_len / sizeof(__be64); |
301 | /* iterate over array */ | 301 | /* iterate over array */ |
302 | for (i = 0; i < super->s_no_je; i++) { | 302 | for (i = 0; i < super->s_no_je; i++) { |
303 | err = read_je(sb, be64_to_cpu(super->s_je_array[i])); | 303 | err = read_je(sb, be64_to_cpu(super->s_je_array[i])); |
304 | if (err) | 304 | if (err) |
305 | return err; | 305 | return err; |
306 | } | 306 | } |
307 | super->s_journal_area->a_segno = segno; | 307 | super->s_journal_area->a_segno = segno; |
308 | return 0; | 308 | return 0; |
309 | } | 309 | } |
310 | 310 | ||
311 | static u64 read_gec(struct super_block *sb, u32 segno) | 311 | static u64 read_gec(struct super_block *sb, u32 segno) |
312 | { | 312 | { |
313 | struct logfs_segment_header sh; | 313 | struct logfs_segment_header sh; |
314 | __be32 crc; | 314 | __be32 crc; |
315 | int err; | 315 | int err; |
316 | 316 | ||
317 | if (!segno) | 317 | if (!segno) |
318 | return 0; | 318 | return 0; |
319 | err = wbuf_read(sb, dev_ofs(sb, segno, 0), sizeof(sh), &sh); | 319 | err = wbuf_read(sb, dev_ofs(sb, segno, 0), sizeof(sh), &sh); |
320 | if (err) | 320 | if (err) |
321 | return 0; | 321 | return 0; |
322 | crc = logfs_crc32(&sh, sizeof(sh), 4); | 322 | crc = logfs_crc32(&sh, sizeof(sh), 4); |
323 | if (crc != sh.crc) { | 323 | if (crc != sh.crc) { |
324 | WARN_ON(sh.gec != cpu_to_be64(0xffffffffffffffffull)); | 324 | WARN_ON(sh.gec != cpu_to_be64(0xffffffffffffffffull)); |
325 | /* Most likely it was just erased */ | 325 | /* Most likely it was just erased */ |
326 | return 0; | 326 | return 0; |
327 | } | 327 | } |
328 | return be64_to_cpu(sh.gec); | 328 | return be64_to_cpu(sh.gec); |
329 | } | 329 | } |
330 | 330 | ||
331 | static int logfs_read_journal(struct super_block *sb) | 331 | static int logfs_read_journal(struct super_block *sb) |
332 | { | 332 | { |
333 | struct logfs_super *super = logfs_super(sb); | 333 | struct logfs_super *super = logfs_super(sb); |
334 | u64 gec[LOGFS_JOURNAL_SEGS], max; | 334 | u64 gec[LOGFS_JOURNAL_SEGS], max; |
335 | u32 segno; | 335 | u32 segno; |
336 | int i, max_i; | 336 | int i, max_i; |
337 | 337 | ||
338 | max = 0; | 338 | max = 0; |
339 | max_i = -1; | 339 | max_i = -1; |
340 | journal_for_each(i) { | 340 | journal_for_each(i) { |
341 | segno = super->s_journal_seg[i]; | 341 | segno = super->s_journal_seg[i]; |
342 | gec[i] = read_gec(sb, super->s_journal_seg[i]); | 342 | gec[i] = read_gec(sb, super->s_journal_seg[i]); |
343 | if (gec[i] > max) { | 343 | if (gec[i] > max) { |
344 | max = gec[i]; | 344 | max = gec[i]; |
345 | max_i = i; | 345 | max_i = i; |
346 | } | 346 | } |
347 | } | 347 | } |
348 | if (max_i == -1) | 348 | if (max_i == -1) |
349 | return -EIO; | 349 | return -EIO; |
350 | /* FIXME: Try older segments in case of error */ | 350 | /* FIXME: Try older segments in case of error */ |
351 | return logfs_read_segment(sb, super->s_journal_seg[max_i]); | 351 | return logfs_read_segment(sb, super->s_journal_seg[max_i]); |
352 | } | 352 | } |
353 | 353 | ||
354 | /* | 354 | /* |
355 | * First search the current segment (outer loop), then pick the next segment | 355 | * First search the current segment (outer loop), then pick the next segment |
356 | * in the array, skipping any zero entries (inner loop). | 356 | * in the array, skipping any zero entries (inner loop). |
357 | */ | 357 | */ |
358 | static void journal_get_free_segment(struct logfs_area *area) | 358 | static void journal_get_free_segment(struct logfs_area *area) |
359 | { | 359 | { |
360 | struct logfs_super *super = logfs_super(area->a_sb); | 360 | struct logfs_super *super = logfs_super(area->a_sb); |
361 | int i; | 361 | int i; |
362 | 362 | ||
363 | journal_for_each(i) { | 363 | journal_for_each(i) { |
364 | if (area->a_segno != super->s_journal_seg[i]) | 364 | if (area->a_segno != super->s_journal_seg[i]) |
365 | continue; | 365 | continue; |
366 | 366 | ||
367 | do { | 367 | do { |
368 | i++; | 368 | i++; |
369 | if (i == LOGFS_JOURNAL_SEGS) | 369 | if (i == LOGFS_JOURNAL_SEGS) |
370 | i = 0; | 370 | i = 0; |
371 | } while (!super->s_journal_seg[i]); | 371 | } while (!super->s_journal_seg[i]); |
372 | 372 | ||
373 | area->a_segno = super->s_journal_seg[i]; | 373 | area->a_segno = super->s_journal_seg[i]; |
374 | area->a_erase_count = ++(super->s_journal_ec[i]); | 374 | area->a_erase_count = ++(super->s_journal_ec[i]); |
375 | log_journal("Journal now at %x (ec %x)\n", area->a_segno, | 375 | log_journal("Journal now at %x (ec %x)\n", area->a_segno, |
376 | area->a_erase_count); | 376 | area->a_erase_count); |
377 | return; | 377 | return; |
378 | } | 378 | } |
379 | BUG(); | 379 | BUG(); |
380 | } | 380 | } |
381 | 381 | ||
382 | static void journal_get_erase_count(struct logfs_area *area) | 382 | static void journal_get_erase_count(struct logfs_area *area) |
383 | { | 383 | { |
384 | /* erase count is stored globally and incremented in | 384 | /* erase count is stored globally and incremented in |
385 | * journal_get_free_segment() - nothing to do here */ | 385 | * journal_get_free_segment() - nothing to do here */ |
386 | } | 386 | } |
387 | 387 | ||
388 | static int journal_erase_segment(struct logfs_area *area) | 388 | static int journal_erase_segment(struct logfs_area *area) |
389 | { | 389 | { |
390 | struct super_block *sb = area->a_sb; | 390 | struct super_block *sb = area->a_sb; |
391 | struct logfs_segment_header sh; | 391 | struct logfs_segment_header sh; |
392 | u64 ofs; | 392 | u64 ofs; |
393 | int err; | 393 | int err; |
394 | 394 | ||
395 | err = logfs_erase_segment(sb, area->a_segno); | 395 | err = logfs_erase_segment(sb, area->a_segno, 1); |
396 | if (err) | 396 | if (err) |
397 | return err; | 397 | return err; |
398 | 398 | ||
399 | sh.pad = 0; | 399 | sh.pad = 0; |
400 | sh.type = SEG_JOURNAL; | 400 | sh.type = SEG_JOURNAL; |
401 | sh.level = 0; | 401 | sh.level = 0; |
402 | sh.segno = cpu_to_be32(area->a_segno); | 402 | sh.segno = cpu_to_be32(area->a_segno); |
403 | sh.ec = cpu_to_be32(area->a_erase_count); | 403 | sh.ec = cpu_to_be32(area->a_erase_count); |
404 | sh.gec = cpu_to_be64(logfs_super(sb)->s_gec); | 404 | sh.gec = cpu_to_be64(logfs_super(sb)->s_gec); |
405 | sh.crc = logfs_crc32(&sh, sizeof(sh), 4); | 405 | sh.crc = logfs_crc32(&sh, sizeof(sh), 4); |
406 | 406 | ||
407 | /* This causes a bug in segment.c. Not yet. */ | 407 | /* This causes a bug in segment.c. Not yet. */ |
408 | //logfs_set_segment_erased(sb, area->a_segno, area->a_erase_count, 0); | 408 | //logfs_set_segment_erased(sb, area->a_segno, area->a_erase_count, 0); |
409 | 409 | ||
410 | ofs = dev_ofs(sb, area->a_segno, 0); | 410 | ofs = dev_ofs(sb, area->a_segno, 0); |
411 | area->a_used_bytes = ALIGN(sizeof(sh), 16); | 411 | area->a_used_bytes = ALIGN(sizeof(sh), 16); |
412 | logfs_buf_write(area, ofs, &sh, sizeof(sh)); | 412 | logfs_buf_write(area, ofs, &sh, sizeof(sh)); |
413 | return 0; | 413 | return 0; |
414 | } | 414 | } |
415 | 415 | ||
416 | static size_t __logfs_write_header(struct logfs_super *super, | 416 | static size_t __logfs_write_header(struct logfs_super *super, |
417 | struct logfs_journal_header *jh, size_t len, size_t datalen, | 417 | struct logfs_journal_header *jh, size_t len, size_t datalen, |
418 | u16 type, u8 compr) | 418 | u16 type, u8 compr) |
419 | { | 419 | { |
420 | jh->h_len = cpu_to_be16(len); | 420 | jh->h_len = cpu_to_be16(len); |
421 | jh->h_type = cpu_to_be16(type); | 421 | jh->h_type = cpu_to_be16(type); |
422 | jh->h_version = cpu_to_be16(++super->s_last_version); | 422 | jh->h_version = cpu_to_be16(++super->s_last_version); |
423 | jh->h_datalen = cpu_to_be16(datalen); | 423 | jh->h_datalen = cpu_to_be16(datalen); |
424 | jh->h_compr = compr; | 424 | jh->h_compr = compr; |
425 | jh->h_pad[0] = 'H'; | 425 | jh->h_pad[0] = 'H'; |
426 | jh->h_pad[1] = 'A'; | 426 | jh->h_pad[1] = 'A'; |
427 | jh->h_pad[2] = 'T'; | 427 | jh->h_pad[2] = 'T'; |
428 | jh->h_crc = logfs_crc32(jh, len + sizeof(*jh), 4); | 428 | jh->h_crc = logfs_crc32(jh, len + sizeof(*jh), 4); |
429 | return ALIGN(len, 16) + sizeof(*jh); | 429 | return ALIGN(len, 16) + sizeof(*jh); |
430 | } | 430 | } |
431 | 431 | ||
432 | static size_t logfs_write_header(struct logfs_super *super, | 432 | static size_t logfs_write_header(struct logfs_super *super, |
433 | struct logfs_journal_header *jh, size_t datalen, u16 type) | 433 | struct logfs_journal_header *jh, size_t datalen, u16 type) |
434 | { | 434 | { |
435 | size_t len = datalen; | 435 | size_t len = datalen; |
436 | 436 | ||
437 | return __logfs_write_header(super, jh, len, datalen, type, COMPR_NONE); | 437 | return __logfs_write_header(super, jh, len, datalen, type, COMPR_NONE); |
438 | } | 438 | } |
439 | 439 | ||
440 | static inline size_t logfs_journal_erasecount_size(struct logfs_super *super) | 440 | static inline size_t logfs_journal_erasecount_size(struct logfs_super *super) |
441 | { | 441 | { |
442 | return LOGFS_JOURNAL_SEGS * sizeof(__be32); | 442 | return LOGFS_JOURNAL_SEGS * sizeof(__be32); |
443 | } | 443 | } |
444 | 444 | ||
445 | static void *logfs_write_erasecount(struct super_block *sb, void *_ec, | 445 | static void *logfs_write_erasecount(struct super_block *sb, void *_ec, |
446 | u16 *type, size_t *len) | 446 | u16 *type, size_t *len) |
447 | { | 447 | { |
448 | struct logfs_super *super = logfs_super(sb); | 448 | struct logfs_super *super = logfs_super(sb); |
449 | struct logfs_je_journal_ec *ec = _ec; | 449 | struct logfs_je_journal_ec *ec = _ec; |
450 | int i; | 450 | int i; |
451 | 451 | ||
452 | journal_for_each(i) | 452 | journal_for_each(i) |
453 | ec->ec[i] = cpu_to_be32(super->s_journal_ec[i]); | 453 | ec->ec[i] = cpu_to_be32(super->s_journal_ec[i]); |
454 | *type = JE_ERASECOUNT; | 454 | *type = JE_ERASECOUNT; |
455 | *len = logfs_journal_erasecount_size(super); | 455 | *len = logfs_journal_erasecount_size(super); |
456 | return ec; | 456 | return ec; |
457 | } | 457 | } |
458 | 458 | ||
459 | static void account_shadow(void *_shadow, unsigned long _sb, u64 ignore, | 459 | static void account_shadow(void *_shadow, unsigned long _sb, u64 ignore, |
460 | size_t ignore2) | 460 | size_t ignore2) |
461 | { | 461 | { |
462 | struct logfs_shadow *shadow = _shadow; | 462 | struct logfs_shadow *shadow = _shadow; |
463 | struct super_block *sb = (void *)_sb; | 463 | struct super_block *sb = (void *)_sb; |
464 | struct logfs_super *super = logfs_super(sb); | 464 | struct logfs_super *super = logfs_super(sb); |
465 | 465 | ||
466 | /* consume new space */ | 466 | /* consume new space */ |
467 | super->s_free_bytes -= shadow->new_len; | 467 | super->s_free_bytes -= shadow->new_len; |
468 | super->s_used_bytes += shadow->new_len; | 468 | super->s_used_bytes += shadow->new_len; |
469 | super->s_dirty_used_bytes -= shadow->new_len; | 469 | super->s_dirty_used_bytes -= shadow->new_len; |
470 | 470 | ||
471 | /* free up old space */ | 471 | /* free up old space */ |
472 | super->s_free_bytes += shadow->old_len; | 472 | super->s_free_bytes += shadow->old_len; |
473 | super->s_used_bytes -= shadow->old_len; | 473 | super->s_used_bytes -= shadow->old_len; |
474 | super->s_dirty_free_bytes -= shadow->old_len; | 474 | super->s_dirty_free_bytes -= shadow->old_len; |
475 | 475 | ||
476 | logfs_set_segment_used(sb, shadow->old_ofs, -shadow->old_len); | 476 | logfs_set_segment_used(sb, shadow->old_ofs, -shadow->old_len); |
477 | logfs_set_segment_used(sb, shadow->new_ofs, shadow->new_len); | 477 | logfs_set_segment_used(sb, shadow->new_ofs, shadow->new_len); |
478 | 478 | ||
479 | log_journal("account_shadow(%llx, %llx, %x) %llx->%llx %x->%x\n", | 479 | log_journal("account_shadow(%llx, %llx, %x) %llx->%llx %x->%x\n", |
480 | shadow->ino, shadow->bix, shadow->gc_level, | 480 | shadow->ino, shadow->bix, shadow->gc_level, |
481 | shadow->old_ofs, shadow->new_ofs, | 481 | shadow->old_ofs, shadow->new_ofs, |
482 | shadow->old_len, shadow->new_len); | 482 | shadow->old_len, shadow->new_len); |
483 | mempool_free(shadow, super->s_shadow_pool); | 483 | mempool_free(shadow, super->s_shadow_pool); |
484 | } | 484 | } |
485 | 485 | ||
486 | static void account_shadows(struct super_block *sb) | 486 | static void account_shadows(struct super_block *sb) |
487 | { | 487 | { |
488 | struct logfs_super *super = logfs_super(sb); | 488 | struct logfs_super *super = logfs_super(sb); |
489 | struct inode *inode = super->s_master_inode; | 489 | struct inode *inode = super->s_master_inode; |
490 | struct logfs_inode *li = logfs_inode(inode); | 490 | struct logfs_inode *li = logfs_inode(inode); |
491 | struct shadow_tree *tree = &super->s_shadow_tree; | 491 | struct shadow_tree *tree = &super->s_shadow_tree; |
492 | 492 | ||
493 | btree_grim_visitor64(&tree->new, (unsigned long)sb, account_shadow); | 493 | btree_grim_visitor64(&tree->new, (unsigned long)sb, account_shadow); |
494 | btree_grim_visitor64(&tree->old, (unsigned long)sb, account_shadow); | 494 | btree_grim_visitor64(&tree->old, (unsigned long)sb, account_shadow); |
495 | 495 | ||
496 | if (li->li_block) { | 496 | if (li->li_block) { |
497 | /* | 497 | /* |
498 | * We never actually use the structure, when attached to the | 498 | * We never actually use the structure, when attached to the |
499 | * master inode. But it is easier to always free it here than | 499 | * master inode. But it is easier to always free it here than |
500 | * to have checks in several places elsewhere when allocating | 500 | * to have checks in several places elsewhere when allocating |
501 | * it. | 501 | * it. |
502 | */ | 502 | */ |
503 | li->li_block->ops->free_block(sb, li->li_block); | 503 | li->li_block->ops->free_block(sb, li->li_block); |
504 | } | 504 | } |
505 | BUG_ON((s64)li->li_used_bytes < 0); | 505 | BUG_ON((s64)li->li_used_bytes < 0); |
506 | } | 506 | } |
507 | 507 | ||
508 | static void *__logfs_write_anchor(struct super_block *sb, void *_da, | 508 | static void *__logfs_write_anchor(struct super_block *sb, void *_da, |
509 | u16 *type, size_t *len) | 509 | u16 *type, size_t *len) |
510 | { | 510 | { |
511 | struct logfs_super *super = logfs_super(sb); | 511 | struct logfs_super *super = logfs_super(sb); |
512 | struct logfs_je_anchor *da = _da; | 512 | struct logfs_je_anchor *da = _da; |
513 | struct inode *inode = super->s_master_inode; | 513 | struct inode *inode = super->s_master_inode; |
514 | struct logfs_inode *li = logfs_inode(inode); | 514 | struct logfs_inode *li = logfs_inode(inode); |
515 | int i; | 515 | int i; |
516 | 516 | ||
517 | da->da_height = li->li_height; | 517 | da->da_height = li->li_height; |
518 | da->da_last_ino = cpu_to_be64(super->s_last_ino); | 518 | da->da_last_ino = cpu_to_be64(super->s_last_ino); |
519 | da->da_size = cpu_to_be64(i_size_read(inode)); | 519 | da->da_size = cpu_to_be64(i_size_read(inode)); |
520 | da->da_used_bytes = cpu_to_be64(li->li_used_bytes); | 520 | da->da_used_bytes = cpu_to_be64(li->li_used_bytes); |
521 | for (i = 0; i < LOGFS_EMBEDDED_FIELDS; i++) | 521 | for (i = 0; i < LOGFS_EMBEDDED_FIELDS; i++) |
522 | da->da_data[i] = cpu_to_be64(li->li_data[i]); | 522 | da->da_data[i] = cpu_to_be64(li->li_data[i]); |
523 | *type = JE_ANCHOR; | 523 | *type = JE_ANCHOR; |
524 | *len = sizeof(*da); | 524 | *len = sizeof(*da); |
525 | return da; | 525 | return da; |
526 | } | 526 | } |
527 | 527 | ||
528 | static void *logfs_write_dynsb(struct super_block *sb, void *_dynsb, | 528 | static void *logfs_write_dynsb(struct super_block *sb, void *_dynsb, |
529 | u16 *type, size_t *len) | 529 | u16 *type, size_t *len) |
530 | { | 530 | { |
531 | struct logfs_super *super = logfs_super(sb); | 531 | struct logfs_super *super = logfs_super(sb); |
532 | struct logfs_je_dynsb *dynsb = _dynsb; | 532 | struct logfs_je_dynsb *dynsb = _dynsb; |
533 | 533 | ||
534 | dynsb->ds_gec = cpu_to_be64(super->s_gec); | 534 | dynsb->ds_gec = cpu_to_be64(super->s_gec); |
535 | dynsb->ds_sweeper = cpu_to_be64(super->s_sweeper); | 535 | dynsb->ds_sweeper = cpu_to_be64(super->s_sweeper); |
536 | dynsb->ds_victim_ino = cpu_to_be64(super->s_victim_ino); | 536 | dynsb->ds_victim_ino = cpu_to_be64(super->s_victim_ino); |
537 | dynsb->ds_rename_dir = cpu_to_be64(super->s_rename_dir); | 537 | dynsb->ds_rename_dir = cpu_to_be64(super->s_rename_dir); |
538 | dynsb->ds_rename_pos = cpu_to_be64(super->s_rename_pos); | 538 | dynsb->ds_rename_pos = cpu_to_be64(super->s_rename_pos); |
539 | dynsb->ds_used_bytes = cpu_to_be64(super->s_used_bytes); | 539 | dynsb->ds_used_bytes = cpu_to_be64(super->s_used_bytes); |
540 | dynsb->ds_generation = cpu_to_be32(super->s_generation); | 540 | dynsb->ds_generation = cpu_to_be32(super->s_generation); |
541 | *type = JE_DYNSB; | 541 | *type = JE_DYNSB; |
542 | *len = sizeof(*dynsb); | 542 | *len = sizeof(*dynsb); |
543 | return dynsb; | 543 | return dynsb; |
544 | } | 544 | } |
545 | 545 | ||
546 | static void write_wbuf(struct super_block *sb, struct logfs_area *area, | 546 | static void write_wbuf(struct super_block *sb, struct logfs_area *area, |
547 | void *wbuf) | 547 | void *wbuf) |
548 | { | 548 | { |
549 | struct logfs_super *super = logfs_super(sb); | 549 | struct logfs_super *super = logfs_super(sb); |
550 | struct address_space *mapping = super->s_mapping_inode->i_mapping; | 550 | struct address_space *mapping = super->s_mapping_inode->i_mapping; |
551 | u64 ofs; | 551 | u64 ofs; |
552 | pgoff_t index; | 552 | pgoff_t index; |
553 | int page_ofs; | 553 | int page_ofs; |
554 | struct page *page; | 554 | struct page *page; |
555 | 555 | ||
556 | ofs = dev_ofs(sb, area->a_segno, | 556 | ofs = dev_ofs(sb, area->a_segno, |
557 | area->a_used_bytes & ~(super->s_writesize - 1)); | 557 | area->a_used_bytes & ~(super->s_writesize - 1)); |
558 | index = ofs >> PAGE_SHIFT; | 558 | index = ofs >> PAGE_SHIFT; |
559 | page_ofs = ofs & (PAGE_SIZE - 1); | 559 | page_ofs = ofs & (PAGE_SIZE - 1); |
560 | 560 | ||
561 | page = find_lock_page(mapping, index); | 561 | page = find_lock_page(mapping, index); |
562 | BUG_ON(!page); | 562 | BUG_ON(!page); |
563 | memcpy(wbuf, page_address(page) + page_ofs, super->s_writesize); | 563 | memcpy(wbuf, page_address(page) + page_ofs, super->s_writesize); |
564 | unlock_page(page); | 564 | unlock_page(page); |
565 | } | 565 | } |
566 | 566 | ||
567 | static void *logfs_write_area(struct super_block *sb, void *_a, | 567 | static void *logfs_write_area(struct super_block *sb, void *_a, |
568 | u16 *type, size_t *len) | 568 | u16 *type, size_t *len) |
569 | { | 569 | { |
570 | struct logfs_super *super = logfs_super(sb); | 570 | struct logfs_super *super = logfs_super(sb); |
571 | struct logfs_area *area = super->s_area[super->s_sum_index]; | 571 | struct logfs_area *area = super->s_area[super->s_sum_index]; |
572 | struct logfs_je_area *a = _a; | 572 | struct logfs_je_area *a = _a; |
573 | 573 | ||
574 | a->vim = VIM_DEFAULT; | 574 | a->vim = VIM_DEFAULT; |
575 | a->gc_level = super->s_sum_index; | 575 | a->gc_level = super->s_sum_index; |
576 | a->used_bytes = cpu_to_be32(area->a_used_bytes); | 576 | a->used_bytes = cpu_to_be32(area->a_used_bytes); |
577 | a->segno = cpu_to_be32(area->a_segno); | 577 | a->segno = cpu_to_be32(area->a_segno); |
578 | if (super->s_writesize > 1) | 578 | if (super->s_writesize > 1) |
579 | write_wbuf(sb, area, a + 1); | 579 | write_wbuf(sb, area, a + 1); |
580 | 580 | ||
581 | *type = JE_AREA; | 581 | *type = JE_AREA; |
582 | *len = sizeof(*a) + super->s_writesize; | 582 | *len = sizeof(*a) + super->s_writesize; |
583 | return a; | 583 | return a; |
584 | } | 584 | } |
585 | 585 | ||
586 | static void *logfs_write_commit(struct super_block *sb, void *h, | 586 | static void *logfs_write_commit(struct super_block *sb, void *h, |
587 | u16 *type, size_t *len) | 587 | u16 *type, size_t *len) |
588 | { | 588 | { |
589 | struct logfs_super *super = logfs_super(sb); | 589 | struct logfs_super *super = logfs_super(sb); |
590 | 590 | ||
591 | *type = JE_COMMIT; | 591 | *type = JE_COMMIT; |
592 | *len = super->s_no_je * sizeof(__be64); | 592 | *len = super->s_no_je * sizeof(__be64); |
593 | return super->s_je_array; | 593 | return super->s_je_array; |
594 | } | 594 | } |
595 | 595 | ||
596 | static size_t __logfs_write_je(struct super_block *sb, void *buf, u16 type, | 596 | static size_t __logfs_write_je(struct super_block *sb, void *buf, u16 type, |
597 | size_t len) | 597 | size_t len) |
598 | { | 598 | { |
599 | struct logfs_super *super = logfs_super(sb); | 599 | struct logfs_super *super = logfs_super(sb); |
600 | void *header = super->s_compressed_je; | 600 | void *header = super->s_compressed_je; |
601 | void *data = header + sizeof(struct logfs_journal_header); | 601 | void *data = header + sizeof(struct logfs_journal_header); |
602 | ssize_t compr_len, pad_len; | 602 | ssize_t compr_len, pad_len; |
603 | u8 compr = COMPR_ZLIB; | 603 | u8 compr = COMPR_ZLIB; |
604 | 604 | ||
605 | if (len == 0) | 605 | if (len == 0) |
606 | return logfs_write_header(super, header, 0, type); | 606 | return logfs_write_header(super, header, 0, type); |
607 | 607 | ||
608 | compr_len = logfs_compress(buf, data, len, sb->s_blocksize); | 608 | compr_len = logfs_compress(buf, data, len, sb->s_blocksize); |
609 | if (compr_len < 0 || type == JE_ANCHOR) { | 609 | if (compr_len < 0 || type == JE_ANCHOR) { |
610 | BUG_ON(len > sb->s_blocksize); | 610 | BUG_ON(len > sb->s_blocksize); |
611 | memcpy(data, buf, len); | 611 | memcpy(data, buf, len); |
612 | compr_len = len; | 612 | compr_len = len; |
613 | compr = COMPR_NONE; | 613 | compr = COMPR_NONE; |
614 | } | 614 | } |
615 | 615 | ||
616 | pad_len = ALIGN(compr_len, 16); | 616 | pad_len = ALIGN(compr_len, 16); |
617 | memset(data + compr_len, 0, pad_len - compr_len); | 617 | memset(data + compr_len, 0, pad_len - compr_len); |
618 | 618 | ||
619 | return __logfs_write_header(super, header, compr_len, len, type, compr); | 619 | return __logfs_write_header(super, header, compr_len, len, type, compr); |
620 | } | 620 | } |
621 | 621 | ||
622 | static s64 logfs_get_free_bytes(struct logfs_area *area, size_t *bytes, | 622 | static s64 logfs_get_free_bytes(struct logfs_area *area, size_t *bytes, |
623 | int must_pad) | 623 | int must_pad) |
624 | { | 624 | { |
625 | u32 writesize = logfs_super(area->a_sb)->s_writesize; | 625 | u32 writesize = logfs_super(area->a_sb)->s_writesize; |
626 | s32 ofs; | 626 | s32 ofs; |
627 | int ret; | 627 | int ret; |
628 | 628 | ||
629 | ret = logfs_open_area(area, *bytes); | 629 | ret = logfs_open_area(area, *bytes); |
630 | if (ret) | 630 | if (ret) |
631 | return -EAGAIN; | 631 | return -EAGAIN; |
632 | 632 | ||
633 | ofs = area->a_used_bytes; | 633 | ofs = area->a_used_bytes; |
634 | area->a_used_bytes += *bytes; | 634 | area->a_used_bytes += *bytes; |
635 | 635 | ||
636 | if (must_pad) { | 636 | if (must_pad) { |
637 | area->a_used_bytes = ALIGN(area->a_used_bytes, writesize); | 637 | area->a_used_bytes = ALIGN(area->a_used_bytes, writesize); |
638 | *bytes = area->a_used_bytes - ofs; | 638 | *bytes = area->a_used_bytes - ofs; |
639 | } | 639 | } |
640 | 640 | ||
641 | return dev_ofs(area->a_sb, area->a_segno, ofs); | 641 | return dev_ofs(area->a_sb, area->a_segno, ofs); |
642 | } | 642 | } |
643 | 643 | ||
644 | static int logfs_write_je_buf(struct super_block *sb, void *buf, u16 type, | 644 | static int logfs_write_je_buf(struct super_block *sb, void *buf, u16 type, |
645 | size_t buf_len) | 645 | size_t buf_len) |
646 | { | 646 | { |
647 | struct logfs_super *super = logfs_super(sb); | 647 | struct logfs_super *super = logfs_super(sb); |
648 | struct logfs_area *area = super->s_journal_area; | 648 | struct logfs_area *area = super->s_journal_area; |
649 | struct logfs_journal_header *jh = super->s_compressed_je; | 649 | struct logfs_journal_header *jh = super->s_compressed_je; |
650 | size_t len; | 650 | size_t len; |
651 | int must_pad = 0; | 651 | int must_pad = 0; |
652 | s64 ofs; | 652 | s64 ofs; |
653 | 653 | ||
654 | len = __logfs_write_je(sb, buf, type, buf_len); | 654 | len = __logfs_write_je(sb, buf, type, buf_len); |
655 | if (jh->h_type == cpu_to_be16(JE_COMMIT)) | 655 | if (jh->h_type == cpu_to_be16(JE_COMMIT)) |
656 | must_pad = 1; | 656 | must_pad = 1; |
657 | 657 | ||
658 | ofs = logfs_get_free_bytes(area, &len, must_pad); | 658 | ofs = logfs_get_free_bytes(area, &len, must_pad); |
659 | if (ofs < 0) | 659 | if (ofs < 0) |
660 | return ofs; | 660 | return ofs; |
661 | logfs_buf_write(area, ofs, super->s_compressed_je, len); | 661 | logfs_buf_write(area, ofs, super->s_compressed_je, len); |
662 | super->s_je_array[super->s_no_je++] = cpu_to_be64(ofs); | 662 | super->s_je_array[super->s_no_je++] = cpu_to_be64(ofs); |
663 | return 0; | 663 | return 0; |
664 | } | 664 | } |
665 | 665 | ||
666 | static int logfs_write_je(struct super_block *sb, | 666 | static int logfs_write_je(struct super_block *sb, |
667 | void* (*write)(struct super_block *sb, void *scratch, | 667 | void* (*write)(struct super_block *sb, void *scratch, |
668 | u16 *type, size_t *len)) | 668 | u16 *type, size_t *len)) |
669 | { | 669 | { |
670 | void *buf; | 670 | void *buf; |
671 | size_t len; | 671 | size_t len; |
672 | u16 type; | 672 | u16 type; |
673 | 673 | ||
674 | buf = write(sb, logfs_super(sb)->s_je, &type, &len); | 674 | buf = write(sb, logfs_super(sb)->s_je, &type, &len); |
675 | return logfs_write_je_buf(sb, buf, type, len); | 675 | return logfs_write_je_buf(sb, buf, type, len); |
676 | } | 676 | } |
677 | 677 | ||
678 | int write_alias_journal(struct super_block *sb, u64 ino, u64 bix, | 678 | int write_alias_journal(struct super_block *sb, u64 ino, u64 bix, |
679 | level_t level, int child_no, __be64 val) | 679 | level_t level, int child_no, __be64 val) |
680 | { | 680 | { |
681 | struct logfs_super *super = logfs_super(sb); | 681 | struct logfs_super *super = logfs_super(sb); |
682 | struct logfs_obj_alias *oa = super->s_je; | 682 | struct logfs_obj_alias *oa = super->s_je; |
683 | int err = 0, fill = super->s_je_fill; | 683 | int err = 0, fill = super->s_je_fill; |
684 | 684 | ||
685 | log_aliases("logfs_write_obj_aliases #%x(%llx, %llx, %x, %x) %llx\n", | 685 | log_aliases("logfs_write_obj_aliases #%x(%llx, %llx, %x, %x) %llx\n", |
686 | fill, ino, bix, level, child_no, be64_to_cpu(val)); | 686 | fill, ino, bix, level, child_no, be64_to_cpu(val)); |
687 | oa[fill].ino = cpu_to_be64(ino); | 687 | oa[fill].ino = cpu_to_be64(ino); |
688 | oa[fill].bix = cpu_to_be64(bix); | 688 | oa[fill].bix = cpu_to_be64(bix); |
689 | oa[fill].val = val; | 689 | oa[fill].val = val; |
690 | oa[fill].level = (__force u8)level; | 690 | oa[fill].level = (__force u8)level; |
691 | oa[fill].child_no = cpu_to_be16(child_no); | 691 | oa[fill].child_no = cpu_to_be16(child_no); |
692 | fill++; | 692 | fill++; |
693 | if (fill >= sb->s_blocksize / sizeof(*oa)) { | 693 | if (fill >= sb->s_blocksize / sizeof(*oa)) { |
694 | err = logfs_write_je_buf(sb, oa, JE_OBJ_ALIAS, sb->s_blocksize); | 694 | err = logfs_write_je_buf(sb, oa, JE_OBJ_ALIAS, sb->s_blocksize); |
695 | fill = 0; | 695 | fill = 0; |
696 | } | 696 | } |
697 | 697 | ||
698 | super->s_je_fill = fill; | 698 | super->s_je_fill = fill; |
699 | return err; | 699 | return err; |
700 | } | 700 | } |
701 | 701 | ||
702 | static int logfs_write_obj_aliases(struct super_block *sb) | 702 | static int logfs_write_obj_aliases(struct super_block *sb) |
703 | { | 703 | { |
704 | struct logfs_super *super = logfs_super(sb); | 704 | struct logfs_super *super = logfs_super(sb); |
705 | int err; | 705 | int err; |
706 | 706 | ||
707 | log_journal("logfs_write_obj_aliases: %d aliases to write\n", | 707 | log_journal("logfs_write_obj_aliases: %d aliases to write\n", |
708 | super->s_no_object_aliases); | 708 | super->s_no_object_aliases); |
709 | super->s_je_fill = 0; | 709 | super->s_je_fill = 0; |
710 | err = logfs_write_obj_aliases_pagecache(sb); | 710 | err = logfs_write_obj_aliases_pagecache(sb); |
711 | if (err) | 711 | if (err) |
712 | return err; | 712 | return err; |
713 | 713 | ||
714 | if (super->s_je_fill) | 714 | if (super->s_je_fill) |
715 | err = logfs_write_je_buf(sb, super->s_je, JE_OBJ_ALIAS, | 715 | err = logfs_write_je_buf(sb, super->s_je, JE_OBJ_ALIAS, |
716 | super->s_je_fill | 716 | super->s_je_fill |
717 | * sizeof(struct logfs_obj_alias)); | 717 | * sizeof(struct logfs_obj_alias)); |
718 | return err; | 718 | return err; |
719 | } | 719 | } |
720 | 720 | ||
721 | /* | 721 | /* |
722 | * Write all journal entries. The goto logic ensures that all journal entries | 722 | * Write all journal entries. The goto logic ensures that all journal entries |
723 | * are written whenever a new segment is used. It is ugly and potentially a | 723 | * are written whenever a new segment is used. It is ugly and potentially a |
724 | * bit wasteful, but robustness is more important. With this we can *always* | 724 | * bit wasteful, but robustness is more important. With this we can *always* |
725 | * erase all journal segments except the one containing the most recent commit. | 725 | * erase all journal segments except the one containing the most recent commit. |
726 | */ | 726 | */ |
727 | void logfs_write_anchor(struct inode *inode) | 727 | void logfs_write_anchor(struct inode *inode) |
728 | { | 728 | { |
729 | struct super_block *sb = inode->i_sb; | 729 | struct super_block *sb = inode->i_sb; |
730 | struct logfs_super *super = logfs_super(sb); | 730 | struct logfs_super *super = logfs_super(sb); |
731 | struct logfs_area *area = super->s_journal_area; | 731 | struct logfs_area *area = super->s_journal_area; |
732 | int i, err; | 732 | int i, err; |
733 | 733 | ||
734 | BUG_ON(logfs_super(sb)->s_flags & LOGFS_SB_FLAG_SHUTDOWN); | 734 | BUG_ON(logfs_super(sb)->s_flags & LOGFS_SB_FLAG_SHUTDOWN); |
735 | mutex_lock(&super->s_journal_mutex); | 735 | mutex_lock(&super->s_journal_mutex); |
736 | 736 | ||
737 | /* Do this first or suffer corruption */ | 737 | /* Do this first or suffer corruption */ |
738 | logfs_sync_segments(sb); | 738 | logfs_sync_segments(sb); |
739 | account_shadows(sb); | 739 | account_shadows(sb); |
740 | 740 | ||
741 | again: | 741 | again: |
742 | super->s_no_je = 0; | 742 | super->s_no_je = 0; |
743 | for_each_area(i) { | 743 | for_each_area(i) { |
744 | if (!super->s_area[i]->a_is_open) | 744 | if (!super->s_area[i]->a_is_open) |
745 | continue; | 745 | continue; |
746 | super->s_sum_index = i; | 746 | super->s_sum_index = i; |
747 | err = logfs_write_je(sb, logfs_write_area); | 747 | err = logfs_write_je(sb, logfs_write_area); |
748 | if (err) | 748 | if (err) |
749 | goto again; | 749 | goto again; |
750 | } | 750 | } |
751 | err = logfs_write_obj_aliases(sb); | 751 | err = logfs_write_obj_aliases(sb); |
752 | if (err) | 752 | if (err) |
753 | goto again; | 753 | goto again; |
754 | err = logfs_write_je(sb, logfs_write_erasecount); | 754 | err = logfs_write_je(sb, logfs_write_erasecount); |
755 | if (err) | 755 | if (err) |
756 | goto again; | 756 | goto again; |
757 | err = logfs_write_je(sb, __logfs_write_anchor); | 757 | err = logfs_write_je(sb, __logfs_write_anchor); |
758 | if (err) | 758 | if (err) |
759 | goto again; | 759 | goto again; |
760 | err = logfs_write_je(sb, logfs_write_dynsb); | 760 | err = logfs_write_je(sb, logfs_write_dynsb); |
761 | if (err) | 761 | if (err) |
762 | goto again; | 762 | goto again; |
763 | /* | 763 | /* |
764 | * Order is imperative. First we sync all writes, including the | 764 | * Order is imperative. First we sync all writes, including the |
765 | * non-committed journal writes. Then we write the final commit and | 765 | * non-committed journal writes. Then we write the final commit and |
766 | * sync the current journal segment. | 766 | * sync the current journal segment. |
767 | * There is a theoretical bug here. Syncing the journal segment will | 767 | * There is a theoretical bug here. Syncing the journal segment will |
768 | * write a number of journal entries and the final commit. All these | 768 | * write a number of journal entries and the final commit. All these |
769 | * are written in a single operation. If the device layer writes the | 769 | * are written in a single operation. If the device layer writes the |
770 | * data back-to-front, the commit will precede the other journal | 770 | * data back-to-front, the commit will precede the other journal |
771 | * entries, leaving a race window. | 771 | * entries, leaving a race window. |
772 | * Two fixes are possible. Preferred is to fix the device layer to | 772 | * Two fixes are possible. Preferred is to fix the device layer to |
773 | * ensure writes happen front-to-back. Alternatively we can insert | 773 | * ensure writes happen front-to-back. Alternatively we can insert |
774 | * another logfs_sync_area() super->s_devops->sync() combo before | 774 | * another logfs_sync_area() super->s_devops->sync() combo before |
775 | * writing the commit. | 775 | * writing the commit. |
776 | */ | 776 | */ |
777 | /* | 777 | /* |
778 | * On another subject, super->s_devops->sync is usually not necessary. | 778 | * On another subject, super->s_devops->sync is usually not necessary. |
779 | * Unless called from sys_sync or friends, a barrier would suffice. | 779 | * Unless called from sys_sync or friends, a barrier would suffice. |
780 | */ | 780 | */ |
781 | super->s_devops->sync(sb); | 781 | super->s_devops->sync(sb); |
782 | err = logfs_write_je(sb, logfs_write_commit); | 782 | err = logfs_write_je(sb, logfs_write_commit); |
783 | if (err) | 783 | if (err) |
784 | goto again; | 784 | goto again; |
785 | log_journal("Write commit to %llx\n", | 785 | log_journal("Write commit to %llx\n", |
786 | be64_to_cpu(super->s_je_array[super->s_no_je - 1])); | 786 | be64_to_cpu(super->s_je_array[super->s_no_je - 1])); |
787 | logfs_sync_area(area); | 787 | logfs_sync_area(area); |
788 | BUG_ON(area->a_used_bytes != area->a_written_bytes); | 788 | BUG_ON(area->a_used_bytes != area->a_written_bytes); |
789 | super->s_devops->sync(sb); | 789 | super->s_devops->sync(sb); |
790 | 790 | ||
791 | mutex_unlock(&super->s_journal_mutex); | 791 | mutex_unlock(&super->s_journal_mutex); |
792 | return; | 792 | return; |
793 | } | 793 | } |
794 | 794 | ||
795 | void do_logfs_journal_wl_pass(struct super_block *sb) | 795 | void do_logfs_journal_wl_pass(struct super_block *sb) |
796 | { | 796 | { |
797 | struct logfs_super *super = logfs_super(sb); | 797 | struct logfs_super *super = logfs_super(sb); |
798 | struct logfs_area *area = super->s_journal_area; | 798 | struct logfs_area *area = super->s_journal_area; |
799 | u32 segno, ec; | 799 | u32 segno, ec; |
800 | int i, err; | 800 | int i, err; |
801 | 801 | ||
802 | log_journal("Journal requires wear-leveling.\n"); | 802 | log_journal("Journal requires wear-leveling.\n"); |
803 | /* Drop old segments */ | 803 | /* Drop old segments */ |
804 | journal_for_each(i) | 804 | journal_for_each(i) |
805 | if (super->s_journal_seg[i]) { | 805 | if (super->s_journal_seg[i]) { |
806 | logfs_set_segment_unreserved(sb, | 806 | logfs_set_segment_unreserved(sb, |
807 | super->s_journal_seg[i], | 807 | super->s_journal_seg[i], |
808 | super->s_journal_ec[i]); | 808 | super->s_journal_ec[i]); |
809 | super->s_journal_seg[i] = 0; | 809 | super->s_journal_seg[i] = 0; |
810 | super->s_journal_ec[i] = 0; | 810 | super->s_journal_ec[i] = 0; |
811 | } | 811 | } |
812 | /* Get new segments */ | 812 | /* Get new segments */ |
813 | for (i = 0; i < super->s_no_journal_segs; i++) { | 813 | for (i = 0; i < super->s_no_journal_segs; i++) { |
814 | segno = get_best_cand(sb, &super->s_reserve_list, &ec); | 814 | segno = get_best_cand(sb, &super->s_reserve_list, &ec); |
815 | super->s_journal_seg[i] = segno; | 815 | super->s_journal_seg[i] = segno; |
816 | super->s_journal_ec[i] = ec; | 816 | super->s_journal_ec[i] = ec; |
817 | logfs_set_segment_reserved(sb, segno); | 817 | logfs_set_segment_reserved(sb, segno); |
818 | } | 818 | } |
819 | /* Manually move journal_area */ | 819 | /* Manually move journal_area */ |
820 | area->a_segno = super->s_journal_seg[0]; | 820 | area->a_segno = super->s_journal_seg[0]; |
821 | area->a_is_open = 0; | 821 | area->a_is_open = 0; |
822 | area->a_used_bytes = 0; | 822 | area->a_used_bytes = 0; |
823 | /* Write journal */ | 823 | /* Write journal */ |
824 | logfs_write_anchor(super->s_master_inode); | 824 | logfs_write_anchor(super->s_master_inode); |
825 | /* Write superblocks */ | 825 | /* Write superblocks */ |
826 | err = logfs_write_sb(sb); | 826 | err = logfs_write_sb(sb); |
827 | BUG_ON(err); | 827 | BUG_ON(err); |
828 | } | 828 | } |
829 | 829 | ||
830 | static const struct logfs_area_ops journal_area_ops = { | 830 | static const struct logfs_area_ops journal_area_ops = { |
831 | .get_free_segment = journal_get_free_segment, | 831 | .get_free_segment = journal_get_free_segment, |
832 | .get_erase_count = journal_get_erase_count, | 832 | .get_erase_count = journal_get_erase_count, |
833 | .erase_segment = journal_erase_segment, | 833 | .erase_segment = journal_erase_segment, |
834 | }; | 834 | }; |
835 | 835 | ||
836 | int logfs_init_journal(struct super_block *sb) | 836 | int logfs_init_journal(struct super_block *sb) |
837 | { | 837 | { |
838 | struct logfs_super *super = logfs_super(sb); | 838 | struct logfs_super *super = logfs_super(sb); |
839 | size_t bufsize = max_t(size_t, sb->s_blocksize, super->s_writesize) | 839 | size_t bufsize = max_t(size_t, sb->s_blocksize, super->s_writesize) |
840 | + MAX_JOURNAL_HEADER; | 840 | + MAX_JOURNAL_HEADER; |
841 | int ret = -ENOMEM; | 841 | int ret = -ENOMEM; |
842 | 842 | ||
843 | mutex_init(&super->s_journal_mutex); | 843 | mutex_init(&super->s_journal_mutex); |
844 | btree_init_mempool32(&super->s_reserved_segments, super->s_btree_pool); | 844 | btree_init_mempool32(&super->s_reserved_segments, super->s_btree_pool); |
845 | 845 | ||
846 | super->s_je = kzalloc(bufsize, GFP_KERNEL); | 846 | super->s_je = kzalloc(bufsize, GFP_KERNEL); |
847 | if (!super->s_je) | 847 | if (!super->s_je) |
848 | return ret; | 848 | return ret; |
849 | 849 | ||
850 | super->s_compressed_je = kzalloc(bufsize, GFP_KERNEL); | 850 | super->s_compressed_je = kzalloc(bufsize, GFP_KERNEL); |
851 | if (!super->s_compressed_je) | 851 | if (!super->s_compressed_je) |
852 | return ret; | 852 | return ret; |
853 | 853 | ||
854 | super->s_master_inode = logfs_new_meta_inode(sb, LOGFS_INO_MASTER); | 854 | super->s_master_inode = logfs_new_meta_inode(sb, LOGFS_INO_MASTER); |
855 | if (IS_ERR(super->s_master_inode)) | 855 | if (IS_ERR(super->s_master_inode)) |
856 | return PTR_ERR(super->s_master_inode); | 856 | return PTR_ERR(super->s_master_inode); |
857 | 857 | ||
858 | ret = logfs_read_journal(sb); | 858 | ret = logfs_read_journal(sb); |
859 | if (ret) | 859 | if (ret) |
860 | return -EIO; | 860 | return -EIO; |
861 | 861 | ||
862 | reserve_sb_and_journal(sb); | 862 | reserve_sb_and_journal(sb); |
863 | logfs_calc_free(sb); | 863 | logfs_calc_free(sb); |
864 | 864 | ||
865 | super->s_journal_area->a_ops = &journal_area_ops; | 865 | super->s_journal_area->a_ops = &journal_area_ops; |
866 | return 0; | 866 | return 0; |
867 | } | 867 | } |
868 | 868 | ||
869 | void logfs_cleanup_journal(struct super_block *sb) | 869 | void logfs_cleanup_journal(struct super_block *sb) |
870 | { | 870 | { |
871 | struct logfs_super *super = logfs_super(sb); | 871 | struct logfs_super *super = logfs_super(sb); |
872 | 872 | ||
873 | btree_grim_visitor32(&super->s_reserved_segments, 0, NULL); | 873 | btree_grim_visitor32(&super->s_reserved_segments, 0, NULL); |
874 | destroy_meta_inode(super->s_master_inode); | 874 | destroy_meta_inode(super->s_master_inode); |
875 | super->s_master_inode = NULL; | 875 | super->s_master_inode = NULL; |
876 | 876 | ||
877 | kfree(super->s_compressed_je); | 877 | kfree(super->s_compressed_je); |
878 | kfree(super->s_je); | 878 | kfree(super->s_je); |
879 | } | 879 | } |
880 | 880 |
fs/logfs/logfs.h
1 | /* | 1 | /* |
2 | * fs/logfs/logfs.h | 2 | * fs/logfs/logfs.h |
3 | * | 3 | * |
4 | * As should be obvious for Linux kernel code, license is GPLv2 | 4 | * As should be obvious for Linux kernel code, license is GPLv2 |
5 | * | 5 | * |
6 | * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org> | 6 | * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org> |
7 | * | 7 | * |
8 | * Private header for logfs. | 8 | * Private header for logfs. |
9 | */ | 9 | */ |
10 | #ifndef FS_LOGFS_LOGFS_H | 10 | #ifndef FS_LOGFS_LOGFS_H |
11 | #define FS_LOGFS_LOGFS_H | 11 | #define FS_LOGFS_LOGFS_H |
12 | 12 | ||
13 | #undef __CHECK_ENDIAN__ | 13 | #undef __CHECK_ENDIAN__ |
14 | #define __CHECK_ENDIAN__ | 14 | #define __CHECK_ENDIAN__ |
15 | 15 | ||
16 | #include <linux/btree.h> | 16 | #include <linux/btree.h> |
17 | #include <linux/crc32.h> | 17 | #include <linux/crc32.h> |
18 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/mempool.h> | 20 | #include <linux/mempool.h> |
21 | #include <linux/pagemap.h> | 21 | #include <linux/pagemap.h> |
22 | #include <linux/mtd/mtd.h> | 22 | #include <linux/mtd/mtd.h> |
23 | #include "logfs_abi.h" | 23 | #include "logfs_abi.h" |
24 | 24 | ||
25 | #define LOGFS_DEBUG_SUPER (0x0001) | 25 | #define LOGFS_DEBUG_SUPER (0x0001) |
26 | #define LOGFS_DEBUG_SEGMENT (0x0002) | 26 | #define LOGFS_DEBUG_SEGMENT (0x0002) |
27 | #define LOGFS_DEBUG_JOURNAL (0x0004) | 27 | #define LOGFS_DEBUG_JOURNAL (0x0004) |
28 | #define LOGFS_DEBUG_DIR (0x0008) | 28 | #define LOGFS_DEBUG_DIR (0x0008) |
29 | #define LOGFS_DEBUG_FILE (0x0010) | 29 | #define LOGFS_DEBUG_FILE (0x0010) |
30 | #define LOGFS_DEBUG_INODE (0x0020) | 30 | #define LOGFS_DEBUG_INODE (0x0020) |
31 | #define LOGFS_DEBUG_READWRITE (0x0040) | 31 | #define LOGFS_DEBUG_READWRITE (0x0040) |
32 | #define LOGFS_DEBUG_GC (0x0080) | 32 | #define LOGFS_DEBUG_GC (0x0080) |
33 | #define LOGFS_DEBUG_GC_NOISY (0x0100) | 33 | #define LOGFS_DEBUG_GC_NOISY (0x0100) |
34 | #define LOGFS_DEBUG_ALIASES (0x0200) | 34 | #define LOGFS_DEBUG_ALIASES (0x0200) |
35 | #define LOGFS_DEBUG_BLOCKMOVE (0x0400) | 35 | #define LOGFS_DEBUG_BLOCKMOVE (0x0400) |
36 | #define LOGFS_DEBUG_ALL (0xffffffff) | 36 | #define LOGFS_DEBUG_ALL (0xffffffff) |
37 | 37 | ||
38 | #define LOGFS_DEBUG (0x01) | 38 | #define LOGFS_DEBUG (0x01) |
39 | /* | 39 | /* |
40 | * To enable specific log messages, simply define LOGFS_DEBUG to match any | 40 | * To enable specific log messages, simply define LOGFS_DEBUG to match any |
41 | * or all of the above. | 41 | * or all of the above. |
42 | */ | 42 | */ |
43 | #ifndef LOGFS_DEBUG | 43 | #ifndef LOGFS_DEBUG |
44 | #define LOGFS_DEBUG (0) | 44 | #define LOGFS_DEBUG (0) |
45 | #endif | 45 | #endif |
46 | 46 | ||
47 | #define log_cond(cond, fmt, arg...) do { \ | 47 | #define log_cond(cond, fmt, arg...) do { \ |
48 | if (cond) \ | 48 | if (cond) \ |
49 | printk(KERN_DEBUG fmt, ##arg); \ | 49 | printk(KERN_DEBUG fmt, ##arg); \ |
50 | } while (0) | 50 | } while (0) |
51 | 51 | ||
52 | #define log_super(fmt, arg...) \ | 52 | #define log_super(fmt, arg...) \ |
53 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_SUPER, fmt, ##arg) | 53 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_SUPER, fmt, ##arg) |
54 | #define log_segment(fmt, arg...) \ | 54 | #define log_segment(fmt, arg...) \ |
55 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_SEGMENT, fmt, ##arg) | 55 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_SEGMENT, fmt, ##arg) |
56 | #define log_journal(fmt, arg...) \ | 56 | #define log_journal(fmt, arg...) \ |
57 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_JOURNAL, fmt, ##arg) | 57 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_JOURNAL, fmt, ##arg) |
58 | #define log_dir(fmt, arg...) \ | 58 | #define log_dir(fmt, arg...) \ |
59 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_DIR, fmt, ##arg) | 59 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_DIR, fmt, ##arg) |
60 | #define log_file(fmt, arg...) \ | 60 | #define log_file(fmt, arg...) \ |
61 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_FILE, fmt, ##arg) | 61 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_FILE, fmt, ##arg) |
62 | #define log_inode(fmt, arg...) \ | 62 | #define log_inode(fmt, arg...) \ |
63 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_INODE, fmt, ##arg) | 63 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_INODE, fmt, ##arg) |
64 | #define log_readwrite(fmt, arg...) \ | 64 | #define log_readwrite(fmt, arg...) \ |
65 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_READWRITE, fmt, ##arg) | 65 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_READWRITE, fmt, ##arg) |
66 | #define log_gc(fmt, arg...) \ | 66 | #define log_gc(fmt, arg...) \ |
67 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_GC, fmt, ##arg) | 67 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_GC, fmt, ##arg) |
68 | #define log_gc_noisy(fmt, arg...) \ | 68 | #define log_gc_noisy(fmt, arg...) \ |
69 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_GC_NOISY, fmt, ##arg) | 69 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_GC_NOISY, fmt, ##arg) |
70 | #define log_aliases(fmt, arg...) \ | 70 | #define log_aliases(fmt, arg...) \ |
71 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_ALIASES, fmt, ##arg) | 71 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_ALIASES, fmt, ##arg) |
72 | #define log_blockmove(fmt, arg...) \ | 72 | #define log_blockmove(fmt, arg...) \ |
73 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_BLOCKMOVE, fmt, ##arg) | 73 | log_cond(LOGFS_DEBUG & LOGFS_DEBUG_BLOCKMOVE, fmt, ##arg) |
74 | 74 | ||
75 | #define PG_pre_locked PG_owner_priv_1 | 75 | #define PG_pre_locked PG_owner_priv_1 |
76 | #define PagePreLocked(page) test_bit(PG_pre_locked, &(page)->flags) | 76 | #define PagePreLocked(page) test_bit(PG_pre_locked, &(page)->flags) |
77 | #define SetPagePreLocked(page) set_bit(PG_pre_locked, &(page)->flags) | 77 | #define SetPagePreLocked(page) set_bit(PG_pre_locked, &(page)->flags) |
78 | #define ClearPagePreLocked(page) clear_bit(PG_pre_locked, &(page)->flags) | 78 | #define ClearPagePreLocked(page) clear_bit(PG_pre_locked, &(page)->flags) |
79 | 79 | ||
80 | /* FIXME: This should really be somewhere in the 64bit area. */ | 80 | /* FIXME: This should really be somewhere in the 64bit area. */ |
81 | #define LOGFS_LINK_MAX (1<<30) | 81 | #define LOGFS_LINK_MAX (1<<30) |
82 | 82 | ||
83 | /* Read-only filesystem */ | 83 | /* Read-only filesystem */ |
84 | #define LOGFS_SB_FLAG_RO 0x0001 | 84 | #define LOGFS_SB_FLAG_RO 0x0001 |
85 | #define LOGFS_SB_FLAG_SEG_ALIAS 0x0002 | 85 | #define LOGFS_SB_FLAG_SEG_ALIAS 0x0002 |
86 | #define LOGFS_SB_FLAG_OBJ_ALIAS 0x0004 | 86 | #define LOGFS_SB_FLAG_OBJ_ALIAS 0x0004 |
87 | #define LOGFS_SB_FLAG_SHUTDOWN 0x0008 | 87 | #define LOGFS_SB_FLAG_SHUTDOWN 0x0008 |
88 | 88 | ||
89 | /* Write Control Flags */ | 89 | /* Write Control Flags */ |
90 | #define WF_LOCK 0x01 /* take write lock */ | 90 | #define WF_LOCK 0x01 /* take write lock */ |
91 | #define WF_WRITE 0x02 /* write block */ | 91 | #define WF_WRITE 0x02 /* write block */ |
92 | #define WF_DELETE 0x04 /* delete old block */ | 92 | #define WF_DELETE 0x04 /* delete old block */ |
93 | 93 | ||
94 | typedef u8 __bitwise level_t; | 94 | typedef u8 __bitwise level_t; |
95 | typedef u8 __bitwise gc_level_t; | 95 | typedef u8 __bitwise gc_level_t; |
96 | 96 | ||
97 | #define LEVEL(level) ((__force level_t)(level)) | 97 | #define LEVEL(level) ((__force level_t)(level)) |
98 | #define GC_LEVEL(gc_level) ((__force gc_level_t)(gc_level)) | 98 | #define GC_LEVEL(gc_level) ((__force gc_level_t)(gc_level)) |
99 | 99 | ||
100 | #define SUBLEVEL(level) ( (void)((level) == LEVEL(1)), \ | 100 | #define SUBLEVEL(level) ( (void)((level) == LEVEL(1)), \ |
101 | (__force level_t)((__force u8)(level) - 1) ) | 101 | (__force level_t)((__force u8)(level) - 1) ) |
102 | 102 | ||
103 | /** | 103 | /** |
104 | * struct logfs_area - area management information | 104 | * struct logfs_area - area management information |
105 | * | 105 | * |
106 | * @a_sb: the superblock this area belongs to | 106 | * @a_sb: the superblock this area belongs to |
107 | * @a_is_open: 1 if the area is currently open, else 0 | 107 | * @a_is_open: 1 if the area is currently open, else 0 |
108 | * @a_segno: segment number of area | 108 | * @a_segno: segment number of area |
109 | * @a_written_bytes: number of bytes already written back | 109 | * @a_written_bytes: number of bytes already written back |
110 | * @a_used_bytes: number of used bytes | 110 | * @a_used_bytes: number of used bytes |
111 | * @a_ops: area operations (either journal or ostore) | 111 | * @a_ops: area operations (either journal or ostore) |
112 | * @a_erase_count: erase count | 112 | * @a_erase_count: erase count |
113 | * @a_level: GC level | 113 | * @a_level: GC level |
114 | */ | 114 | */ |
115 | struct logfs_area { /* a segment open for writing */ | 115 | struct logfs_area { /* a segment open for writing */ |
116 | struct super_block *a_sb; | 116 | struct super_block *a_sb; |
117 | int a_is_open; | 117 | int a_is_open; |
118 | u32 a_segno; | 118 | u32 a_segno; |
119 | u32 a_written_bytes; | 119 | u32 a_written_bytes; |
120 | u32 a_used_bytes; | 120 | u32 a_used_bytes; |
121 | const struct logfs_area_ops *a_ops; | 121 | const struct logfs_area_ops *a_ops; |
122 | u32 a_erase_count; | 122 | u32 a_erase_count; |
123 | gc_level_t a_level; | 123 | gc_level_t a_level; |
124 | }; | 124 | }; |
125 | 125 | ||
126 | /** | 126 | /** |
127 | * struct logfs_area_ops - area operations | 127 | * struct logfs_area_ops - area operations |
128 | * | 128 | * |
129 | * @get_free_segment: fill area->ofs with the offset of a free segment | 129 | * @get_free_segment: fill area->ofs with the offset of a free segment |
130 | * @get_erase_count: fill area->erase_count (needs area->ofs) | 130 | * @get_erase_count: fill area->erase_count (needs area->ofs) |
131 | * @erase_segment: erase and setup segment | 131 | * @erase_segment: erase and setup segment |
132 | */ | 132 | */ |
133 | struct logfs_area_ops { | 133 | struct logfs_area_ops { |
134 | void (*get_free_segment)(struct logfs_area *area); | 134 | void (*get_free_segment)(struct logfs_area *area); |
135 | void (*get_erase_count)(struct logfs_area *area); | 135 | void (*get_erase_count)(struct logfs_area *area); |
136 | int (*erase_segment)(struct logfs_area *area); | 136 | int (*erase_segment)(struct logfs_area *area); |
137 | }; | 137 | }; |
138 | 138 | ||
139 | /** | 139 | /** |
140 | * struct logfs_device_ops - device access operations | 140 | * struct logfs_device_ops - device access operations |
141 | * | 141 | * |
142 | * @readpage: read one page (mm page) | 142 | * @readpage: read one page (mm page) |
143 | * @writeseg: write one segment. may be a partial segment | 143 | * @writeseg: write one segment. may be a partial segment |
144 | * @erase: erase one segment | 144 | * @erase: erase one segment |
145 | * @read: read from the device | 145 | * @read: read from the device |
146 | * @erase: erase part of the device | 146 | * @erase: erase part of the device |
147 | */ | 147 | */ |
148 | struct logfs_device_ops { | 148 | struct logfs_device_ops { |
149 | struct page *(*find_first_sb)(struct super_block *sb, u64 *ofs); | 149 | struct page *(*find_first_sb)(struct super_block *sb, u64 *ofs); |
150 | struct page *(*find_last_sb)(struct super_block *sb, u64 *ofs); | 150 | struct page *(*find_last_sb)(struct super_block *sb, u64 *ofs); |
151 | int (*write_sb)(struct super_block *sb, struct page *page); | 151 | int (*write_sb)(struct super_block *sb, struct page *page); |
152 | int (*readpage)(void *_sb, struct page *page); | 152 | int (*readpage)(void *_sb, struct page *page); |
153 | void (*writeseg)(struct super_block *sb, u64 ofs, size_t len); | 153 | void (*writeseg)(struct super_block *sb, u64 ofs, size_t len); |
154 | int (*erase)(struct super_block *sb, loff_t ofs, size_t len); | 154 | int (*erase)(struct super_block *sb, loff_t ofs, size_t len, |
155 | int ensure_write); | ||
155 | void (*sync)(struct super_block *sb); | 156 | void (*sync)(struct super_block *sb); |
156 | void (*put_device)(struct super_block *sb); | 157 | void (*put_device)(struct super_block *sb); |
157 | }; | 158 | }; |
158 | 159 | ||
159 | /** | 160 | /** |
160 | * struct candidate_list - list of similar candidates | 161 | * struct candidate_list - list of similar candidates |
161 | */ | 162 | */ |
162 | struct candidate_list { | 163 | struct candidate_list { |
163 | struct rb_root rb_tree; | 164 | struct rb_root rb_tree; |
164 | int count; | 165 | int count; |
165 | int maxcount; | 166 | int maxcount; |
166 | int sort_by_ec; | 167 | int sort_by_ec; |
167 | }; | 168 | }; |
168 | 169 | ||
169 | /** | 170 | /** |
170 | * struct gc_candidate - "candidate" segment to be garbage collected next | 171 | * struct gc_candidate - "candidate" segment to be garbage collected next |
171 | * | 172 | * |
172 | * @list: list (either free of low) | 173 | * @list: list (either free of low) |
173 | * @segno: segment number | 174 | * @segno: segment number |
174 | * @valid: number of valid bytes | 175 | * @valid: number of valid bytes |
175 | * @erase_count: erase count of segment | 176 | * @erase_count: erase count of segment |
176 | * @dist: distance from tree root | 177 | * @dist: distance from tree root |
177 | * | 178 | * |
178 | * Candidates can be on two lists. The free list contains electees rather | 179 | * Candidates can be on two lists. The free list contains electees rather |
179 | * than candidates - segments that no longer contain any valid data. The | 180 | * than candidates - segments that no longer contain any valid data. The |
180 | * low list contains candidates to be picked for GC. It should be kept | 181 | * low list contains candidates to be picked for GC. It should be kept |
181 | * short. It is not required to always pick a perfect candidate. In the | 182 | * short. It is not required to always pick a perfect candidate. In the |
182 | * worst case GC will have to move more data than absolutely necessary. | 183 | * worst case GC will have to move more data than absolutely necessary. |
183 | */ | 184 | */ |
184 | struct gc_candidate { | 185 | struct gc_candidate { |
185 | struct rb_node rb_node; | 186 | struct rb_node rb_node; |
186 | struct candidate_list *list; | 187 | struct candidate_list *list; |
187 | u32 segno; | 188 | u32 segno; |
188 | u32 valid; | 189 | u32 valid; |
189 | u32 erase_count; | 190 | u32 erase_count; |
190 | u8 dist; | 191 | u8 dist; |
191 | }; | 192 | }; |
192 | 193 | ||
193 | /** | 194 | /** |
194 | * struct logfs_journal_entry - temporary structure used during journal scan | 195 | * struct logfs_journal_entry - temporary structure used during journal scan |
195 | * | 196 | * |
196 | * @used: | 197 | * @used: |
197 | * @version: normalized version | 198 | * @version: normalized version |
198 | * @len: length | 199 | * @len: length |
199 | * @offset: offset | 200 | * @offset: offset |
200 | */ | 201 | */ |
201 | struct logfs_journal_entry { | 202 | struct logfs_journal_entry { |
202 | int used; | 203 | int used; |
203 | s16 version; | 204 | s16 version; |
204 | u16 len; | 205 | u16 len; |
205 | u16 datalen; | 206 | u16 datalen; |
206 | u64 offset; | 207 | u64 offset; |
207 | }; | 208 | }; |
208 | 209 | ||
209 | enum transaction_state { | 210 | enum transaction_state { |
210 | CREATE_1 = 1, | 211 | CREATE_1 = 1, |
211 | CREATE_2, | 212 | CREATE_2, |
212 | UNLINK_1, | 213 | UNLINK_1, |
213 | UNLINK_2, | 214 | UNLINK_2, |
214 | CROSS_RENAME_1, | 215 | CROSS_RENAME_1, |
215 | CROSS_RENAME_2, | 216 | CROSS_RENAME_2, |
216 | TARGET_RENAME_1, | 217 | TARGET_RENAME_1, |
217 | TARGET_RENAME_2, | 218 | TARGET_RENAME_2, |
218 | TARGET_RENAME_3 | 219 | TARGET_RENAME_3 |
219 | }; | 220 | }; |
220 | 221 | ||
221 | /** | 222 | /** |
222 | * struct logfs_transaction - essential fields to support atomic dirops | 223 | * struct logfs_transaction - essential fields to support atomic dirops |
223 | * | 224 | * |
224 | * @ino: target inode | 225 | * @ino: target inode |
225 | * @dir: inode of directory containing dentry | 226 | * @dir: inode of directory containing dentry |
226 | * @pos: pos of dentry in directory | 227 | * @pos: pos of dentry in directory |
227 | */ | 228 | */ |
228 | struct logfs_transaction { | 229 | struct logfs_transaction { |
229 | enum transaction_state state; | 230 | enum transaction_state state; |
230 | u64 ino; | 231 | u64 ino; |
231 | u64 dir; | 232 | u64 dir; |
232 | u64 pos; | 233 | u64 pos; |
233 | }; | 234 | }; |
234 | 235 | ||
235 | /** | 236 | /** |
236 | * struct logfs_shadow - old block in the shadow of a not-yet-committed new one | 237 | * struct logfs_shadow - old block in the shadow of a not-yet-committed new one |
237 | * @old_ofs: offset of old block on medium | 238 | * @old_ofs: offset of old block on medium |
238 | * @new_ofs: offset of new block on medium | 239 | * @new_ofs: offset of new block on medium |
239 | * @ino: inode number | 240 | * @ino: inode number |
240 | * @bix: block index | 241 | * @bix: block index |
241 | * @old_len: size of old block, including header | 242 | * @old_len: size of old block, including header |
242 | * @new_len: size of new block, including header | 243 | * @new_len: size of new block, including header |
243 | * @level: block level | 244 | * @level: block level |
244 | */ | 245 | */ |
245 | struct logfs_shadow { | 246 | struct logfs_shadow { |
246 | u64 old_ofs; | 247 | u64 old_ofs; |
247 | u64 new_ofs; | 248 | u64 new_ofs; |
248 | u64 ino; | 249 | u64 ino; |
249 | u64 bix; | 250 | u64 bix; |
250 | int old_len; | 251 | int old_len; |
251 | int new_len; | 252 | int new_len; |
252 | gc_level_t gc_level; | 253 | gc_level_t gc_level; |
253 | }; | 254 | }; |
254 | 255 | ||
255 | /** | 256 | /** |
256 | * struct shadow_tree | 257 | * struct shadow_tree |
257 | * @new: shadows where old_ofs==0, indexed by new_ofs | 258 | * @new: shadows where old_ofs==0, indexed by new_ofs |
258 | * @old: shadows where old_ofs!=0, indexed by old_ofs | 259 | * @old: shadows where old_ofs!=0, indexed by old_ofs |
259 | */ | 260 | */ |
260 | struct shadow_tree { | 261 | struct shadow_tree { |
261 | struct btree_head64 new; | 262 | struct btree_head64 new; |
262 | struct btree_head64 old; | 263 | struct btree_head64 old; |
263 | }; | 264 | }; |
264 | 265 | ||
265 | struct object_alias_item { | 266 | struct object_alias_item { |
266 | struct list_head list; | 267 | struct list_head list; |
267 | __be64 val; | 268 | __be64 val; |
268 | int child_no; | 269 | int child_no; |
269 | }; | 270 | }; |
270 | 271 | ||
271 | /** | 272 | /** |
272 | * struct logfs_block - contains any block state | 273 | * struct logfs_block - contains any block state |
273 | * @type: indirect block or inode | 274 | * @type: indirect block or inode |
274 | * @full: number of fully populated children | 275 | * @full: number of fully populated children |
275 | * @partial: number of partially populated children | 276 | * @partial: number of partially populated children |
276 | * | 277 | * |
277 | * Most blocks are directly represented by page cache pages. But when a block | 278 | * Most blocks are directly represented by page cache pages. But when a block |
278 | * becomes dirty, is part of a transaction, contains aliases or is otherwise | 279 | * becomes dirty, is part of a transaction, contains aliases or is otherwise |
279 | * special, a struct logfs_block is allocated to track the additional state. | 280 | * special, a struct logfs_block is allocated to track the additional state. |
280 | * Inodes are very similar to indirect blocks, so they can also get one of | 281 | * Inodes are very similar to indirect blocks, so they can also get one of |
281 | * these structures added when appropriate. | 282 | * these structures added when appropriate. |
282 | */ | 283 | */ |
283 | #define BLOCK_INDIRECT 1 /* Indirect block */ | 284 | #define BLOCK_INDIRECT 1 /* Indirect block */ |
284 | #define BLOCK_INODE 2 /* Inode */ | 285 | #define BLOCK_INODE 2 /* Inode */ |
285 | struct logfs_block_ops; | 286 | struct logfs_block_ops; |
286 | struct logfs_block { | 287 | struct logfs_block { |
287 | struct list_head alias_list; | 288 | struct list_head alias_list; |
288 | struct list_head item_list; | 289 | struct list_head item_list; |
289 | struct super_block *sb; | 290 | struct super_block *sb; |
290 | u64 ino; | 291 | u64 ino; |
291 | u64 bix; | 292 | u64 bix; |
292 | level_t level; | 293 | level_t level; |
293 | struct page *page; | 294 | struct page *page; |
294 | struct inode *inode; | 295 | struct inode *inode; |
295 | struct logfs_transaction *ta; | 296 | struct logfs_transaction *ta; |
296 | unsigned long alias_map[LOGFS_BLOCK_FACTOR / BITS_PER_LONG]; | 297 | unsigned long alias_map[LOGFS_BLOCK_FACTOR / BITS_PER_LONG]; |
297 | struct logfs_block_ops *ops; | 298 | struct logfs_block_ops *ops; |
298 | int full; | 299 | int full; |
299 | int partial; | 300 | int partial; |
300 | int reserved_bytes; | 301 | int reserved_bytes; |
301 | }; | 302 | }; |
302 | 303 | ||
303 | typedef int write_alias_t(struct super_block *sb, u64 ino, u64 bix, | 304 | typedef int write_alias_t(struct super_block *sb, u64 ino, u64 bix, |
304 | level_t level, int child_no, __be64 val); | 305 | level_t level, int child_no, __be64 val); |
305 | struct logfs_block_ops { | 306 | struct logfs_block_ops { |
306 | void (*write_block)(struct logfs_block *block); | 307 | void (*write_block)(struct logfs_block *block); |
307 | gc_level_t (*block_level)(struct logfs_block *block); | 308 | gc_level_t (*block_level)(struct logfs_block *block); |
308 | void (*free_block)(struct super_block *sb, struct logfs_block*block); | 309 | void (*free_block)(struct super_block *sb, struct logfs_block*block); |
309 | int (*write_alias)(struct super_block *sb, | 310 | int (*write_alias)(struct super_block *sb, |
310 | struct logfs_block *block, | 311 | struct logfs_block *block, |
311 | write_alias_t *write_one_alias); | 312 | write_alias_t *write_one_alias); |
312 | }; | 313 | }; |
313 | 314 | ||
314 | struct logfs_super { | 315 | struct logfs_super { |
315 | struct mtd_info *s_mtd; /* underlying device */ | 316 | struct mtd_info *s_mtd; /* underlying device */ |
316 | struct block_device *s_bdev; /* underlying device */ | 317 | struct block_device *s_bdev; /* underlying device */ |
317 | const struct logfs_device_ops *s_devops;/* device access */ | 318 | const struct logfs_device_ops *s_devops;/* device access */ |
318 | struct inode *s_master_inode; /* inode file */ | 319 | struct inode *s_master_inode; /* inode file */ |
319 | struct inode *s_segfile_inode; /* segment file */ | 320 | struct inode *s_segfile_inode; /* segment file */ |
320 | struct inode *s_mapping_inode; /* device mapping */ | 321 | struct inode *s_mapping_inode; /* device mapping */ |
321 | atomic_t s_pending_writes; /* outstanting bios */ | 322 | atomic_t s_pending_writes; /* outstanting bios */ |
322 | long s_flags; | 323 | long s_flags; |
323 | mempool_t *s_btree_pool; /* for btree nodes */ | 324 | mempool_t *s_btree_pool; /* for btree nodes */ |
324 | mempool_t *s_alias_pool; /* aliases in segment.c */ | 325 | mempool_t *s_alias_pool; /* aliases in segment.c */ |
325 | u64 s_feature_incompat; | 326 | u64 s_feature_incompat; |
326 | u64 s_feature_ro_compat; | 327 | u64 s_feature_ro_compat; |
327 | u64 s_feature_compat; | 328 | u64 s_feature_compat; |
328 | u64 s_feature_flags; | 329 | u64 s_feature_flags; |
329 | u64 s_sb_ofs[2]; | 330 | u64 s_sb_ofs[2]; |
331 | struct page *s_erase_page; /* for dev_bdev.c */ | ||
330 | /* alias.c fields */ | 332 | /* alias.c fields */ |
331 | struct btree_head32 s_segment_alias; /* remapped segments */ | 333 | struct btree_head32 s_segment_alias; /* remapped segments */ |
332 | int s_no_object_aliases; | 334 | int s_no_object_aliases; |
333 | struct list_head s_object_alias; /* remapped objects */ | 335 | struct list_head s_object_alias; /* remapped objects */ |
334 | struct btree_head128 s_object_alias_tree; /* remapped objects */ | 336 | struct btree_head128 s_object_alias_tree; /* remapped objects */ |
335 | struct mutex s_object_alias_mutex; | 337 | struct mutex s_object_alias_mutex; |
336 | /* dir.c fields */ | 338 | /* dir.c fields */ |
337 | struct mutex s_dirop_mutex; /* for creat/unlink/rename */ | 339 | struct mutex s_dirop_mutex; /* for creat/unlink/rename */ |
338 | u64 s_victim_ino; /* used for atomic dir-ops */ | 340 | u64 s_victim_ino; /* used for atomic dir-ops */ |
339 | u64 s_rename_dir; /* source directory ino */ | 341 | u64 s_rename_dir; /* source directory ino */ |
340 | u64 s_rename_pos; /* position of source dd */ | 342 | u64 s_rename_pos; /* position of source dd */ |
341 | /* gc.c fields */ | 343 | /* gc.c fields */ |
342 | long s_segsize; /* size of a segment */ | 344 | long s_segsize; /* size of a segment */ |
343 | int s_segshift; /* log2 of segment size */ | 345 | int s_segshift; /* log2 of segment size */ |
344 | long s_segmask; /* 1 << s_segshift - 1 */ | 346 | long s_segmask; /* 1 << s_segshift - 1 */ |
345 | long s_no_segs; /* segments on device */ | 347 | long s_no_segs; /* segments on device */ |
346 | long s_no_journal_segs; /* segments used for journal */ | 348 | long s_no_journal_segs; /* segments used for journal */ |
347 | long s_no_blocks; /* blocks per segment */ | 349 | long s_no_blocks; /* blocks per segment */ |
348 | long s_writesize; /* minimum write size */ | 350 | long s_writesize; /* minimum write size */ |
349 | int s_writeshift; /* log2 of write size */ | 351 | int s_writeshift; /* log2 of write size */ |
350 | u64 s_size; /* filesystem size */ | 352 | u64 s_size; /* filesystem size */ |
351 | struct logfs_area *s_area[LOGFS_NO_AREAS]; /* open segment array */ | 353 | struct logfs_area *s_area[LOGFS_NO_AREAS]; /* open segment array */ |
352 | u64 s_gec; /* global erase count */ | 354 | u64 s_gec; /* global erase count */ |
353 | u64 s_wl_gec_ostore; /* time of last wl event */ | 355 | u64 s_wl_gec_ostore; /* time of last wl event */ |
354 | u64 s_wl_gec_journal; /* time of last wl event */ | 356 | u64 s_wl_gec_journal; /* time of last wl event */ |
355 | u64 s_sweeper; /* current sweeper pos */ | 357 | u64 s_sweeper; /* current sweeper pos */ |
356 | u8 s_ifile_levels; /* max level of ifile */ | 358 | u8 s_ifile_levels; /* max level of ifile */ |
357 | u8 s_iblock_levels; /* max level of regular files */ | 359 | u8 s_iblock_levels; /* max level of regular files */ |
358 | u8 s_data_levels; /* # of segments to leaf block*/ | 360 | u8 s_data_levels; /* # of segments to leaf block*/ |
359 | u8 s_total_levels; /* sum of above three */ | 361 | u8 s_total_levels; /* sum of above three */ |
360 | struct btree_head32 s_cand_tree; /* all candidates */ | 362 | struct btree_head32 s_cand_tree; /* all candidates */ |
361 | struct candidate_list s_free_list; /* 100% free segments */ | 363 | struct candidate_list s_free_list; /* 100% free segments */ |
362 | struct candidate_list s_reserve_list; /* Bad segment reserve */ | 364 | struct candidate_list s_reserve_list; /* Bad segment reserve */ |
363 | struct candidate_list s_low_list[LOGFS_NO_AREAS];/* good candidates */ | 365 | struct candidate_list s_low_list[LOGFS_NO_AREAS];/* good candidates */ |
364 | struct candidate_list s_ec_list; /* wear level candidates */ | 366 | struct candidate_list s_ec_list; /* wear level candidates */ |
365 | struct btree_head32 s_reserved_segments;/* sb, journal, bad, etc. */ | 367 | struct btree_head32 s_reserved_segments;/* sb, journal, bad, etc. */ |
366 | /* inode.c fields */ | 368 | /* inode.c fields */ |
367 | u64 s_last_ino; /* highest ino used */ | 369 | u64 s_last_ino; /* highest ino used */ |
368 | long s_inos_till_wrap; | 370 | long s_inos_till_wrap; |
369 | u32 s_generation; /* i_generation for new files */ | 371 | u32 s_generation; /* i_generation for new files */ |
370 | struct list_head s_freeing_list; /* inodes being freed */ | 372 | struct list_head s_freeing_list; /* inodes being freed */ |
371 | /* journal.c fields */ | 373 | /* journal.c fields */ |
372 | struct mutex s_journal_mutex; | 374 | struct mutex s_journal_mutex; |
373 | void *s_je; /* journal entry to compress */ | 375 | void *s_je; /* journal entry to compress */ |
374 | void *s_compressed_je; /* block to write to journal */ | 376 | void *s_compressed_je; /* block to write to journal */ |
375 | u32 s_journal_seg[LOGFS_JOURNAL_SEGS]; /* journal segments */ | 377 | u32 s_journal_seg[LOGFS_JOURNAL_SEGS]; /* journal segments */ |
376 | u32 s_journal_ec[LOGFS_JOURNAL_SEGS]; /* journal erasecounts */ | 378 | u32 s_journal_ec[LOGFS_JOURNAL_SEGS]; /* journal erasecounts */ |
377 | u64 s_last_version; | 379 | u64 s_last_version; |
378 | struct logfs_area *s_journal_area; /* open journal segment */ | 380 | struct logfs_area *s_journal_area; /* open journal segment */ |
379 | __be64 s_je_array[64]; | 381 | __be64 s_je_array[64]; |
380 | int s_no_je; | 382 | int s_no_je; |
381 | 383 | ||
382 | int s_sum_index; /* for the 12 summaries */ | 384 | int s_sum_index; /* for the 12 summaries */ |
383 | struct shadow_tree s_shadow_tree; | 385 | struct shadow_tree s_shadow_tree; |
384 | int s_je_fill; /* index of current je */ | 386 | int s_je_fill; /* index of current je */ |
385 | /* readwrite.c fields */ | 387 | /* readwrite.c fields */ |
386 | struct mutex s_write_mutex; | 388 | struct mutex s_write_mutex; |
387 | int s_lock_count; | 389 | int s_lock_count; |
388 | mempool_t *s_block_pool; /* struct logfs_block pool */ | 390 | mempool_t *s_block_pool; /* struct logfs_block pool */ |
389 | mempool_t *s_shadow_pool; /* struct logfs_shadow pool */ | 391 | mempool_t *s_shadow_pool; /* struct logfs_shadow pool */ |
390 | /* | 392 | /* |
391 | * Space accounting: | 393 | * Space accounting: |
392 | * - s_used_bytes specifies space used to store valid data objects. | 394 | * - s_used_bytes specifies space used to store valid data objects. |
393 | * - s_dirty_used_bytes is space used to store non-committed data | 395 | * - s_dirty_used_bytes is space used to store non-committed data |
394 | * objects. Those objects have already been written themselves, | 396 | * objects. Those objects have already been written themselves, |
395 | * but they don't become valid until all indirect blocks up to the | 397 | * but they don't become valid until all indirect blocks up to the |
396 | * journal have been written as well. | 398 | * journal have been written as well. |
397 | * - s_dirty_free_bytes is space used to store the old copy of a | 399 | * - s_dirty_free_bytes is space used to store the old copy of a |
398 | * replaced object, as long as the replacement is non-committed. | 400 | * replaced object, as long as the replacement is non-committed. |
399 | * In other words, it is the amount of space freed when all dirty | 401 | * In other words, it is the amount of space freed when all dirty |
400 | * blocks are written back. | 402 | * blocks are written back. |
401 | * - s_free_bytes is the amount of free space available for any | 403 | * - s_free_bytes is the amount of free space available for any |
402 | * purpose. | 404 | * purpose. |
403 | * - s_root_reserve is the amount of free space available only to | 405 | * - s_root_reserve is the amount of free space available only to |
404 | * the root user. Non-privileged users can no longer write once | 406 | * the root user. Non-privileged users can no longer write once |
405 | * this watermark has been reached. | 407 | * this watermark has been reached. |
406 | * - s_speed_reserve is space which remains unused to speed up | 408 | * - s_speed_reserve is space which remains unused to speed up |
407 | * garbage collection performance. | 409 | * garbage collection performance. |
408 | * - s_dirty_pages is the space reserved for currently dirty pages. | 410 | * - s_dirty_pages is the space reserved for currently dirty pages. |
409 | * It is a pessimistic estimate, so some/most will get freed on | 411 | * It is a pessimistic estimate, so some/most will get freed on |
410 | * page writeback. | 412 | * page writeback. |
411 | * | 413 | * |
412 | * s_used_bytes + s_free_bytes + s_speed_reserve = total usable size | 414 | * s_used_bytes + s_free_bytes + s_speed_reserve = total usable size |
413 | */ | 415 | */ |
414 | u64 s_free_bytes; | 416 | u64 s_free_bytes; |
415 | u64 s_used_bytes; | 417 | u64 s_used_bytes; |
416 | u64 s_dirty_free_bytes; | 418 | u64 s_dirty_free_bytes; |
417 | u64 s_dirty_used_bytes; | 419 | u64 s_dirty_used_bytes; |
418 | u64 s_root_reserve; | 420 | u64 s_root_reserve; |
419 | u64 s_speed_reserve; | 421 | u64 s_speed_reserve; |
420 | u64 s_dirty_pages; | 422 | u64 s_dirty_pages; |
421 | /* Bad block handling: | 423 | /* Bad block handling: |
422 | * - s_bad_seg_reserve is a number of segments usually kept | 424 | * - s_bad_seg_reserve is a number of segments usually kept |
423 | * free. When encountering bad blocks, the affected segment's data | 425 | * free. When encountering bad blocks, the affected segment's data |
424 | * is _temporarily_ moved to a reserved segment. | 426 | * is _temporarily_ moved to a reserved segment. |
425 | * - s_bad_segments is the number of known bad segments. | 427 | * - s_bad_segments is the number of known bad segments. |
426 | */ | 428 | */ |
427 | u32 s_bad_seg_reserve; | 429 | u32 s_bad_seg_reserve; |
428 | u32 s_bad_segments; | 430 | u32 s_bad_segments; |
429 | }; | 431 | }; |
430 | 432 | ||
431 | /** | 433 | /** |
432 | * struct logfs_inode - in-memory inode | 434 | * struct logfs_inode - in-memory inode |
433 | * | 435 | * |
434 | * @vfs_inode: struct inode | 436 | * @vfs_inode: struct inode |
435 | * @li_data: data pointers | 437 | * @li_data: data pointers |
436 | * @li_used_bytes: number of used bytes | 438 | * @li_used_bytes: number of used bytes |
437 | * @li_freeing_list: used to track inodes currently being freed | 439 | * @li_freeing_list: used to track inodes currently being freed |
438 | * @li_flags: inode flags | 440 | * @li_flags: inode flags |
439 | * @li_refcount: number of internal (GC-induced) references | 441 | * @li_refcount: number of internal (GC-induced) references |
440 | */ | 442 | */ |
441 | struct logfs_inode { | 443 | struct logfs_inode { |
442 | struct inode vfs_inode; | 444 | struct inode vfs_inode; |
443 | u64 li_data[LOGFS_EMBEDDED_FIELDS]; | 445 | u64 li_data[LOGFS_EMBEDDED_FIELDS]; |
444 | u64 li_used_bytes; | 446 | u64 li_used_bytes; |
445 | struct list_head li_freeing_list; | 447 | struct list_head li_freeing_list; |
446 | struct logfs_block *li_block; | 448 | struct logfs_block *li_block; |
447 | u32 li_flags; | 449 | u32 li_flags; |
448 | u8 li_height; | 450 | u8 li_height; |
449 | int li_refcount; | 451 | int li_refcount; |
450 | }; | 452 | }; |
451 | 453 | ||
452 | #define journal_for_each(__i) for (__i = 0; __i < LOGFS_JOURNAL_SEGS; __i++) | 454 | #define journal_for_each(__i) for (__i = 0; __i < LOGFS_JOURNAL_SEGS; __i++) |
453 | #define for_each_area(__i) for (__i = 0; __i < LOGFS_NO_AREAS; __i++) | 455 | #define for_each_area(__i) for (__i = 0; __i < LOGFS_NO_AREAS; __i++) |
454 | #define for_each_area_down(__i) for (__i = LOGFS_NO_AREAS - 1; __i >= 0; __i--) | 456 | #define for_each_area_down(__i) for (__i = LOGFS_NO_AREAS - 1; __i >= 0; __i--) |
455 | 457 | ||
456 | /* compr.c */ | 458 | /* compr.c */ |
457 | int logfs_compress(void *in, void *out, size_t inlen, size_t outlen); | 459 | int logfs_compress(void *in, void *out, size_t inlen, size_t outlen); |
458 | int logfs_uncompress(void *in, void *out, size_t inlen, size_t outlen); | 460 | int logfs_uncompress(void *in, void *out, size_t inlen, size_t outlen); |
459 | int __init logfs_compr_init(void); | 461 | int __init logfs_compr_init(void); |
460 | void logfs_compr_exit(void); | 462 | void logfs_compr_exit(void); |
461 | 463 | ||
462 | /* dev_bdev.c */ | 464 | /* dev_bdev.c */ |
463 | #ifdef CONFIG_BLOCK | 465 | #ifdef CONFIG_BLOCK |
464 | int logfs_get_sb_bdev(struct file_system_type *type, int flags, | 466 | int logfs_get_sb_bdev(struct file_system_type *type, int flags, |
465 | const char *devname, struct vfsmount *mnt); | 467 | const char *devname, struct vfsmount *mnt); |
466 | #else | 468 | #else |
467 | static inline int logfs_get_sb_bdev(struct file_system_type *type, int flags, | 469 | static inline int logfs_get_sb_bdev(struct file_system_type *type, int flags, |
468 | const char *devname, struct vfsmount *mnt) | 470 | const char *devname, struct vfsmount *mnt) |
469 | { | 471 | { |
470 | return -ENODEV; | 472 | return -ENODEV; |
471 | } | 473 | } |
472 | #endif | 474 | #endif |
473 | 475 | ||
474 | /* dev_mtd.c */ | 476 | /* dev_mtd.c */ |
475 | #ifdef CONFIG_MTD | 477 | #ifdef CONFIG_MTD |
476 | int logfs_get_sb_mtd(struct file_system_type *type, int flags, | 478 | int logfs_get_sb_mtd(struct file_system_type *type, int flags, |
477 | int mtdnr, struct vfsmount *mnt); | 479 | int mtdnr, struct vfsmount *mnt); |
478 | #else | 480 | #else |
479 | static inline int logfs_get_sb_mtd(struct file_system_type *type, int flags, | 481 | static inline int logfs_get_sb_mtd(struct file_system_type *type, int flags, |
480 | int mtdnr, struct vfsmount *mnt) | 482 | int mtdnr, struct vfsmount *mnt) |
481 | { | 483 | { |
482 | return -ENODEV; | 484 | return -ENODEV; |
483 | } | 485 | } |
484 | #endif | 486 | #endif |
485 | 487 | ||
486 | /* dir.c */ | 488 | /* dir.c */ |
487 | extern const struct inode_operations logfs_symlink_iops; | 489 | extern const struct inode_operations logfs_symlink_iops; |
488 | extern const struct inode_operations logfs_dir_iops; | 490 | extern const struct inode_operations logfs_dir_iops; |
489 | extern const struct file_operations logfs_dir_fops; | 491 | extern const struct file_operations logfs_dir_fops; |
490 | int logfs_replay_journal(struct super_block *sb); | 492 | int logfs_replay_journal(struct super_block *sb); |
491 | 493 | ||
492 | /* file.c */ | 494 | /* file.c */ |
493 | extern const struct inode_operations logfs_reg_iops; | 495 | extern const struct inode_operations logfs_reg_iops; |
494 | extern const struct file_operations logfs_reg_fops; | 496 | extern const struct file_operations logfs_reg_fops; |
495 | extern const struct address_space_operations logfs_reg_aops; | 497 | extern const struct address_space_operations logfs_reg_aops; |
496 | int logfs_readpage(struct file *file, struct page *page); | 498 | int logfs_readpage(struct file *file, struct page *page); |
497 | int logfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 499 | int logfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, |
498 | unsigned long arg); | 500 | unsigned long arg); |
499 | int logfs_fsync(struct file *file, struct dentry *dentry, int datasync); | 501 | int logfs_fsync(struct file *file, struct dentry *dentry, int datasync); |
500 | 502 | ||
501 | /* gc.c */ | 503 | /* gc.c */ |
502 | u32 get_best_cand(struct super_block *sb, struct candidate_list *list, u32 *ec); | 504 | u32 get_best_cand(struct super_block *sb, struct candidate_list *list, u32 *ec); |
503 | void logfs_gc_pass(struct super_block *sb); | 505 | void logfs_gc_pass(struct super_block *sb); |
504 | int logfs_check_areas(struct super_block *sb); | 506 | int logfs_check_areas(struct super_block *sb); |
505 | int logfs_init_gc(struct super_block *sb); | 507 | int logfs_init_gc(struct super_block *sb); |
506 | void logfs_cleanup_gc(struct super_block *sb); | 508 | void logfs_cleanup_gc(struct super_block *sb); |
507 | 509 | ||
508 | /* inode.c */ | 510 | /* inode.c */ |
509 | extern const struct super_operations logfs_super_operations; | 511 | extern const struct super_operations logfs_super_operations; |
510 | struct inode *logfs_iget(struct super_block *sb, ino_t ino); | 512 | struct inode *logfs_iget(struct super_block *sb, ino_t ino); |
511 | struct inode *logfs_safe_iget(struct super_block *sb, ino_t ino, int *cookie); | 513 | struct inode *logfs_safe_iget(struct super_block *sb, ino_t ino, int *cookie); |
512 | void logfs_safe_iput(struct inode *inode, int cookie); | 514 | void logfs_safe_iput(struct inode *inode, int cookie); |
513 | struct inode *logfs_new_inode(struct inode *dir, int mode); | 515 | struct inode *logfs_new_inode(struct inode *dir, int mode); |
514 | struct inode *logfs_new_meta_inode(struct super_block *sb, u64 ino); | 516 | struct inode *logfs_new_meta_inode(struct super_block *sb, u64 ino); |
515 | struct inode *logfs_read_meta_inode(struct super_block *sb, u64 ino); | 517 | struct inode *logfs_read_meta_inode(struct super_block *sb, u64 ino); |
516 | int logfs_init_inode_cache(void); | 518 | int logfs_init_inode_cache(void); |
517 | void logfs_destroy_inode_cache(void); | 519 | void logfs_destroy_inode_cache(void); |
518 | void destroy_meta_inode(struct inode *inode); | 520 | void destroy_meta_inode(struct inode *inode); |
519 | void logfs_set_blocks(struct inode *inode, u64 no); | 521 | void logfs_set_blocks(struct inode *inode, u64 no); |
520 | /* these logically belong into inode.c but actually reside in readwrite.c */ | 522 | /* these logically belong into inode.c but actually reside in readwrite.c */ |
521 | int logfs_read_inode(struct inode *inode); | 523 | int logfs_read_inode(struct inode *inode); |
522 | int __logfs_write_inode(struct inode *inode, long flags); | 524 | int __logfs_write_inode(struct inode *inode, long flags); |
523 | void logfs_delete_inode(struct inode *inode); | 525 | void logfs_delete_inode(struct inode *inode); |
524 | void logfs_clear_inode(struct inode *inode); | 526 | void logfs_clear_inode(struct inode *inode); |
525 | 527 | ||
526 | /* journal.c */ | 528 | /* journal.c */ |
527 | void logfs_write_anchor(struct inode *inode); | 529 | void logfs_write_anchor(struct inode *inode); |
528 | int logfs_init_journal(struct super_block *sb); | 530 | int logfs_init_journal(struct super_block *sb); |
529 | void logfs_cleanup_journal(struct super_block *sb); | 531 | void logfs_cleanup_journal(struct super_block *sb); |
530 | int write_alias_journal(struct super_block *sb, u64 ino, u64 bix, | 532 | int write_alias_journal(struct super_block *sb, u64 ino, u64 bix, |
531 | level_t level, int child_no, __be64 val); | 533 | level_t level, int child_no, __be64 val); |
532 | void do_logfs_journal_wl_pass(struct super_block *sb); | 534 | void do_logfs_journal_wl_pass(struct super_block *sb); |
533 | 535 | ||
534 | /* readwrite.c */ | 536 | /* readwrite.c */ |
535 | pgoff_t logfs_pack_index(u64 bix, level_t level); | 537 | pgoff_t logfs_pack_index(u64 bix, level_t level); |
536 | void logfs_unpack_index(pgoff_t index, u64 *bix, level_t *level); | 538 | void logfs_unpack_index(pgoff_t index, u64 *bix, level_t *level); |
537 | int logfs_inode_write(struct inode *inode, const void *buf, size_t count, | 539 | int logfs_inode_write(struct inode *inode, const void *buf, size_t count, |
538 | loff_t bix, long flags, struct shadow_tree *shadow_tree); | 540 | loff_t bix, long flags, struct shadow_tree *shadow_tree); |
539 | int logfs_readpage_nolock(struct page *page); | 541 | int logfs_readpage_nolock(struct page *page); |
540 | int logfs_write_buf(struct inode *inode, struct page *page, long flags); | 542 | int logfs_write_buf(struct inode *inode, struct page *page, long flags); |
541 | int logfs_delete(struct inode *inode, pgoff_t index, | 543 | int logfs_delete(struct inode *inode, pgoff_t index, |
542 | struct shadow_tree *shadow_tree); | 544 | struct shadow_tree *shadow_tree); |
543 | int logfs_rewrite_block(struct inode *inode, u64 bix, u64 ofs, | 545 | int logfs_rewrite_block(struct inode *inode, u64 bix, u64 ofs, |
544 | gc_level_t gc_level, long flags); | 546 | gc_level_t gc_level, long flags); |
545 | int logfs_is_valid_block(struct super_block *sb, u64 ofs, u64 ino, u64 bix, | 547 | int logfs_is_valid_block(struct super_block *sb, u64 ofs, u64 ino, u64 bix, |
546 | gc_level_t gc_level); | 548 | gc_level_t gc_level); |
547 | int logfs_truncate(struct inode *inode, u64 size); | 549 | int logfs_truncate(struct inode *inode, u64 size); |
548 | u64 logfs_seek_hole(struct inode *inode, u64 bix); | 550 | u64 logfs_seek_hole(struct inode *inode, u64 bix); |
549 | u64 logfs_seek_data(struct inode *inode, u64 bix); | 551 | u64 logfs_seek_data(struct inode *inode, u64 bix); |
550 | int logfs_open_segfile(struct super_block *sb); | 552 | int logfs_open_segfile(struct super_block *sb); |
551 | int logfs_init_rw(struct super_block *sb); | 553 | int logfs_init_rw(struct super_block *sb); |
552 | void logfs_cleanup_rw(struct super_block *sb); | 554 | void logfs_cleanup_rw(struct super_block *sb); |
553 | void logfs_add_transaction(struct inode *inode, struct logfs_transaction *ta); | 555 | void logfs_add_transaction(struct inode *inode, struct logfs_transaction *ta); |
554 | void logfs_del_transaction(struct inode *inode, struct logfs_transaction *ta); | 556 | void logfs_del_transaction(struct inode *inode, struct logfs_transaction *ta); |
555 | void logfs_write_block(struct logfs_block *block, long flags); | 557 | void logfs_write_block(struct logfs_block *block, long flags); |
556 | int logfs_write_obj_aliases_pagecache(struct super_block *sb); | 558 | int logfs_write_obj_aliases_pagecache(struct super_block *sb); |
557 | void logfs_get_segment_entry(struct super_block *sb, u32 segno, | 559 | void logfs_get_segment_entry(struct super_block *sb, u32 segno, |
558 | struct logfs_segment_entry *se); | 560 | struct logfs_segment_entry *se); |
559 | void logfs_set_segment_used(struct super_block *sb, u64 ofs, int increment); | 561 | void logfs_set_segment_used(struct super_block *sb, u64 ofs, int increment); |
560 | void logfs_set_segment_erased(struct super_block *sb, u32 segno, u32 ec, | 562 | void logfs_set_segment_erased(struct super_block *sb, u32 segno, u32 ec, |
561 | gc_level_t gc_level); | 563 | gc_level_t gc_level); |
562 | void logfs_set_segment_reserved(struct super_block *sb, u32 segno); | 564 | void logfs_set_segment_reserved(struct super_block *sb, u32 segno); |
563 | void logfs_set_segment_unreserved(struct super_block *sb, u32 segno, u32 ec); | 565 | void logfs_set_segment_unreserved(struct super_block *sb, u32 segno, u32 ec); |
564 | struct logfs_block *__alloc_block(struct super_block *sb, | 566 | struct logfs_block *__alloc_block(struct super_block *sb, |
565 | u64 ino, u64 bix, level_t level); | 567 | u64 ino, u64 bix, level_t level); |
566 | void __free_block(struct super_block *sb, struct logfs_block *block); | 568 | void __free_block(struct super_block *sb, struct logfs_block *block); |
567 | void btree_write_block(struct logfs_block *block); | 569 | void btree_write_block(struct logfs_block *block); |
568 | void initialize_block_counters(struct page *page, struct logfs_block *block, | 570 | void initialize_block_counters(struct page *page, struct logfs_block *block, |
569 | __be64 *array, int page_is_empty); | 571 | __be64 *array, int page_is_empty); |
570 | int logfs_exist_block(struct inode *inode, u64 bix); | 572 | int logfs_exist_block(struct inode *inode, u64 bix); |
571 | int get_page_reserve(struct inode *inode, struct page *page); | 573 | int get_page_reserve(struct inode *inode, struct page *page); |
572 | extern struct logfs_block_ops indirect_block_ops; | 574 | extern struct logfs_block_ops indirect_block_ops; |
573 | 575 | ||
574 | /* segment.c */ | 576 | /* segment.c */ |
575 | int logfs_erase_segment(struct super_block *sb, u32 ofs); | 577 | int logfs_erase_segment(struct super_block *sb, u32 ofs, int ensure_erase); |
576 | int wbuf_read(struct super_block *sb, u64 ofs, size_t len, void *buf); | 578 | int wbuf_read(struct super_block *sb, u64 ofs, size_t len, void *buf); |
577 | int logfs_segment_read(struct inode *inode, struct page *page, u64 ofs, u64 bix, | 579 | int logfs_segment_read(struct inode *inode, struct page *page, u64 ofs, u64 bix, |
578 | level_t level); | 580 | level_t level); |
579 | int logfs_segment_write(struct inode *inode, struct page *page, | 581 | int logfs_segment_write(struct inode *inode, struct page *page, |
580 | struct logfs_shadow *shadow); | 582 | struct logfs_shadow *shadow); |
581 | int logfs_segment_delete(struct inode *inode, struct logfs_shadow *shadow); | 583 | int logfs_segment_delete(struct inode *inode, struct logfs_shadow *shadow); |
582 | int logfs_load_object_aliases(struct super_block *sb, | 584 | int logfs_load_object_aliases(struct super_block *sb, |
583 | struct logfs_obj_alias *oa, int count); | 585 | struct logfs_obj_alias *oa, int count); |
584 | void move_page_to_btree(struct page *page); | 586 | void move_page_to_btree(struct page *page); |
585 | int logfs_init_mapping(struct super_block *sb); | 587 | int logfs_init_mapping(struct super_block *sb); |
586 | void logfs_sync_area(struct logfs_area *area); | 588 | void logfs_sync_area(struct logfs_area *area); |
587 | void logfs_sync_segments(struct super_block *sb); | 589 | void logfs_sync_segments(struct super_block *sb); |
588 | 590 | ||
589 | /* area handling */ | 591 | /* area handling */ |
590 | int logfs_init_areas(struct super_block *sb); | 592 | int logfs_init_areas(struct super_block *sb); |
591 | void logfs_cleanup_areas(struct super_block *sb); | 593 | void logfs_cleanup_areas(struct super_block *sb); |
592 | int logfs_open_area(struct logfs_area *area, size_t bytes); | 594 | int logfs_open_area(struct logfs_area *area, size_t bytes); |
593 | void __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, | 595 | void __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, |
594 | int use_filler); | 596 | int use_filler); |
595 | 597 | ||
596 | static inline void logfs_buf_write(struct logfs_area *area, u64 ofs, | 598 | static inline void logfs_buf_write(struct logfs_area *area, u64 ofs, |
597 | void *buf, size_t len) | 599 | void *buf, size_t len) |
598 | { | 600 | { |
599 | __logfs_buf_write(area, ofs, buf, len, 0); | 601 | __logfs_buf_write(area, ofs, buf, len, 0); |
600 | } | 602 | } |
601 | 603 | ||
602 | static inline void logfs_buf_recover(struct logfs_area *area, u64 ofs, | 604 | static inline void logfs_buf_recover(struct logfs_area *area, u64 ofs, |
603 | void *buf, size_t len) | 605 | void *buf, size_t len) |
604 | { | 606 | { |
605 | __logfs_buf_write(area, ofs, buf, len, 1); | 607 | __logfs_buf_write(area, ofs, buf, len, 1); |
606 | } | 608 | } |
607 | 609 | ||
608 | /* super.c */ | 610 | /* super.c */ |
609 | struct page *emergency_read_begin(struct address_space *mapping, pgoff_t index); | 611 | struct page *emergency_read_begin(struct address_space *mapping, pgoff_t index); |
610 | void emergency_read_end(struct page *page); | 612 | void emergency_read_end(struct page *page); |
611 | void logfs_crash_dump(struct super_block *sb); | 613 | void logfs_crash_dump(struct super_block *sb); |
612 | void *memchr_inv(const void *s, int c, size_t n); | 614 | void *memchr_inv(const void *s, int c, size_t n); |
613 | int logfs_statfs(struct dentry *dentry, struct kstatfs *stats); | 615 | int logfs_statfs(struct dentry *dentry, struct kstatfs *stats); |
614 | int logfs_get_sb_device(struct file_system_type *type, int flags, | 616 | int logfs_get_sb_device(struct file_system_type *type, int flags, |
615 | struct mtd_info *mtd, struct block_device *bdev, | 617 | struct mtd_info *mtd, struct block_device *bdev, |
616 | const struct logfs_device_ops *devops, struct vfsmount *mnt); | 618 | const struct logfs_device_ops *devops, struct vfsmount *mnt); |
617 | int logfs_check_ds(struct logfs_disk_super *ds); | 619 | int logfs_check_ds(struct logfs_disk_super *ds); |
618 | int logfs_write_sb(struct super_block *sb); | 620 | int logfs_write_sb(struct super_block *sb); |
619 | 621 | ||
620 | static inline struct logfs_super *logfs_super(struct super_block *sb) | 622 | static inline struct logfs_super *logfs_super(struct super_block *sb) |
621 | { | 623 | { |
622 | return sb->s_fs_info; | 624 | return sb->s_fs_info; |
623 | } | 625 | } |
624 | 626 | ||
625 | static inline struct logfs_inode *logfs_inode(struct inode *inode) | 627 | static inline struct logfs_inode *logfs_inode(struct inode *inode) |
626 | { | 628 | { |
627 | return container_of(inode, struct logfs_inode, vfs_inode); | 629 | return container_of(inode, struct logfs_inode, vfs_inode); |
628 | } | 630 | } |
629 | 631 | ||
630 | static inline void logfs_set_ro(struct super_block *sb) | 632 | static inline void logfs_set_ro(struct super_block *sb) |
631 | { | 633 | { |
632 | logfs_super(sb)->s_flags |= LOGFS_SB_FLAG_RO; | 634 | logfs_super(sb)->s_flags |= LOGFS_SB_FLAG_RO; |
633 | } | 635 | } |
634 | 636 | ||
635 | #define LOGFS_BUG(sb) do { \ | 637 | #define LOGFS_BUG(sb) do { \ |
636 | struct super_block *__sb = sb; \ | 638 | struct super_block *__sb = sb; \ |
637 | logfs_crash_dump(__sb); \ | 639 | logfs_crash_dump(__sb); \ |
638 | logfs_super(__sb)->s_flags |= LOGFS_SB_FLAG_RO; \ | 640 | logfs_super(__sb)->s_flags |= LOGFS_SB_FLAG_RO; \ |
639 | BUG(); \ | 641 | BUG(); \ |
640 | } while (0) | 642 | } while (0) |
641 | 643 | ||
642 | #define LOGFS_BUG_ON(condition, sb) \ | 644 | #define LOGFS_BUG_ON(condition, sb) \ |
643 | do { if (unlikely(condition)) LOGFS_BUG((sb)); } while (0) | 645 | do { if (unlikely(condition)) LOGFS_BUG((sb)); } while (0) |
644 | 646 | ||
645 | static inline __be32 logfs_crc32(void *data, size_t len, size_t skip) | 647 | static inline __be32 logfs_crc32(void *data, size_t len, size_t skip) |
646 | { | 648 | { |
647 | return cpu_to_be32(crc32(~0, data+skip, len-skip)); | 649 | return cpu_to_be32(crc32(~0, data+skip, len-skip)); |
648 | } | 650 | } |
649 | 651 | ||
650 | static inline u8 logfs_type(struct inode *inode) | 652 | static inline u8 logfs_type(struct inode *inode) |
651 | { | 653 | { |
652 | return (inode->i_mode >> 12) & 15; | 654 | return (inode->i_mode >> 12) & 15; |
653 | } | 655 | } |
654 | 656 | ||
655 | static inline pgoff_t logfs_index(struct super_block *sb, u64 pos) | 657 | static inline pgoff_t logfs_index(struct super_block *sb, u64 pos) |
656 | { | 658 | { |
657 | return pos >> sb->s_blocksize_bits; | 659 | return pos >> sb->s_blocksize_bits; |
658 | } | 660 | } |
659 | 661 | ||
660 | static inline u64 dev_ofs(struct super_block *sb, u32 segno, u32 ofs) | 662 | static inline u64 dev_ofs(struct super_block *sb, u32 segno, u32 ofs) |
661 | { | 663 | { |
662 | return ((u64)segno << logfs_super(sb)->s_segshift) + ofs; | 664 | return ((u64)segno << logfs_super(sb)->s_segshift) + ofs; |
663 | } | 665 | } |
664 | 666 | ||
665 | static inline u32 seg_no(struct super_block *sb, u64 ofs) | 667 | static inline u32 seg_no(struct super_block *sb, u64 ofs) |
666 | { | 668 | { |
667 | return ofs >> logfs_super(sb)->s_segshift; | 669 | return ofs >> logfs_super(sb)->s_segshift; |
668 | } | 670 | } |
669 | 671 | ||
670 | static inline u32 seg_ofs(struct super_block *sb, u64 ofs) | 672 | static inline u32 seg_ofs(struct super_block *sb, u64 ofs) |
671 | { | 673 | { |
672 | return ofs & logfs_super(sb)->s_segmask; | 674 | return ofs & logfs_super(sb)->s_segmask; |
673 | } | 675 | } |
674 | 676 | ||
675 | static inline u64 seg_align(struct super_block *sb, u64 ofs) | 677 | static inline u64 seg_align(struct super_block *sb, u64 ofs) |
676 | { | 678 | { |
677 | return ofs & ~logfs_super(sb)->s_segmask; | 679 | return ofs & ~logfs_super(sb)->s_segmask; |
678 | } | 680 | } |
679 | 681 | ||
680 | static inline struct logfs_block *logfs_block(struct page *page) | 682 | static inline struct logfs_block *logfs_block(struct page *page) |
681 | { | 683 | { |
682 | return (void *)page->private; | 684 | return (void *)page->private; |
683 | } | 685 | } |
684 | 686 | ||
685 | static inline level_t shrink_level(gc_level_t __level) | 687 | static inline level_t shrink_level(gc_level_t __level) |
686 | { | 688 | { |
687 | u8 level = (__force u8)__level; | 689 | u8 level = (__force u8)__level; |
688 | 690 | ||
689 | if (level >= LOGFS_MAX_LEVELS) | 691 | if (level >= LOGFS_MAX_LEVELS) |
690 | level -= LOGFS_MAX_LEVELS; | 692 | level -= LOGFS_MAX_LEVELS; |
691 | return (__force level_t)level; | 693 | return (__force level_t)level; |
692 | } | 694 | } |
693 | 695 | ||
694 | static inline gc_level_t expand_level(u64 ino, level_t __level) | 696 | static inline gc_level_t expand_level(u64 ino, level_t __level) |
695 | { | 697 | { |
696 | u8 level = (__force u8)__level; | 698 | u8 level = (__force u8)__level; |
697 | 699 | ||
698 | if (ino == LOGFS_INO_MASTER) { | 700 | if (ino == LOGFS_INO_MASTER) { |
699 | /* ifile has seperate areas */ | 701 | /* ifile has seperate areas */ |
700 | level += LOGFS_MAX_LEVELS; | 702 | level += LOGFS_MAX_LEVELS; |
701 | } | 703 | } |
702 | return (__force gc_level_t)level; | 704 | return (__force gc_level_t)level; |
703 | } | 705 | } |
704 | 706 | ||
705 | static inline int logfs_block_shift(struct super_block *sb, level_t level) | 707 | static inline int logfs_block_shift(struct super_block *sb, level_t level) |
706 | { | 708 | { |
707 | level = shrink_level((__force gc_level_t)level); | 709 | level = shrink_level((__force gc_level_t)level); |
708 | return (__force int)level * (sb->s_blocksize_bits - 3); | 710 | return (__force int)level * (sb->s_blocksize_bits - 3); |
709 | } | 711 | } |
710 | 712 | ||
711 | static inline u64 logfs_block_mask(struct super_block *sb, level_t level) | 713 | static inline u64 logfs_block_mask(struct super_block *sb, level_t level) |
712 | { | 714 | { |
713 | return ~0ull << logfs_block_shift(sb, level); | 715 | return ~0ull << logfs_block_shift(sb, level); |
714 | } | 716 | } |
715 | 717 | ||
716 | static inline struct logfs_area *get_area(struct super_block *sb, | 718 | static inline struct logfs_area *get_area(struct super_block *sb, |
717 | gc_level_t gc_level) | 719 | gc_level_t gc_level) |
718 | { | 720 | { |
719 | return logfs_super(sb)->s_area[(__force u8)gc_level]; | 721 | return logfs_super(sb)->s_area[(__force u8)gc_level]; |
720 | } | 722 | } |
721 | 723 | ||
722 | #endif | 724 | #endif |
723 | 725 |
fs/logfs/segment.c
1 | /* | 1 | /* |
2 | * fs/logfs/segment.c - Handling the Object Store | 2 | * fs/logfs/segment.c - Handling the Object Store |
3 | * | 3 | * |
4 | * As should be obvious for Linux kernel code, license is GPLv2 | 4 | * As should be obvious for Linux kernel code, license is GPLv2 |
5 | * | 5 | * |
6 | * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org> | 6 | * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org> |
7 | * | 7 | * |
8 | * Object store or ostore makes up the complete device with exception of | 8 | * Object store or ostore makes up the complete device with exception of |
9 | * the superblock and journal areas. Apart from its own metadata it stores | 9 | * the superblock and journal areas. Apart from its own metadata it stores |
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 | 13 | ||
14 | static int logfs_mark_segment_bad(struct super_block *sb, u32 segno) | 14 | static int logfs_mark_segment_bad(struct super_block *sb, u32 segno) |
15 | { | 15 | { |
16 | struct logfs_super *super = logfs_super(sb); | 16 | struct logfs_super *super = logfs_super(sb); |
17 | struct btree_head32 *head = &super->s_reserved_segments; | 17 | struct btree_head32 *head = &super->s_reserved_segments; |
18 | int err; | 18 | int err; |
19 | 19 | ||
20 | err = btree_insert32(head, segno, (void *)1, GFP_NOFS); | 20 | err = btree_insert32(head, segno, (void *)1, GFP_NOFS); |
21 | if (err) | 21 | if (err) |
22 | return err; | 22 | return err; |
23 | logfs_super(sb)->s_bad_segments++; | 23 | logfs_super(sb)->s_bad_segments++; |
24 | /* FIXME: write to journal */ | 24 | /* FIXME: write to journal */ |
25 | return 0; | 25 | return 0; |
26 | } | 26 | } |
27 | 27 | ||
28 | int logfs_erase_segment(struct super_block *sb, u32 segno) | 28 | int logfs_erase_segment(struct super_block *sb, u32 segno, int ensure_erase) |
29 | { | 29 | { |
30 | struct logfs_super *super = logfs_super(sb); | 30 | struct logfs_super *super = logfs_super(sb); |
31 | 31 | ||
32 | super->s_gec++; | 32 | super->s_gec++; |
33 | 33 | ||
34 | return super->s_devops->erase(sb, (u64)segno << super->s_segshift, | 34 | return super->s_devops->erase(sb, (u64)segno << super->s_segshift, |
35 | super->s_segsize); | 35 | super->s_segsize, ensure_erase); |
36 | } | 36 | } |
37 | 37 | ||
38 | static s64 logfs_get_free_bytes(struct logfs_area *area, size_t bytes) | 38 | static s64 logfs_get_free_bytes(struct logfs_area *area, size_t bytes) |
39 | { | 39 | { |
40 | s32 ofs; | 40 | s32 ofs; |
41 | 41 | ||
42 | logfs_open_area(area, bytes); | 42 | logfs_open_area(area, bytes); |
43 | 43 | ||
44 | ofs = area->a_used_bytes; | 44 | ofs = area->a_used_bytes; |
45 | area->a_used_bytes += bytes; | 45 | area->a_used_bytes += bytes; |
46 | BUG_ON(area->a_used_bytes >= logfs_super(area->a_sb)->s_segsize); | 46 | BUG_ON(area->a_used_bytes >= logfs_super(area->a_sb)->s_segsize); |
47 | 47 | ||
48 | return dev_ofs(area->a_sb, area->a_segno, ofs); | 48 | return dev_ofs(area->a_sb, area->a_segno, ofs); |
49 | } | 49 | } |
50 | 50 | ||
51 | static struct page *get_mapping_page(struct super_block *sb, pgoff_t index, | 51 | static struct page *get_mapping_page(struct super_block *sb, pgoff_t index, |
52 | int use_filler) | 52 | int use_filler) |
53 | { | 53 | { |
54 | struct logfs_super *super = logfs_super(sb); | 54 | struct logfs_super *super = logfs_super(sb); |
55 | struct address_space *mapping = super->s_mapping_inode->i_mapping; | 55 | struct address_space *mapping = super->s_mapping_inode->i_mapping; |
56 | filler_t *filler = super->s_devops->readpage; | 56 | filler_t *filler = super->s_devops->readpage; |
57 | struct page *page; | 57 | struct page *page; |
58 | 58 | ||
59 | BUG_ON(mapping_gfp_mask(mapping) & __GFP_FS); | 59 | BUG_ON(mapping_gfp_mask(mapping) & __GFP_FS); |
60 | if (use_filler) | 60 | if (use_filler) |
61 | page = read_cache_page(mapping, index, filler, sb); | 61 | page = read_cache_page(mapping, index, filler, sb); |
62 | else { | 62 | else { |
63 | page = find_or_create_page(mapping, index, GFP_NOFS); | 63 | page = find_or_create_page(mapping, index, GFP_NOFS); |
64 | unlock_page(page); | 64 | unlock_page(page); |
65 | } | 65 | } |
66 | return page; | 66 | return page; |
67 | } | 67 | } |
68 | 68 | ||
69 | void __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, | 69 | void __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, |
70 | int use_filler) | 70 | int use_filler) |
71 | { | 71 | { |
72 | pgoff_t index = ofs >> PAGE_SHIFT; | 72 | pgoff_t index = ofs >> PAGE_SHIFT; |
73 | struct page *page; | 73 | struct page *page; |
74 | long offset = ofs & (PAGE_SIZE-1); | 74 | long offset = ofs & (PAGE_SIZE-1); |
75 | long copylen; | 75 | long copylen; |
76 | 76 | ||
77 | /* Only logfs_wbuf_recover may use len==0 */ | 77 | /* Only logfs_wbuf_recover may use len==0 */ |
78 | BUG_ON(!len && !use_filler); | 78 | BUG_ON(!len && !use_filler); |
79 | do { | 79 | do { |
80 | copylen = min((ulong)len, PAGE_SIZE - offset); | 80 | copylen = min((ulong)len, PAGE_SIZE - offset); |
81 | 81 | ||
82 | page = get_mapping_page(area->a_sb, index, use_filler); | 82 | page = get_mapping_page(area->a_sb, index, use_filler); |
83 | SetPageUptodate(page); | 83 | SetPageUptodate(page); |
84 | BUG_ON(!page); /* FIXME: reserve a pool */ | 84 | BUG_ON(!page); /* FIXME: reserve a pool */ |
85 | memcpy(page_address(page) + offset, buf, copylen); | 85 | memcpy(page_address(page) + offset, buf, copylen); |
86 | SetPagePrivate(page); | 86 | SetPagePrivate(page); |
87 | page_cache_release(page); | 87 | page_cache_release(page); |
88 | 88 | ||
89 | buf += copylen; | 89 | buf += copylen; |
90 | len -= copylen; | 90 | len -= copylen; |
91 | offset = 0; | 91 | offset = 0; |
92 | index++; | 92 | index++; |
93 | } while (len); | 93 | } while (len); |
94 | } | 94 | } |
95 | 95 | ||
96 | /* | 96 | /* |
97 | * bdev_writeseg will write full pages. Memset the tail to prevent data leaks. | 97 | * bdev_writeseg will write full pages. Memset the tail to prevent data leaks. |
98 | */ | 98 | */ |
99 | static void pad_wbuf(struct logfs_area *area, int final) | 99 | static void pad_wbuf(struct logfs_area *area, int final) |
100 | { | 100 | { |
101 | struct super_block *sb = area->a_sb; | 101 | struct super_block *sb = area->a_sb; |
102 | struct logfs_super *super = logfs_super(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 | /* The math in this function can surely use some love */ |
111 | len = 0; | 111 | len = 0; |
112 | } | 112 | } |
113 | if (len) { | 113 | if (len) { |
114 | BUG_ON(area->a_used_bytes >= super->s_segsize); | 114 | BUG_ON(area->a_used_bytes >= super->s_segsize); |
115 | 115 | ||
116 | page = get_mapping_page(area->a_sb, index, 0); | 116 | page = get_mapping_page(area->a_sb, index, 0); |
117 | BUG_ON(!page); /* FIXME: reserve a pool */ | 117 | BUG_ON(!page); /* FIXME: reserve a pool */ |
118 | memset(page_address(page) + offset, 0xff, len); | 118 | memset(page_address(page) + offset, 0xff, len); |
119 | SetPagePrivate(page); | 119 | SetPagePrivate(page); |
120 | page_cache_release(page); | 120 | page_cache_release(page); |
121 | } | 121 | } |
122 | 122 | ||
123 | if (!final) | 123 | if (!final) |
124 | return; | 124 | return; |
125 | 125 | ||
126 | area->a_used_bytes += len; | 126 | area->a_used_bytes += len; |
127 | for ( ; area->a_used_bytes < super->s_segsize; | 127 | for ( ; area->a_used_bytes < super->s_segsize; |
128 | area->a_used_bytes += PAGE_SIZE) { | 128 | area->a_used_bytes += PAGE_SIZE) { |
129 | /* Memset another page */ | 129 | /* Memset another page */ |
130 | index++; | 130 | index++; |
131 | page = get_mapping_page(area->a_sb, index, 0); | 131 | page = get_mapping_page(area->a_sb, index, 0); |
132 | BUG_ON(!page); /* FIXME: reserve a pool */ | 132 | BUG_ON(!page); /* FIXME: reserve a pool */ |
133 | memset(page_address(page), 0xff, PAGE_SIZE); | 133 | memset(page_address(page), 0xff, PAGE_SIZE); |
134 | SetPagePrivate(page); | 134 | SetPagePrivate(page); |
135 | page_cache_release(page); | 135 | page_cache_release(page); |
136 | } | 136 | } |
137 | } | 137 | } |
138 | 138 | ||
139 | /* | 139 | /* |
140 | * We have to be careful with the alias tree. Since lookup is done by bix, | 140 | * 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 | 141 | * 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. | 142 | * indirect blocks. So always use it through accessor functions. |
143 | */ | 143 | */ |
144 | static void *alias_tree_lookup(struct super_block *sb, u64 ino, u64 bix, | 144 | static void *alias_tree_lookup(struct super_block *sb, u64 ino, u64 bix, |
145 | level_t level) | 145 | level_t level) |
146 | { | 146 | { |
147 | struct btree_head128 *head = &logfs_super(sb)->s_object_alias_tree; | 147 | struct btree_head128 *head = &logfs_super(sb)->s_object_alias_tree; |
148 | pgoff_t index = logfs_pack_index(bix, level); | 148 | pgoff_t index = logfs_pack_index(bix, level); |
149 | 149 | ||
150 | return btree_lookup128(head, ino, index); | 150 | return btree_lookup128(head, ino, index); |
151 | } | 151 | } |
152 | 152 | ||
153 | static int alias_tree_insert(struct super_block *sb, u64 ino, u64 bix, | 153 | static int alias_tree_insert(struct super_block *sb, u64 ino, u64 bix, |
154 | level_t level, void *val) | 154 | level_t level, void *val) |
155 | { | 155 | { |
156 | struct btree_head128 *head = &logfs_super(sb)->s_object_alias_tree; | 156 | struct btree_head128 *head = &logfs_super(sb)->s_object_alias_tree; |
157 | pgoff_t index = logfs_pack_index(bix, level); | 157 | pgoff_t index = logfs_pack_index(bix, level); |
158 | 158 | ||
159 | return btree_insert128(head, ino, index, val, GFP_NOFS); | 159 | return btree_insert128(head, ino, index, val, GFP_NOFS); |
160 | } | 160 | } |
161 | 161 | ||
162 | static int btree_write_alias(struct super_block *sb, struct logfs_block *block, | 162 | static int btree_write_alias(struct super_block *sb, struct logfs_block *block, |
163 | write_alias_t *write_one_alias) | 163 | write_alias_t *write_one_alias) |
164 | { | 164 | { |
165 | struct object_alias_item *item; | 165 | struct object_alias_item *item; |
166 | int err; | 166 | int err; |
167 | 167 | ||
168 | list_for_each_entry(item, &block->item_list, list) { | 168 | list_for_each_entry(item, &block->item_list, list) { |
169 | err = write_alias_journal(sb, block->ino, block->bix, | 169 | err = write_alias_journal(sb, block->ino, block->bix, |
170 | block->level, item->child_no, item->val); | 170 | block->level, item->child_no, item->val); |
171 | if (err) | 171 | if (err) |
172 | return err; | 172 | return err; |
173 | } | 173 | } |
174 | return 0; | 174 | return 0; |
175 | } | 175 | } |
176 | 176 | ||
177 | static gc_level_t btree_block_level(struct logfs_block *block) | 177 | static gc_level_t btree_block_level(struct logfs_block *block) |
178 | { | 178 | { |
179 | return expand_level(block->ino, block->level); | 179 | return expand_level(block->ino, block->level); |
180 | } | 180 | } |
181 | 181 | ||
182 | static struct logfs_block_ops btree_block_ops = { | 182 | static struct logfs_block_ops btree_block_ops = { |
183 | .write_block = btree_write_block, | 183 | .write_block = btree_write_block, |
184 | .block_level = btree_block_level, | 184 | .block_level = btree_block_level, |
185 | .free_block = __free_block, | 185 | .free_block = __free_block, |
186 | .write_alias = btree_write_alias, | 186 | .write_alias = btree_write_alias, |
187 | }; | 187 | }; |
188 | 188 | ||
189 | int logfs_load_object_aliases(struct super_block *sb, | 189 | int logfs_load_object_aliases(struct super_block *sb, |
190 | struct logfs_obj_alias *oa, int count) | 190 | struct logfs_obj_alias *oa, int count) |
191 | { | 191 | { |
192 | struct logfs_super *super = logfs_super(sb); | 192 | struct logfs_super *super = logfs_super(sb); |
193 | struct logfs_block *block; | 193 | struct logfs_block *block; |
194 | struct object_alias_item *item; | 194 | struct object_alias_item *item; |
195 | u64 ino, bix; | 195 | u64 ino, bix; |
196 | level_t level; | 196 | level_t level; |
197 | int i, err; | 197 | int i, err; |
198 | 198 | ||
199 | super->s_flags |= LOGFS_SB_FLAG_OBJ_ALIAS; | 199 | super->s_flags |= LOGFS_SB_FLAG_OBJ_ALIAS; |
200 | count /= sizeof(*oa); | 200 | count /= sizeof(*oa); |
201 | for (i = 0; i < count; i++) { | 201 | for (i = 0; i < count; i++) { |
202 | item = mempool_alloc(super->s_alias_pool, GFP_NOFS); | 202 | item = mempool_alloc(super->s_alias_pool, GFP_NOFS); |
203 | if (!item) | 203 | if (!item) |
204 | return -ENOMEM; | 204 | return -ENOMEM; |
205 | memset(item, 0, sizeof(*item)); | 205 | memset(item, 0, sizeof(*item)); |
206 | 206 | ||
207 | super->s_no_object_aliases++; | 207 | super->s_no_object_aliases++; |
208 | item->val = oa[i].val; | 208 | item->val = oa[i].val; |
209 | item->child_no = be16_to_cpu(oa[i].child_no); | 209 | item->child_no = be16_to_cpu(oa[i].child_no); |
210 | 210 | ||
211 | ino = be64_to_cpu(oa[i].ino); | 211 | ino = be64_to_cpu(oa[i].ino); |
212 | bix = be64_to_cpu(oa[i].bix); | 212 | bix = be64_to_cpu(oa[i].bix); |
213 | level = LEVEL(oa[i].level); | 213 | level = LEVEL(oa[i].level); |
214 | 214 | ||
215 | log_aliases("logfs_load_object_aliases(%llx, %llx, %x, %x) %llx\n", | 215 | log_aliases("logfs_load_object_aliases(%llx, %llx, %x, %x) %llx\n", |
216 | ino, bix, level, item->child_no, | 216 | ino, bix, level, item->child_no, |
217 | be64_to_cpu(item->val)); | 217 | be64_to_cpu(item->val)); |
218 | block = alias_tree_lookup(sb, ino, bix, level); | 218 | block = alias_tree_lookup(sb, ino, bix, level); |
219 | if (!block) { | 219 | if (!block) { |
220 | block = __alloc_block(sb, ino, bix, level); | 220 | block = __alloc_block(sb, ino, bix, level); |
221 | block->ops = &btree_block_ops; | 221 | block->ops = &btree_block_ops; |
222 | err = alias_tree_insert(sb, ino, bix, level, block); | 222 | err = alias_tree_insert(sb, ino, bix, level, block); |
223 | BUG_ON(err); /* mempool empty */ | 223 | BUG_ON(err); /* mempool empty */ |
224 | } | 224 | } |
225 | if (test_and_set_bit(item->child_no, block->alias_map)) { | 225 | if (test_and_set_bit(item->child_no, block->alias_map)) { |
226 | printk(KERN_ERR"LogFS: Alias collision detected\n"); | 226 | printk(KERN_ERR"LogFS: Alias collision detected\n"); |
227 | return -EIO; | 227 | return -EIO; |
228 | } | 228 | } |
229 | list_move_tail(&block->alias_list, &super->s_object_alias); | 229 | list_move_tail(&block->alias_list, &super->s_object_alias); |
230 | list_add(&item->list, &block->item_list); | 230 | list_add(&item->list, &block->item_list); |
231 | } | 231 | } |
232 | return 0; | 232 | return 0; |
233 | } | 233 | } |
234 | 234 | ||
235 | static void kill_alias(void *_block, unsigned long ignore0, | 235 | static void kill_alias(void *_block, unsigned long ignore0, |
236 | u64 ignore1, u64 ignore2, size_t ignore3) | 236 | u64 ignore1, u64 ignore2, size_t ignore3) |
237 | { | 237 | { |
238 | struct logfs_block *block = _block; | 238 | struct logfs_block *block = _block; |
239 | struct super_block *sb = block->sb; | 239 | struct super_block *sb = block->sb; |
240 | struct logfs_super *super = logfs_super(sb); | 240 | struct logfs_super *super = logfs_super(sb); |
241 | struct object_alias_item *item; | 241 | struct object_alias_item *item; |
242 | 242 | ||
243 | while (!list_empty(&block->item_list)) { | 243 | while (!list_empty(&block->item_list)) { |
244 | item = list_entry(block->item_list.next, typeof(*item), list); | 244 | item = list_entry(block->item_list.next, typeof(*item), list); |
245 | list_del(&item->list); | 245 | list_del(&item->list); |
246 | mempool_free(item, super->s_alias_pool); | 246 | mempool_free(item, super->s_alias_pool); |
247 | } | 247 | } |
248 | block->ops->free_block(sb, block); | 248 | block->ops->free_block(sb, block); |
249 | } | 249 | } |
250 | 250 | ||
251 | static int obj_type(struct inode *inode, level_t level) | 251 | static int obj_type(struct inode *inode, level_t level) |
252 | { | 252 | { |
253 | if (level == 0) { | 253 | if (level == 0) { |
254 | if (S_ISDIR(inode->i_mode)) | 254 | if (S_ISDIR(inode->i_mode)) |
255 | return OBJ_DENTRY; | 255 | return OBJ_DENTRY; |
256 | if (inode->i_ino == LOGFS_INO_MASTER) | 256 | if (inode->i_ino == LOGFS_INO_MASTER) |
257 | return OBJ_INODE; | 257 | return OBJ_INODE; |
258 | } | 258 | } |
259 | return OBJ_BLOCK; | 259 | return OBJ_BLOCK; |
260 | } | 260 | } |
261 | 261 | ||
262 | static int obj_len(struct super_block *sb, int obj_type) | 262 | static int obj_len(struct super_block *sb, int obj_type) |
263 | { | 263 | { |
264 | switch (obj_type) { | 264 | switch (obj_type) { |
265 | case OBJ_DENTRY: | 265 | case OBJ_DENTRY: |
266 | return sizeof(struct logfs_disk_dentry); | 266 | return sizeof(struct logfs_disk_dentry); |
267 | case OBJ_INODE: | 267 | case OBJ_INODE: |
268 | return sizeof(struct logfs_disk_inode); | 268 | return sizeof(struct logfs_disk_inode); |
269 | case OBJ_BLOCK: | 269 | case OBJ_BLOCK: |
270 | return sb->s_blocksize; | 270 | return sb->s_blocksize; |
271 | default: | 271 | default: |
272 | BUG(); | 272 | BUG(); |
273 | } | 273 | } |
274 | } | 274 | } |
275 | 275 | ||
276 | static int __logfs_segment_write(struct inode *inode, void *buf, | 276 | static int __logfs_segment_write(struct inode *inode, void *buf, |
277 | struct logfs_shadow *shadow, int type, int len, int compr) | 277 | struct logfs_shadow *shadow, int type, int len, int compr) |
278 | { | 278 | { |
279 | struct logfs_area *area; | 279 | struct logfs_area *area; |
280 | struct super_block *sb = inode->i_sb; | 280 | struct super_block *sb = inode->i_sb; |
281 | s64 ofs; | 281 | s64 ofs; |
282 | struct logfs_object_header h; | 282 | struct logfs_object_header h; |
283 | int acc_len; | 283 | int acc_len; |
284 | 284 | ||
285 | if (shadow->gc_level == 0) | 285 | if (shadow->gc_level == 0) |
286 | acc_len = len; | 286 | acc_len = len; |
287 | else | 287 | else |
288 | acc_len = obj_len(sb, type); | 288 | acc_len = obj_len(sb, type); |
289 | 289 | ||
290 | area = get_area(sb, shadow->gc_level); | 290 | area = get_area(sb, shadow->gc_level); |
291 | ofs = logfs_get_free_bytes(area, len + LOGFS_OBJECT_HEADERSIZE); | 291 | ofs = logfs_get_free_bytes(area, len + LOGFS_OBJECT_HEADERSIZE); |
292 | LOGFS_BUG_ON(ofs <= 0, sb); | 292 | LOGFS_BUG_ON(ofs <= 0, sb); |
293 | /* | 293 | /* |
294 | * Order is important. logfs_get_free_bytes(), by modifying the | 294 | * Order is important. logfs_get_free_bytes(), by modifying the |
295 | * segment file, may modify the content of the very page we're about | 295 | * segment file, may modify the content of the very page we're about |
296 | * to write now. Which is fine, as long as the calculated crc and | 296 | * to write now. Which is fine, as long as the calculated crc and |
297 | * written data still match. So do the modifications _before_ | 297 | * written data still match. So do the modifications _before_ |
298 | * calculating the crc. | 298 | * calculating the crc. |
299 | */ | 299 | */ |
300 | 300 | ||
301 | h.len = cpu_to_be16(len); | 301 | h.len = cpu_to_be16(len); |
302 | h.type = type; | 302 | h.type = type; |
303 | h.compr = compr; | 303 | h.compr = compr; |
304 | h.ino = cpu_to_be64(inode->i_ino); | 304 | h.ino = cpu_to_be64(inode->i_ino); |
305 | h.bix = cpu_to_be64(shadow->bix); | 305 | h.bix = cpu_to_be64(shadow->bix); |
306 | h.crc = logfs_crc32(&h, sizeof(h) - 4, 4); | 306 | h.crc = logfs_crc32(&h, sizeof(h) - 4, 4); |
307 | h.data_crc = logfs_crc32(buf, len, 0); | 307 | h.data_crc = logfs_crc32(buf, len, 0); |
308 | 308 | ||
309 | logfs_buf_write(area, ofs, &h, sizeof(h)); | 309 | logfs_buf_write(area, ofs, &h, sizeof(h)); |
310 | logfs_buf_write(area, ofs + LOGFS_OBJECT_HEADERSIZE, buf, len); | 310 | logfs_buf_write(area, ofs + LOGFS_OBJECT_HEADERSIZE, buf, len); |
311 | 311 | ||
312 | shadow->new_ofs = ofs; | 312 | shadow->new_ofs = ofs; |
313 | shadow->new_len = acc_len + LOGFS_OBJECT_HEADERSIZE; | 313 | shadow->new_len = acc_len + LOGFS_OBJECT_HEADERSIZE; |
314 | 314 | ||
315 | return 0; | 315 | return 0; |
316 | } | 316 | } |
317 | 317 | ||
318 | static s64 logfs_segment_write_compress(struct inode *inode, void *buf, | 318 | static s64 logfs_segment_write_compress(struct inode *inode, void *buf, |
319 | struct logfs_shadow *shadow, int type, int len) | 319 | struct logfs_shadow *shadow, int type, int len) |
320 | { | 320 | { |
321 | struct super_block *sb = inode->i_sb; | 321 | struct super_block *sb = inode->i_sb; |
322 | void *compressor_buf = logfs_super(sb)->s_compressed_je; | 322 | void *compressor_buf = logfs_super(sb)->s_compressed_je; |
323 | ssize_t compr_len; | 323 | ssize_t compr_len; |
324 | int ret; | 324 | int ret; |
325 | 325 | ||
326 | mutex_lock(&logfs_super(sb)->s_journal_mutex); | 326 | mutex_lock(&logfs_super(sb)->s_journal_mutex); |
327 | compr_len = logfs_compress(buf, compressor_buf, len, len); | 327 | compr_len = logfs_compress(buf, compressor_buf, len, len); |
328 | 328 | ||
329 | if (compr_len >= 0) { | 329 | if (compr_len >= 0) { |
330 | ret = __logfs_segment_write(inode, compressor_buf, shadow, | 330 | ret = __logfs_segment_write(inode, compressor_buf, shadow, |
331 | type, compr_len, COMPR_ZLIB); | 331 | type, compr_len, COMPR_ZLIB); |
332 | } else { | 332 | } else { |
333 | ret = __logfs_segment_write(inode, buf, shadow, type, len, | 333 | ret = __logfs_segment_write(inode, buf, shadow, type, len, |
334 | COMPR_NONE); | 334 | COMPR_NONE); |
335 | } | 335 | } |
336 | mutex_unlock(&logfs_super(sb)->s_journal_mutex); | 336 | mutex_unlock(&logfs_super(sb)->s_journal_mutex); |
337 | return ret; | 337 | return ret; |
338 | } | 338 | } |
339 | 339 | ||
340 | /** | 340 | /** |
341 | * logfs_segment_write - write data block to object store | 341 | * logfs_segment_write - write data block to object store |
342 | * @inode: inode containing data | 342 | * @inode: inode containing data |
343 | * | 343 | * |
344 | * Returns an errno or zero. | 344 | * Returns an errno or zero. |
345 | */ | 345 | */ |
346 | int logfs_segment_write(struct inode *inode, struct page *page, | 346 | int logfs_segment_write(struct inode *inode, struct page *page, |
347 | struct logfs_shadow *shadow) | 347 | struct logfs_shadow *shadow) |
348 | { | 348 | { |
349 | struct super_block *sb = inode->i_sb; | 349 | struct super_block *sb = inode->i_sb; |
350 | struct logfs_super *super = logfs_super(sb); | 350 | struct logfs_super *super = logfs_super(sb); |
351 | int do_compress, type, len; | 351 | int do_compress, type, len; |
352 | int ret; | 352 | int ret; |
353 | void *buf; | 353 | void *buf; |
354 | 354 | ||
355 | BUG_ON(logfs_super(sb)->s_flags & LOGFS_SB_FLAG_SHUTDOWN); | 355 | BUG_ON(logfs_super(sb)->s_flags & LOGFS_SB_FLAG_SHUTDOWN); |
356 | do_compress = logfs_inode(inode)->li_flags & LOGFS_IF_COMPRESSED; | 356 | do_compress = logfs_inode(inode)->li_flags & LOGFS_IF_COMPRESSED; |
357 | if (shadow->gc_level != 0) { | 357 | if (shadow->gc_level != 0) { |
358 | /* temporarily disable compression for indirect blocks */ | 358 | /* temporarily disable compression for indirect blocks */ |
359 | do_compress = 0; | 359 | do_compress = 0; |
360 | } | 360 | } |
361 | 361 | ||
362 | type = obj_type(inode, shrink_level(shadow->gc_level)); | 362 | type = obj_type(inode, shrink_level(shadow->gc_level)); |
363 | len = obj_len(sb, type); | 363 | len = obj_len(sb, type); |
364 | buf = kmap(page); | 364 | buf = kmap(page); |
365 | if (do_compress) | 365 | if (do_compress) |
366 | ret = logfs_segment_write_compress(inode, buf, shadow, type, | 366 | ret = logfs_segment_write_compress(inode, buf, shadow, type, |
367 | len); | 367 | len); |
368 | else | 368 | else |
369 | ret = __logfs_segment_write(inode, buf, shadow, type, len, | 369 | ret = __logfs_segment_write(inode, buf, shadow, type, len, |
370 | COMPR_NONE); | 370 | COMPR_NONE); |
371 | kunmap(page); | 371 | kunmap(page); |
372 | 372 | ||
373 | log_segment("logfs_segment_write(%llx, %llx, %x) %llx->%llx %x->%x\n", | 373 | log_segment("logfs_segment_write(%llx, %llx, %x) %llx->%llx %x->%x\n", |
374 | shadow->ino, shadow->bix, shadow->gc_level, | 374 | shadow->ino, shadow->bix, shadow->gc_level, |
375 | shadow->old_ofs, shadow->new_ofs, | 375 | shadow->old_ofs, shadow->new_ofs, |
376 | shadow->old_len, shadow->new_len); | 376 | shadow->old_len, shadow->new_len); |
377 | /* this BUG_ON did catch a locking bug. useful */ | 377 | /* this BUG_ON did catch a locking bug. useful */ |
378 | BUG_ON(!(shadow->new_ofs & (super->s_segsize - 1))); | 378 | BUG_ON(!(shadow->new_ofs & (super->s_segsize - 1))); |
379 | return ret; | 379 | return ret; |
380 | } | 380 | } |
381 | 381 | ||
382 | int wbuf_read(struct super_block *sb, u64 ofs, size_t len, void *buf) | 382 | int wbuf_read(struct super_block *sb, u64 ofs, size_t len, void *buf) |
383 | { | 383 | { |
384 | pgoff_t index = ofs >> PAGE_SHIFT; | 384 | pgoff_t index = ofs >> PAGE_SHIFT; |
385 | struct page *page; | 385 | struct page *page; |
386 | long offset = ofs & (PAGE_SIZE-1); | 386 | long offset = ofs & (PAGE_SIZE-1); |
387 | long copylen; | 387 | long copylen; |
388 | 388 | ||
389 | while (len) { | 389 | while (len) { |
390 | copylen = min((ulong)len, PAGE_SIZE - offset); | 390 | copylen = min((ulong)len, PAGE_SIZE - offset); |
391 | 391 | ||
392 | page = get_mapping_page(sb, index, 1); | 392 | page = get_mapping_page(sb, index, 1); |
393 | if (IS_ERR(page)) | 393 | if (IS_ERR(page)) |
394 | return PTR_ERR(page); | 394 | return PTR_ERR(page); |
395 | memcpy(buf, page_address(page) + offset, copylen); | 395 | memcpy(buf, page_address(page) + offset, copylen); |
396 | page_cache_release(page); | 396 | page_cache_release(page); |
397 | 397 | ||
398 | buf += copylen; | 398 | buf += copylen; |
399 | len -= copylen; | 399 | len -= copylen; |
400 | offset = 0; | 400 | offset = 0; |
401 | index++; | 401 | index++; |
402 | } | 402 | } |
403 | return 0; | 403 | return 0; |
404 | } | 404 | } |
405 | 405 | ||
406 | /* | 406 | /* |
407 | * The "position" of indirect blocks is ambiguous. It can be the position | 407 | * The "position" of indirect blocks is ambiguous. It can be the position |
408 | * of any data block somewhere behind this indirect block. So we need to | 408 | * of any data block somewhere behind this indirect block. So we need to |
409 | * normalize the positions through logfs_block_mask() before comparing. | 409 | * normalize the positions through logfs_block_mask() before comparing. |
410 | */ | 410 | */ |
411 | static int check_pos(struct super_block *sb, u64 pos1, u64 pos2, level_t level) | 411 | static int check_pos(struct super_block *sb, u64 pos1, u64 pos2, level_t level) |
412 | { | 412 | { |
413 | return (pos1 & logfs_block_mask(sb, level)) != | 413 | return (pos1 & logfs_block_mask(sb, level)) != |
414 | (pos2 & logfs_block_mask(sb, level)); | 414 | (pos2 & logfs_block_mask(sb, level)); |
415 | } | 415 | } |
416 | 416 | ||
417 | #if 0 | 417 | #if 0 |
418 | static int read_seg_header(struct super_block *sb, u64 ofs, | 418 | static int read_seg_header(struct super_block *sb, u64 ofs, |
419 | struct logfs_segment_header *sh) | 419 | struct logfs_segment_header *sh) |
420 | { | 420 | { |
421 | __be32 crc; | 421 | __be32 crc; |
422 | int err; | 422 | int err; |
423 | 423 | ||
424 | err = wbuf_read(sb, ofs, sizeof(*sh), sh); | 424 | err = wbuf_read(sb, ofs, sizeof(*sh), sh); |
425 | if (err) | 425 | if (err) |
426 | return err; | 426 | return err; |
427 | crc = logfs_crc32(sh, sizeof(*sh), 4); | 427 | crc = logfs_crc32(sh, sizeof(*sh), 4); |
428 | if (crc != sh->crc) { | 428 | if (crc != sh->crc) { |
429 | printk(KERN_ERR"LOGFS: header crc error at %llx: expected %x, " | 429 | printk(KERN_ERR"LOGFS: header crc error at %llx: expected %x, " |
430 | "got %x\n", ofs, be32_to_cpu(sh->crc), | 430 | "got %x\n", ofs, be32_to_cpu(sh->crc), |
431 | be32_to_cpu(crc)); | 431 | be32_to_cpu(crc)); |
432 | return -EIO; | 432 | return -EIO; |
433 | } | 433 | } |
434 | return 0; | 434 | return 0; |
435 | } | 435 | } |
436 | #endif | 436 | #endif |
437 | 437 | ||
438 | static int read_obj_header(struct super_block *sb, u64 ofs, | 438 | static int read_obj_header(struct super_block *sb, u64 ofs, |
439 | struct logfs_object_header *oh) | 439 | struct logfs_object_header *oh) |
440 | { | 440 | { |
441 | __be32 crc; | 441 | __be32 crc; |
442 | int err; | 442 | int err; |
443 | 443 | ||
444 | err = wbuf_read(sb, ofs, sizeof(*oh), oh); | 444 | err = wbuf_read(sb, ofs, sizeof(*oh), oh); |
445 | if (err) | 445 | if (err) |
446 | return err; | 446 | return err; |
447 | crc = logfs_crc32(oh, sizeof(*oh) - 4, 4); | 447 | crc = logfs_crc32(oh, sizeof(*oh) - 4, 4); |
448 | if (crc != oh->crc) { | 448 | if (crc != oh->crc) { |
449 | printk(KERN_ERR"LOGFS: header crc error at %llx: expected %x, " | 449 | printk(KERN_ERR"LOGFS: header crc error at %llx: expected %x, " |
450 | "got %x\n", ofs, be32_to_cpu(oh->crc), | 450 | "got %x\n", ofs, be32_to_cpu(oh->crc), |
451 | be32_to_cpu(crc)); | 451 | be32_to_cpu(crc)); |
452 | return -EIO; | 452 | return -EIO; |
453 | } | 453 | } |
454 | return 0; | 454 | return 0; |
455 | } | 455 | } |
456 | 456 | ||
457 | static void move_btree_to_page(struct inode *inode, struct page *page, | 457 | static void move_btree_to_page(struct inode *inode, struct page *page, |
458 | __be64 *data) | 458 | __be64 *data) |
459 | { | 459 | { |
460 | struct super_block *sb = inode->i_sb; | 460 | struct super_block *sb = inode->i_sb; |
461 | struct logfs_super *super = logfs_super(sb); | 461 | struct logfs_super *super = logfs_super(sb); |
462 | struct btree_head128 *head = &super->s_object_alias_tree; | 462 | struct btree_head128 *head = &super->s_object_alias_tree; |
463 | struct logfs_block *block; | 463 | struct logfs_block *block; |
464 | struct object_alias_item *item, *next; | 464 | struct object_alias_item *item, *next; |
465 | 465 | ||
466 | if (!(super->s_flags & LOGFS_SB_FLAG_OBJ_ALIAS)) | 466 | if (!(super->s_flags & LOGFS_SB_FLAG_OBJ_ALIAS)) |
467 | return; | 467 | return; |
468 | 468 | ||
469 | block = btree_remove128(head, inode->i_ino, page->index); | 469 | block = btree_remove128(head, inode->i_ino, page->index); |
470 | if (!block) | 470 | if (!block) |
471 | return; | 471 | return; |
472 | 472 | ||
473 | log_blockmove("move_btree_to_page(%llx, %llx, %x)\n", | 473 | log_blockmove("move_btree_to_page(%llx, %llx, %x)\n", |
474 | block->ino, block->bix, block->level); | 474 | block->ino, block->bix, block->level); |
475 | list_for_each_entry_safe(item, next, &block->item_list, list) { | 475 | list_for_each_entry_safe(item, next, &block->item_list, list) { |
476 | data[item->child_no] = item->val; | 476 | data[item->child_no] = item->val; |
477 | list_del(&item->list); | 477 | list_del(&item->list); |
478 | mempool_free(item, super->s_alias_pool); | 478 | mempool_free(item, super->s_alias_pool); |
479 | } | 479 | } |
480 | block->page = page; | 480 | block->page = page; |
481 | SetPagePrivate(page); | 481 | SetPagePrivate(page); |
482 | page->private = (unsigned long)block; | 482 | page->private = (unsigned long)block; |
483 | block->ops = &indirect_block_ops; | 483 | block->ops = &indirect_block_ops; |
484 | initialize_block_counters(page, block, data, 0); | 484 | initialize_block_counters(page, block, data, 0); |
485 | } | 485 | } |
486 | 486 | ||
487 | /* | 487 | /* |
488 | * This silences a false, yet annoying gcc warning. I hate it when my editor | 488 | * This silences a false, yet annoying gcc warning. I hate it when my editor |
489 | * jumps into bitops.h each time I recompile this file. | 489 | * jumps into bitops.h each time I recompile this file. |
490 | * TODO: Complain to gcc folks about this and upgrade compiler. | 490 | * TODO: Complain to gcc folks about this and upgrade compiler. |
491 | */ | 491 | */ |
492 | static unsigned long fnb(const unsigned long *addr, | 492 | static unsigned long fnb(const unsigned long *addr, |
493 | unsigned long size, unsigned long offset) | 493 | unsigned long size, unsigned long offset) |
494 | { | 494 | { |
495 | return find_next_bit(addr, size, offset); | 495 | return find_next_bit(addr, size, offset); |
496 | } | 496 | } |
497 | 497 | ||
498 | void move_page_to_btree(struct page *page) | 498 | void move_page_to_btree(struct page *page) |
499 | { | 499 | { |
500 | struct logfs_block *block = logfs_block(page); | 500 | struct logfs_block *block = logfs_block(page); |
501 | struct super_block *sb = block->sb; | 501 | struct super_block *sb = block->sb; |
502 | struct logfs_super *super = logfs_super(sb); | 502 | struct logfs_super *super = logfs_super(sb); |
503 | struct object_alias_item *item; | 503 | struct object_alias_item *item; |
504 | unsigned long pos; | 504 | unsigned long pos; |
505 | __be64 *child; | 505 | __be64 *child; |
506 | int err; | 506 | int err; |
507 | 507 | ||
508 | if (super->s_flags & LOGFS_SB_FLAG_SHUTDOWN) { | 508 | if (super->s_flags & LOGFS_SB_FLAG_SHUTDOWN) { |
509 | block->ops->free_block(sb, block); | 509 | block->ops->free_block(sb, block); |
510 | return; | 510 | return; |
511 | } | 511 | } |
512 | log_blockmove("move_page_to_btree(%llx, %llx, %x)\n", | 512 | log_blockmove("move_page_to_btree(%llx, %llx, %x)\n", |
513 | block->ino, block->bix, block->level); | 513 | block->ino, block->bix, block->level); |
514 | super->s_flags |= LOGFS_SB_FLAG_OBJ_ALIAS; | 514 | super->s_flags |= LOGFS_SB_FLAG_OBJ_ALIAS; |
515 | 515 | ||
516 | for (pos = 0; ; pos++) { | 516 | for (pos = 0; ; pos++) { |
517 | pos = fnb(block->alias_map, LOGFS_BLOCK_FACTOR, pos); | 517 | pos = fnb(block->alias_map, LOGFS_BLOCK_FACTOR, pos); |
518 | if (pos >= LOGFS_BLOCK_FACTOR) | 518 | if (pos >= LOGFS_BLOCK_FACTOR) |
519 | break; | 519 | break; |
520 | 520 | ||
521 | item = mempool_alloc(super->s_alias_pool, GFP_NOFS); | 521 | item = mempool_alloc(super->s_alias_pool, GFP_NOFS); |
522 | BUG_ON(!item); /* mempool empty */ | 522 | BUG_ON(!item); /* mempool empty */ |
523 | memset(item, 0, sizeof(*item)); | 523 | memset(item, 0, sizeof(*item)); |
524 | 524 | ||
525 | child = kmap_atomic(page, KM_USER0); | 525 | child = kmap_atomic(page, KM_USER0); |
526 | item->val = child[pos]; | 526 | item->val = child[pos]; |
527 | kunmap_atomic(child, KM_USER0); | 527 | kunmap_atomic(child, KM_USER0); |
528 | item->child_no = pos; | 528 | item->child_no = pos; |
529 | list_add(&item->list, &block->item_list); | 529 | list_add(&item->list, &block->item_list); |
530 | } | 530 | } |
531 | block->page = NULL; | 531 | block->page = NULL; |
532 | ClearPagePrivate(page); | 532 | ClearPagePrivate(page); |
533 | page->private = 0; | 533 | page->private = 0; |
534 | block->ops = &btree_block_ops; | 534 | block->ops = &btree_block_ops; |
535 | err = alias_tree_insert(block->sb, block->ino, block->bix, block->level, | 535 | err = alias_tree_insert(block->sb, block->ino, block->bix, block->level, |
536 | block); | 536 | block); |
537 | BUG_ON(err); /* mempool empty */ | 537 | BUG_ON(err); /* mempool empty */ |
538 | ClearPageUptodate(page); | 538 | ClearPageUptodate(page); |
539 | } | 539 | } |
540 | 540 | ||
541 | static int __logfs_segment_read(struct inode *inode, void *buf, | 541 | static int __logfs_segment_read(struct inode *inode, void *buf, |
542 | u64 ofs, u64 bix, level_t level) | 542 | u64 ofs, u64 bix, level_t level) |
543 | { | 543 | { |
544 | struct super_block *sb = inode->i_sb; | 544 | struct super_block *sb = inode->i_sb; |
545 | void *compressor_buf = logfs_super(sb)->s_compressed_je; | 545 | void *compressor_buf = logfs_super(sb)->s_compressed_je; |
546 | struct logfs_object_header oh; | 546 | struct logfs_object_header oh; |
547 | __be32 crc; | 547 | __be32 crc; |
548 | u16 len; | 548 | u16 len; |
549 | int err, block_len; | 549 | int err, block_len; |
550 | 550 | ||
551 | block_len = obj_len(sb, obj_type(inode, level)); | 551 | block_len = obj_len(sb, obj_type(inode, level)); |
552 | err = read_obj_header(sb, ofs, &oh); | 552 | err = read_obj_header(sb, ofs, &oh); |
553 | if (err) | 553 | if (err) |
554 | goto out_err; | 554 | goto out_err; |
555 | 555 | ||
556 | err = -EIO; | 556 | err = -EIO; |
557 | if (be64_to_cpu(oh.ino) != inode->i_ino | 557 | if (be64_to_cpu(oh.ino) != inode->i_ino |
558 | || check_pos(sb, be64_to_cpu(oh.bix), bix, level)) { | 558 | || check_pos(sb, be64_to_cpu(oh.bix), bix, level)) { |
559 | printk(KERN_ERR"LOGFS: (ino, bix) don't match at %llx: " | 559 | printk(KERN_ERR"LOGFS: (ino, bix) don't match at %llx: " |
560 | "expected (%lx, %llx), got (%llx, %llx)\n", | 560 | "expected (%lx, %llx), got (%llx, %llx)\n", |
561 | ofs, inode->i_ino, bix, | 561 | ofs, inode->i_ino, bix, |
562 | be64_to_cpu(oh.ino), be64_to_cpu(oh.bix)); | 562 | be64_to_cpu(oh.ino), be64_to_cpu(oh.bix)); |
563 | goto out_err; | 563 | goto out_err; |
564 | } | 564 | } |
565 | 565 | ||
566 | len = be16_to_cpu(oh.len); | 566 | len = be16_to_cpu(oh.len); |
567 | 567 | ||
568 | switch (oh.compr) { | 568 | switch (oh.compr) { |
569 | case COMPR_NONE: | 569 | case COMPR_NONE: |
570 | err = wbuf_read(sb, ofs + LOGFS_OBJECT_HEADERSIZE, len, buf); | 570 | err = wbuf_read(sb, ofs + LOGFS_OBJECT_HEADERSIZE, len, buf); |
571 | if (err) | 571 | if (err) |
572 | goto out_err; | 572 | goto out_err; |
573 | crc = logfs_crc32(buf, len, 0); | 573 | crc = logfs_crc32(buf, len, 0); |
574 | if (crc != oh.data_crc) { | 574 | if (crc != oh.data_crc) { |
575 | printk(KERN_ERR"LOGFS: uncompressed data crc error at " | 575 | printk(KERN_ERR"LOGFS: uncompressed data crc error at " |
576 | "%llx: expected %x, got %x\n", ofs, | 576 | "%llx: expected %x, got %x\n", ofs, |
577 | be32_to_cpu(oh.data_crc), | 577 | be32_to_cpu(oh.data_crc), |
578 | be32_to_cpu(crc)); | 578 | be32_to_cpu(crc)); |
579 | goto out_err; | 579 | goto out_err; |
580 | } | 580 | } |
581 | break; | 581 | break; |
582 | case COMPR_ZLIB: | 582 | case COMPR_ZLIB: |
583 | mutex_lock(&logfs_super(sb)->s_journal_mutex); | 583 | mutex_lock(&logfs_super(sb)->s_journal_mutex); |
584 | err = wbuf_read(sb, ofs + LOGFS_OBJECT_HEADERSIZE, len, | 584 | err = wbuf_read(sb, ofs + LOGFS_OBJECT_HEADERSIZE, len, |
585 | compressor_buf); | 585 | compressor_buf); |
586 | if (err) { | 586 | if (err) { |
587 | mutex_unlock(&logfs_super(sb)->s_journal_mutex); | 587 | mutex_unlock(&logfs_super(sb)->s_journal_mutex); |
588 | goto out_err; | 588 | goto out_err; |
589 | } | 589 | } |
590 | crc = logfs_crc32(compressor_buf, len, 0); | 590 | crc = logfs_crc32(compressor_buf, len, 0); |
591 | if (crc != oh.data_crc) { | 591 | if (crc != oh.data_crc) { |
592 | printk(KERN_ERR"LOGFS: compressed data crc error at " | 592 | printk(KERN_ERR"LOGFS: compressed data crc error at " |
593 | "%llx: expected %x, got %x\n", ofs, | 593 | "%llx: expected %x, got %x\n", ofs, |
594 | be32_to_cpu(oh.data_crc), | 594 | be32_to_cpu(oh.data_crc), |
595 | be32_to_cpu(crc)); | 595 | be32_to_cpu(crc)); |
596 | mutex_unlock(&logfs_super(sb)->s_journal_mutex); | 596 | mutex_unlock(&logfs_super(sb)->s_journal_mutex); |
597 | goto out_err; | 597 | goto out_err; |
598 | } | 598 | } |
599 | err = logfs_uncompress(compressor_buf, buf, len, block_len); | 599 | err = logfs_uncompress(compressor_buf, buf, len, block_len); |
600 | mutex_unlock(&logfs_super(sb)->s_journal_mutex); | 600 | mutex_unlock(&logfs_super(sb)->s_journal_mutex); |
601 | if (err) { | 601 | if (err) { |
602 | printk(KERN_ERR"LOGFS: uncompress error at %llx\n", ofs); | 602 | printk(KERN_ERR"LOGFS: uncompress error at %llx\n", ofs); |
603 | goto out_err; | 603 | goto out_err; |
604 | } | 604 | } |
605 | break; | 605 | break; |
606 | default: | 606 | default: |
607 | LOGFS_BUG(sb); | 607 | LOGFS_BUG(sb); |
608 | err = -EIO; | 608 | err = -EIO; |
609 | goto out_err; | 609 | goto out_err; |
610 | } | 610 | } |
611 | return 0; | 611 | return 0; |
612 | 612 | ||
613 | out_err: | 613 | out_err: |
614 | logfs_set_ro(sb); | 614 | logfs_set_ro(sb); |
615 | printk(KERN_ERR"LOGFS: device is read-only now\n"); | 615 | printk(KERN_ERR"LOGFS: device is read-only now\n"); |
616 | LOGFS_BUG(sb); | 616 | LOGFS_BUG(sb); |
617 | return err; | 617 | return err; |
618 | } | 618 | } |
619 | 619 | ||
620 | /** | 620 | /** |
621 | * logfs_segment_read - read data block from object store | 621 | * logfs_segment_read - read data block from object store |
622 | * @inode: inode containing data | 622 | * @inode: inode containing data |
623 | * @buf: data buffer | 623 | * @buf: data buffer |
624 | * @ofs: physical data offset | 624 | * @ofs: physical data offset |
625 | * @bix: block index | 625 | * @bix: block index |
626 | * @level: block level | 626 | * @level: block level |
627 | * | 627 | * |
628 | * Returns 0 on success or a negative errno. | 628 | * Returns 0 on success or a negative errno. |
629 | */ | 629 | */ |
630 | int logfs_segment_read(struct inode *inode, struct page *page, | 630 | int logfs_segment_read(struct inode *inode, struct page *page, |
631 | u64 ofs, u64 bix, level_t level) | 631 | u64 ofs, u64 bix, level_t level) |
632 | { | 632 | { |
633 | int err; | 633 | int err; |
634 | void *buf; | 634 | void *buf; |
635 | 635 | ||
636 | if (PageUptodate(page)) | 636 | if (PageUptodate(page)) |
637 | return 0; | 637 | return 0; |
638 | 638 | ||
639 | ofs &= ~LOGFS_FULLY_POPULATED; | 639 | ofs &= ~LOGFS_FULLY_POPULATED; |
640 | 640 | ||
641 | buf = kmap(page); | 641 | buf = kmap(page); |
642 | err = __logfs_segment_read(inode, buf, ofs, bix, level); | 642 | err = __logfs_segment_read(inode, buf, ofs, bix, level); |
643 | if (!err) { | 643 | if (!err) { |
644 | move_btree_to_page(inode, page, buf); | 644 | move_btree_to_page(inode, page, buf); |
645 | SetPageUptodate(page); | 645 | SetPageUptodate(page); |
646 | } | 646 | } |
647 | kunmap(page); | 647 | kunmap(page); |
648 | log_segment("logfs_segment_read(%lx, %llx, %x) %llx (%d)\n", | 648 | log_segment("logfs_segment_read(%lx, %llx, %x) %llx (%d)\n", |
649 | inode->i_ino, bix, level, ofs, err); | 649 | inode->i_ino, bix, level, ofs, err); |
650 | return err; | 650 | return err; |
651 | } | 651 | } |
652 | 652 | ||
653 | int logfs_segment_delete(struct inode *inode, struct logfs_shadow *shadow) | 653 | int logfs_segment_delete(struct inode *inode, struct logfs_shadow *shadow) |
654 | { | 654 | { |
655 | struct super_block *sb = inode->i_sb; | 655 | struct super_block *sb = inode->i_sb; |
656 | struct logfs_object_header h; | 656 | struct logfs_object_header h; |
657 | u16 len; | 657 | u16 len; |
658 | int err; | 658 | int err; |
659 | 659 | ||
660 | BUG_ON(logfs_super(sb)->s_flags & LOGFS_SB_FLAG_SHUTDOWN); | 660 | BUG_ON(logfs_super(sb)->s_flags & LOGFS_SB_FLAG_SHUTDOWN); |
661 | BUG_ON(shadow->old_ofs & LOGFS_FULLY_POPULATED); | 661 | BUG_ON(shadow->old_ofs & LOGFS_FULLY_POPULATED); |
662 | if (!shadow->old_ofs) | 662 | if (!shadow->old_ofs) |
663 | return 0; | 663 | return 0; |
664 | 664 | ||
665 | log_segment("logfs_segment_delete(%llx, %llx, %x) %llx->%llx %x->%x\n", | 665 | log_segment("logfs_segment_delete(%llx, %llx, %x) %llx->%llx %x->%x\n", |
666 | shadow->ino, shadow->bix, shadow->gc_level, | 666 | shadow->ino, shadow->bix, shadow->gc_level, |
667 | shadow->old_ofs, shadow->new_ofs, | 667 | shadow->old_ofs, shadow->new_ofs, |
668 | shadow->old_len, shadow->new_len); | 668 | shadow->old_len, shadow->new_len); |
669 | err = read_obj_header(sb, shadow->old_ofs, &h); | 669 | err = read_obj_header(sb, shadow->old_ofs, &h); |
670 | LOGFS_BUG_ON(err, sb); | 670 | LOGFS_BUG_ON(err, sb); |
671 | LOGFS_BUG_ON(be64_to_cpu(h.ino) != inode->i_ino, sb); | 671 | LOGFS_BUG_ON(be64_to_cpu(h.ino) != inode->i_ino, sb); |
672 | LOGFS_BUG_ON(check_pos(sb, shadow->bix, be64_to_cpu(h.bix), | 672 | LOGFS_BUG_ON(check_pos(sb, shadow->bix, be64_to_cpu(h.bix), |
673 | shrink_level(shadow->gc_level)), sb); | 673 | shrink_level(shadow->gc_level)), sb); |
674 | 674 | ||
675 | if (shadow->gc_level == 0) | 675 | if (shadow->gc_level == 0) |
676 | len = be16_to_cpu(h.len); | 676 | len = be16_to_cpu(h.len); |
677 | else | 677 | else |
678 | len = obj_len(sb, h.type); | 678 | len = obj_len(sb, h.type); |
679 | shadow->old_len = len + sizeof(h); | 679 | shadow->old_len = len + sizeof(h); |
680 | return 0; | 680 | return 0; |
681 | } | 681 | } |
682 | 682 | ||
683 | static void freeseg(struct super_block *sb, u32 segno) | 683 | static void freeseg(struct super_block *sb, u32 segno) |
684 | { | 684 | { |
685 | struct logfs_super *super = logfs_super(sb); | 685 | struct logfs_super *super = logfs_super(sb); |
686 | struct address_space *mapping = super->s_mapping_inode->i_mapping; | 686 | struct address_space *mapping = super->s_mapping_inode->i_mapping; |
687 | struct page *page; | 687 | struct page *page; |
688 | u64 ofs, start, end; | 688 | u64 ofs, start, end; |
689 | 689 | ||
690 | start = dev_ofs(sb, segno, 0); | 690 | start = dev_ofs(sb, segno, 0); |
691 | end = dev_ofs(sb, segno + 1, 0); | 691 | end = dev_ofs(sb, segno + 1, 0); |
692 | for (ofs = start; ofs < end; ofs += PAGE_SIZE) { | 692 | for (ofs = start; ofs < end; ofs += PAGE_SIZE) { |
693 | page = find_get_page(mapping, ofs >> PAGE_SHIFT); | 693 | page = find_get_page(mapping, ofs >> PAGE_SHIFT); |
694 | if (!page) | 694 | if (!page) |
695 | continue; | 695 | continue; |
696 | ClearPagePrivate(page); | 696 | ClearPagePrivate(page); |
697 | page_cache_release(page); | 697 | page_cache_release(page); |
698 | } | 698 | } |
699 | } | 699 | } |
700 | 700 | ||
701 | int logfs_open_area(struct logfs_area *area, size_t bytes) | 701 | int logfs_open_area(struct logfs_area *area, size_t bytes) |
702 | { | 702 | { |
703 | struct super_block *sb = area->a_sb; | 703 | struct super_block *sb = area->a_sb; |
704 | struct logfs_super *super = logfs_super(sb); | 704 | struct logfs_super *super = logfs_super(sb); |
705 | int err, closed = 0; | 705 | int err, closed = 0; |
706 | 706 | ||
707 | if (area->a_is_open && area->a_used_bytes + bytes <= super->s_segsize) | 707 | if (area->a_is_open && area->a_used_bytes + bytes <= super->s_segsize) |
708 | return 0; | 708 | return 0; |
709 | 709 | ||
710 | if (area->a_is_open) { | 710 | if (area->a_is_open) { |
711 | u64 ofs = dev_ofs(sb, area->a_segno, area->a_written_bytes); | 711 | u64 ofs = dev_ofs(sb, area->a_segno, area->a_written_bytes); |
712 | u32 len = super->s_segsize - area->a_written_bytes; | 712 | u32 len = super->s_segsize - area->a_written_bytes; |
713 | 713 | ||
714 | log_gc("logfs_close_area(%x)\n", area->a_segno); | 714 | log_gc("logfs_close_area(%x)\n", area->a_segno); |
715 | pad_wbuf(area, 1); | 715 | pad_wbuf(area, 1); |
716 | super->s_devops->writeseg(area->a_sb, ofs, len); | 716 | super->s_devops->writeseg(area->a_sb, ofs, len); |
717 | freeseg(sb, area->a_segno); | 717 | freeseg(sb, area->a_segno); |
718 | closed = 1; | 718 | closed = 1; |
719 | } | 719 | } |
720 | 720 | ||
721 | area->a_used_bytes = 0; | 721 | area->a_used_bytes = 0; |
722 | area->a_written_bytes = 0; | 722 | area->a_written_bytes = 0; |
723 | again: | 723 | again: |
724 | area->a_ops->get_free_segment(area); | 724 | area->a_ops->get_free_segment(area); |
725 | area->a_ops->get_erase_count(area); | 725 | area->a_ops->get_erase_count(area); |
726 | 726 | ||
727 | log_gc("logfs_open_area(%x, %x)\n", area->a_segno, area->a_level); | 727 | log_gc("logfs_open_area(%x, %x)\n", area->a_segno, area->a_level); |
728 | err = area->a_ops->erase_segment(area); | 728 | err = area->a_ops->erase_segment(area); |
729 | if (err) { | 729 | if (err) { |
730 | printk(KERN_WARNING "LogFS: Error erasing segment %x\n", | 730 | printk(KERN_WARNING "LogFS: Error erasing segment %x\n", |
731 | area->a_segno); | 731 | area->a_segno); |
732 | logfs_mark_segment_bad(sb, area->a_segno); | 732 | logfs_mark_segment_bad(sb, area->a_segno); |
733 | goto again; | 733 | goto again; |
734 | } | 734 | } |
735 | area->a_is_open = 1; | 735 | area->a_is_open = 1; |
736 | return closed; | 736 | return closed; |
737 | } | 737 | } |
738 | 738 | ||
739 | void logfs_sync_area(struct logfs_area *area) | 739 | void logfs_sync_area(struct logfs_area *area) |
740 | { | 740 | { |
741 | struct super_block *sb = area->a_sb; | 741 | struct super_block *sb = area->a_sb; |
742 | struct logfs_super *super = logfs_super(sb); | 742 | struct logfs_super *super = logfs_super(sb); |
743 | u64 ofs = dev_ofs(sb, area->a_segno, area->a_written_bytes); | 743 | u64 ofs = dev_ofs(sb, area->a_segno, area->a_written_bytes); |
744 | u32 len = (area->a_used_bytes - area->a_written_bytes); | 744 | u32 len = (area->a_used_bytes - area->a_written_bytes); |
745 | 745 | ||
746 | if (super->s_writesize) | 746 | if (super->s_writesize) |
747 | len &= ~(super->s_writesize - 1); | 747 | len &= ~(super->s_writesize - 1); |
748 | if (len == 0) | 748 | if (len == 0) |
749 | return; | 749 | return; |
750 | pad_wbuf(area, 0); | 750 | pad_wbuf(area, 0); |
751 | super->s_devops->writeseg(sb, ofs, len); | 751 | super->s_devops->writeseg(sb, ofs, len); |
752 | area->a_written_bytes += len; | 752 | area->a_written_bytes += len; |
753 | } | 753 | } |
754 | 754 | ||
755 | void logfs_sync_segments(struct super_block *sb) | 755 | void logfs_sync_segments(struct super_block *sb) |
756 | { | 756 | { |
757 | struct logfs_super *super = logfs_super(sb); | 757 | struct logfs_super *super = logfs_super(sb); |
758 | int i; | 758 | int i; |
759 | 759 | ||
760 | for_each_area(i) | 760 | for_each_area(i) |
761 | logfs_sync_area(super->s_area[i]); | 761 | logfs_sync_area(super->s_area[i]); |
762 | } | 762 | } |
763 | 763 | ||
764 | /* | 764 | /* |
765 | * Pick a free segment to be used for this area. Effectively takes a | 765 | * Pick a free segment to be used for this area. Effectively takes a |
766 | * candidate from the free list (not really a candidate anymore). | 766 | * candidate from the free list (not really a candidate anymore). |
767 | */ | 767 | */ |
768 | static void ostore_get_free_segment(struct logfs_area *area) | 768 | static void ostore_get_free_segment(struct logfs_area *area) |
769 | { | 769 | { |
770 | struct super_block *sb = area->a_sb; | 770 | struct super_block *sb = area->a_sb; |
771 | struct logfs_super *super = logfs_super(sb); | 771 | struct logfs_super *super = logfs_super(sb); |
772 | 772 | ||
773 | if (super->s_free_list.count == 0) { | 773 | if (super->s_free_list.count == 0) { |
774 | printk(KERN_ERR"LOGFS: ran out of free segments\n"); | 774 | printk(KERN_ERR"LOGFS: ran out of free segments\n"); |
775 | LOGFS_BUG(sb); | 775 | LOGFS_BUG(sb); |
776 | } | 776 | } |
777 | 777 | ||
778 | area->a_segno = get_best_cand(sb, &super->s_free_list, NULL); | 778 | area->a_segno = get_best_cand(sb, &super->s_free_list, NULL); |
779 | } | 779 | } |
780 | 780 | ||
781 | static void ostore_get_erase_count(struct logfs_area *area) | 781 | static void ostore_get_erase_count(struct logfs_area *area) |
782 | { | 782 | { |
783 | struct logfs_segment_entry se; | 783 | struct logfs_segment_entry se; |
784 | u32 ec_level; | 784 | u32 ec_level; |
785 | 785 | ||
786 | logfs_get_segment_entry(area->a_sb, area->a_segno, &se); | 786 | logfs_get_segment_entry(area->a_sb, area->a_segno, &se); |
787 | BUG_ON(se.ec_level == cpu_to_be32(BADSEG) || | 787 | BUG_ON(se.ec_level == cpu_to_be32(BADSEG) || |
788 | se.valid == cpu_to_be32(RESERVED)); | 788 | se.valid == cpu_to_be32(RESERVED)); |
789 | 789 | ||
790 | ec_level = be32_to_cpu(se.ec_level); | 790 | ec_level = be32_to_cpu(se.ec_level); |
791 | area->a_erase_count = (ec_level >> 4) + 1; | 791 | area->a_erase_count = (ec_level >> 4) + 1; |
792 | } | 792 | } |
793 | 793 | ||
794 | static int ostore_erase_segment(struct logfs_area *area) | 794 | static int ostore_erase_segment(struct logfs_area *area) |
795 | { | 795 | { |
796 | struct super_block *sb = area->a_sb; | 796 | struct super_block *sb = area->a_sb; |
797 | struct logfs_segment_header sh; | 797 | struct logfs_segment_header sh; |
798 | u64 ofs; | 798 | u64 ofs; |
799 | int err; | 799 | int err; |
800 | 800 | ||
801 | err = logfs_erase_segment(sb, area->a_segno); | 801 | err = logfs_erase_segment(sb, area->a_segno, 0); |
802 | if (err) | 802 | if (err) |
803 | return err; | 803 | return err; |
804 | 804 | ||
805 | sh.pad = 0; | 805 | sh.pad = 0; |
806 | sh.type = SEG_OSTORE; | 806 | sh.type = SEG_OSTORE; |
807 | sh.level = (__force u8)area->a_level; | 807 | sh.level = (__force u8)area->a_level; |
808 | sh.segno = cpu_to_be32(area->a_segno); | 808 | sh.segno = cpu_to_be32(area->a_segno); |
809 | sh.ec = cpu_to_be32(area->a_erase_count); | 809 | sh.ec = cpu_to_be32(area->a_erase_count); |
810 | sh.gec = cpu_to_be64(logfs_super(sb)->s_gec); | 810 | sh.gec = cpu_to_be64(logfs_super(sb)->s_gec); |
811 | sh.crc = logfs_crc32(&sh, sizeof(sh), 4); | 811 | sh.crc = logfs_crc32(&sh, sizeof(sh), 4); |
812 | 812 | ||
813 | logfs_set_segment_erased(sb, area->a_segno, area->a_erase_count, | 813 | logfs_set_segment_erased(sb, area->a_segno, area->a_erase_count, |
814 | area->a_level); | 814 | area->a_level); |
815 | 815 | ||
816 | ofs = dev_ofs(sb, area->a_segno, 0); | 816 | ofs = dev_ofs(sb, area->a_segno, 0); |
817 | area->a_used_bytes = sizeof(sh); | 817 | area->a_used_bytes = sizeof(sh); |
818 | logfs_buf_write(area, ofs, &sh, sizeof(sh)); | 818 | logfs_buf_write(area, ofs, &sh, sizeof(sh)); |
819 | return 0; | 819 | return 0; |
820 | } | 820 | } |
821 | 821 | ||
822 | static const struct logfs_area_ops ostore_area_ops = { | 822 | static const struct logfs_area_ops ostore_area_ops = { |
823 | .get_free_segment = ostore_get_free_segment, | 823 | .get_free_segment = ostore_get_free_segment, |
824 | .get_erase_count = ostore_get_erase_count, | 824 | .get_erase_count = ostore_get_erase_count, |
825 | .erase_segment = ostore_erase_segment, | 825 | .erase_segment = ostore_erase_segment, |
826 | }; | 826 | }; |
827 | 827 | ||
828 | static void free_area(struct logfs_area *area) | 828 | static void free_area(struct logfs_area *area) |
829 | { | 829 | { |
830 | if (area) | 830 | if (area) |
831 | freeseg(area->a_sb, area->a_segno); | 831 | freeseg(area->a_sb, area->a_segno); |
832 | kfree(area); | 832 | kfree(area); |
833 | } | 833 | } |
834 | 834 | ||
835 | static struct logfs_area *alloc_area(struct super_block *sb) | 835 | static struct logfs_area *alloc_area(struct super_block *sb) |
836 | { | 836 | { |
837 | struct logfs_area *area; | 837 | struct logfs_area *area; |
838 | 838 | ||
839 | area = kzalloc(sizeof(*area), GFP_KERNEL); | 839 | area = kzalloc(sizeof(*area), GFP_KERNEL); |
840 | if (!area) | 840 | if (!area) |
841 | return NULL; | 841 | return NULL; |
842 | 842 | ||
843 | area->a_sb = sb; | 843 | area->a_sb = sb; |
844 | return area; | 844 | return area; |
845 | } | 845 | } |
846 | 846 | ||
847 | static void map_invalidatepage(struct page *page, unsigned long l) | 847 | static void map_invalidatepage(struct page *page, unsigned long l) |
848 | { | 848 | { |
849 | BUG(); | 849 | BUG(); |
850 | } | 850 | } |
851 | 851 | ||
852 | static int map_releasepage(struct page *page, gfp_t g) | 852 | static int map_releasepage(struct page *page, gfp_t g) |
853 | { | 853 | { |
854 | /* Don't release these pages */ | 854 | /* Don't release these pages */ |
855 | return 0; | 855 | return 0; |
856 | } | 856 | } |
857 | 857 | ||
858 | static const struct address_space_operations mapping_aops = { | 858 | static const struct address_space_operations mapping_aops = { |
859 | .invalidatepage = map_invalidatepage, | 859 | .invalidatepage = map_invalidatepage, |
860 | .releasepage = map_releasepage, | 860 | .releasepage = map_releasepage, |
861 | .set_page_dirty = __set_page_dirty_nobuffers, | 861 | .set_page_dirty = __set_page_dirty_nobuffers, |
862 | }; | 862 | }; |
863 | 863 | ||
864 | int logfs_init_mapping(struct super_block *sb) | 864 | int logfs_init_mapping(struct super_block *sb) |
865 | { | 865 | { |
866 | struct logfs_super *super = logfs_super(sb); | 866 | struct logfs_super *super = logfs_super(sb); |
867 | struct address_space *mapping; | 867 | struct address_space *mapping; |
868 | struct inode *inode; | 868 | struct inode *inode; |
869 | 869 | ||
870 | inode = logfs_new_meta_inode(sb, LOGFS_INO_MAPPING); | 870 | inode = logfs_new_meta_inode(sb, LOGFS_INO_MAPPING); |
871 | if (IS_ERR(inode)) | 871 | if (IS_ERR(inode)) |
872 | return PTR_ERR(inode); | 872 | return PTR_ERR(inode); |
873 | super->s_mapping_inode = inode; | 873 | super->s_mapping_inode = inode; |
874 | mapping = inode->i_mapping; | 874 | mapping = inode->i_mapping; |
875 | mapping->a_ops = &mapping_aops; | 875 | mapping->a_ops = &mapping_aops; |
876 | /* Would it be possible to use __GFP_HIGHMEM as well? */ | 876 | /* Would it be possible to use __GFP_HIGHMEM as well? */ |
877 | mapping_set_gfp_mask(mapping, GFP_NOFS); | 877 | mapping_set_gfp_mask(mapping, GFP_NOFS); |
878 | return 0; | 878 | return 0; |
879 | } | 879 | } |
880 | 880 | ||
881 | int logfs_init_areas(struct super_block *sb) | 881 | int logfs_init_areas(struct super_block *sb) |
882 | { | 882 | { |
883 | struct logfs_super *super = logfs_super(sb); | 883 | struct logfs_super *super = logfs_super(sb); |
884 | int i = -1; | 884 | int i = -1; |
885 | 885 | ||
886 | super->s_alias_pool = mempool_create_kmalloc_pool(600, | 886 | super->s_alias_pool = mempool_create_kmalloc_pool(600, |
887 | sizeof(struct object_alias_item)); | 887 | sizeof(struct object_alias_item)); |
888 | if (!super->s_alias_pool) | 888 | if (!super->s_alias_pool) |
889 | return -ENOMEM; | 889 | return -ENOMEM; |
890 | 890 | ||
891 | super->s_journal_area = alloc_area(sb); | 891 | super->s_journal_area = alloc_area(sb); |
892 | if (!super->s_journal_area) | 892 | if (!super->s_journal_area) |
893 | goto err; | 893 | goto err; |
894 | 894 | ||
895 | for_each_area(i) { | 895 | for_each_area(i) { |
896 | super->s_area[i] = alloc_area(sb); | 896 | super->s_area[i] = alloc_area(sb); |
897 | if (!super->s_area[i]) | 897 | if (!super->s_area[i]) |
898 | goto err; | 898 | goto err; |
899 | super->s_area[i]->a_level = GC_LEVEL(i); | 899 | super->s_area[i]->a_level = GC_LEVEL(i); |
900 | super->s_area[i]->a_ops = &ostore_area_ops; | 900 | super->s_area[i]->a_ops = &ostore_area_ops; |
901 | } | 901 | } |
902 | btree_init_mempool128(&super->s_object_alias_tree, | 902 | btree_init_mempool128(&super->s_object_alias_tree, |
903 | super->s_btree_pool); | 903 | super->s_btree_pool); |
904 | return 0; | 904 | return 0; |
905 | 905 | ||
906 | err: | 906 | err: |
907 | for (i--; i >= 0; i--) | 907 | for (i--; i >= 0; i--) |
908 | free_area(super->s_area[i]); | 908 | free_area(super->s_area[i]); |
909 | free_area(super->s_journal_area); | 909 | free_area(super->s_journal_area); |
910 | mempool_destroy(super->s_alias_pool); | 910 | mempool_destroy(super->s_alias_pool); |
911 | return -ENOMEM; | 911 | return -ENOMEM; |
912 | } | 912 | } |
913 | 913 | ||
914 | void logfs_cleanup_areas(struct super_block *sb) | 914 | void logfs_cleanup_areas(struct super_block *sb) |
915 | { | 915 | { |
916 | struct logfs_super *super = logfs_super(sb); | 916 | struct logfs_super *super = logfs_super(sb); |
917 | int i; | 917 | int i; |
918 | 918 | ||
919 | btree_grim_visitor128(&super->s_object_alias_tree, 0, kill_alias); | 919 | btree_grim_visitor128(&super->s_object_alias_tree, 0, kill_alias); |
920 | for_each_area(i) | 920 | for_each_area(i) |
921 | free_area(super->s_area[i]); | 921 | free_area(super->s_area[i]); |
922 | free_area(super->s_journal_area); | 922 | free_area(super->s_journal_area); |
923 | destroy_meta_inode(super->s_mapping_inode); | 923 | destroy_meta_inode(super->s_mapping_inode); |
924 | } | 924 | } |
925 | 925 |
fs/logfs/super.c
1 | /* | 1 | /* |
2 | * fs/logfs/super.c | 2 | * fs/logfs/super.c |
3 | * | 3 | * |
4 | * As should be obvious for Linux kernel code, license is GPLv2 | 4 | * As should be obvious for Linux kernel code, license is GPLv2 |
5 | * | 5 | * |
6 | * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org> | 6 | * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org> |
7 | * | 7 | * |
8 | * Generally contains mount/umount code and also serves as a dump area for | 8 | * Generally contains mount/umount code and also serves as a dump area for |
9 | * any functions that don't fit elsewhere and neither justify a file of their | 9 | * any functions that don't fit elsewhere and neither justify a file of their |
10 | * own. | 10 | * own. |
11 | */ | 11 | */ |
12 | #include "logfs.h" | 12 | #include "logfs.h" |
13 | #include <linux/bio.h> | 13 | #include <linux/bio.h> |
14 | #include <linux/mtd/mtd.h> | 14 | #include <linux/mtd/mtd.h> |
15 | #include <linux/statfs.h> | 15 | #include <linux/statfs.h> |
16 | #include <linux/buffer_head.h> | 16 | #include <linux/buffer_head.h> |
17 | 17 | ||
18 | static DEFINE_MUTEX(emergency_mutex); | 18 | static DEFINE_MUTEX(emergency_mutex); |
19 | static struct page *emergency_page; | 19 | static struct page *emergency_page; |
20 | 20 | ||
21 | struct page *emergency_read_begin(struct address_space *mapping, pgoff_t index) | 21 | struct page *emergency_read_begin(struct address_space *mapping, pgoff_t index) |
22 | { | 22 | { |
23 | filler_t *filler = (filler_t *)mapping->a_ops->readpage; | 23 | filler_t *filler = (filler_t *)mapping->a_ops->readpage; |
24 | struct page *page; | 24 | struct page *page; |
25 | int err; | 25 | int err; |
26 | 26 | ||
27 | page = read_cache_page(mapping, index, filler, NULL); | 27 | page = read_cache_page(mapping, index, filler, NULL); |
28 | if (page) | 28 | if (page) |
29 | return page; | 29 | return page; |
30 | 30 | ||
31 | /* No more pages available, switch to emergency page */ | 31 | /* No more pages available, switch to emergency page */ |
32 | printk(KERN_INFO"Logfs: Using emergency page\n"); | 32 | printk(KERN_INFO"Logfs: Using emergency page\n"); |
33 | mutex_lock(&emergency_mutex); | 33 | mutex_lock(&emergency_mutex); |
34 | err = filler(NULL, emergency_page); | 34 | err = filler(NULL, emergency_page); |
35 | if (err) { | 35 | if (err) { |
36 | mutex_unlock(&emergency_mutex); | 36 | mutex_unlock(&emergency_mutex); |
37 | printk(KERN_EMERG"Logfs: Error reading emergency page\n"); | 37 | printk(KERN_EMERG"Logfs: Error reading emergency page\n"); |
38 | return ERR_PTR(err); | 38 | return ERR_PTR(err); |
39 | } | 39 | } |
40 | return emergency_page; | 40 | return emergency_page; |
41 | } | 41 | } |
42 | 42 | ||
43 | void emergency_read_end(struct page *page) | 43 | void emergency_read_end(struct page *page) |
44 | { | 44 | { |
45 | if (page == emergency_page) | 45 | if (page == emergency_page) |
46 | mutex_unlock(&emergency_mutex); | 46 | mutex_unlock(&emergency_mutex); |
47 | else | 47 | else |
48 | page_cache_release(page); | 48 | page_cache_release(page); |
49 | } | 49 | } |
50 | 50 | ||
51 | static void dump_segfile(struct super_block *sb) | 51 | static void dump_segfile(struct super_block *sb) |
52 | { | 52 | { |
53 | struct logfs_super *super = logfs_super(sb); | 53 | struct logfs_super *super = logfs_super(sb); |
54 | struct logfs_segment_entry se; | 54 | struct logfs_segment_entry se; |
55 | u32 segno; | 55 | u32 segno; |
56 | 56 | ||
57 | for (segno = 0; segno < super->s_no_segs; segno++) { | 57 | for (segno = 0; segno < super->s_no_segs; segno++) { |
58 | logfs_get_segment_entry(sb, segno, &se); | 58 | logfs_get_segment_entry(sb, segno, &se); |
59 | printk("%3x: %6x %8x", segno, be32_to_cpu(se.ec_level), | 59 | printk("%3x: %6x %8x", segno, be32_to_cpu(se.ec_level), |
60 | be32_to_cpu(se.valid)); | 60 | be32_to_cpu(se.valid)); |
61 | if (++segno < super->s_no_segs) { | 61 | if (++segno < super->s_no_segs) { |
62 | logfs_get_segment_entry(sb, segno, &se); | 62 | logfs_get_segment_entry(sb, segno, &se); |
63 | printk(" %6x %8x", be32_to_cpu(se.ec_level), | 63 | printk(" %6x %8x", be32_to_cpu(se.ec_level), |
64 | be32_to_cpu(se.valid)); | 64 | be32_to_cpu(se.valid)); |
65 | } | 65 | } |
66 | if (++segno < super->s_no_segs) { | 66 | if (++segno < super->s_no_segs) { |
67 | logfs_get_segment_entry(sb, segno, &se); | 67 | logfs_get_segment_entry(sb, segno, &se); |
68 | printk(" %6x %8x", be32_to_cpu(se.ec_level), | 68 | printk(" %6x %8x", be32_to_cpu(se.ec_level), |
69 | be32_to_cpu(se.valid)); | 69 | be32_to_cpu(se.valid)); |
70 | } | 70 | } |
71 | if (++segno < super->s_no_segs) { | 71 | if (++segno < super->s_no_segs) { |
72 | logfs_get_segment_entry(sb, segno, &se); | 72 | logfs_get_segment_entry(sb, segno, &se); |
73 | printk(" %6x %8x", be32_to_cpu(se.ec_level), | 73 | printk(" %6x %8x", be32_to_cpu(se.ec_level), |
74 | be32_to_cpu(se.valid)); | 74 | be32_to_cpu(se.valid)); |
75 | } | 75 | } |
76 | printk("\n"); | 76 | printk("\n"); |
77 | } | 77 | } |
78 | } | 78 | } |
79 | 79 | ||
80 | /* | 80 | /* |
81 | * logfs_crash_dump - dump debug information to device | 81 | * logfs_crash_dump - dump debug information to device |
82 | * | 82 | * |
83 | * The LogFS superblock only occupies part of a segment. This function will | 83 | * The LogFS superblock only occupies part of a segment. This function will |
84 | * write as much debug information as it can gather into the spare space. | 84 | * write as much debug information as it can gather into the spare space. |
85 | */ | 85 | */ |
86 | void logfs_crash_dump(struct super_block *sb) | 86 | void logfs_crash_dump(struct super_block *sb) |
87 | { | 87 | { |
88 | dump_segfile(sb); | 88 | dump_segfile(sb); |
89 | } | 89 | } |
90 | 90 | ||
91 | /* | 91 | /* |
92 | * TODO: move to lib/string.c | 92 | * TODO: move to lib/string.c |
93 | */ | 93 | */ |
94 | /** | 94 | /** |
95 | * memchr_inv - Find a character in an area of memory. | 95 | * memchr_inv - Find a character in an area of memory. |
96 | * @s: The memory area | 96 | * @s: The memory area |
97 | * @c: The byte to search for | 97 | * @c: The byte to search for |
98 | * @n: The size of the area. | 98 | * @n: The size of the area. |
99 | * | 99 | * |
100 | * returns the address of the first character other than @c, or %NULL | 100 | * returns the address of the first character other than @c, or %NULL |
101 | * if the whole buffer contains just @c. | 101 | * if the whole buffer contains just @c. |
102 | */ | 102 | */ |
103 | void *memchr_inv(const void *s, int c, size_t n) | 103 | void *memchr_inv(const void *s, int c, size_t n) |
104 | { | 104 | { |
105 | const unsigned char *p = s; | 105 | const unsigned char *p = s; |
106 | while (n-- != 0) | 106 | while (n-- != 0) |
107 | if ((unsigned char)c != *p++) | 107 | if ((unsigned char)c != *p++) |
108 | return (void *)(p - 1); | 108 | return (void *)(p - 1); |
109 | 109 | ||
110 | return NULL; | 110 | return NULL; |
111 | } | 111 | } |
112 | 112 | ||
113 | /* | 113 | /* |
114 | * FIXME: There should be a reserve for root, similar to ext2. | 114 | * FIXME: There should be a reserve for root, similar to ext2. |
115 | */ | 115 | */ |
116 | int logfs_statfs(struct dentry *dentry, struct kstatfs *stats) | 116 | int logfs_statfs(struct dentry *dentry, struct kstatfs *stats) |
117 | { | 117 | { |
118 | struct super_block *sb = dentry->d_sb; | 118 | struct super_block *sb = dentry->d_sb; |
119 | struct logfs_super *super = logfs_super(sb); | 119 | struct logfs_super *super = logfs_super(sb); |
120 | 120 | ||
121 | stats->f_type = LOGFS_MAGIC_U32; | 121 | stats->f_type = LOGFS_MAGIC_U32; |
122 | stats->f_bsize = sb->s_blocksize; | 122 | stats->f_bsize = sb->s_blocksize; |
123 | stats->f_blocks = super->s_size >> LOGFS_BLOCK_BITS >> 3; | 123 | stats->f_blocks = super->s_size >> LOGFS_BLOCK_BITS >> 3; |
124 | stats->f_bfree = super->s_free_bytes >> sb->s_blocksize_bits; | 124 | stats->f_bfree = super->s_free_bytes >> sb->s_blocksize_bits; |
125 | stats->f_bavail = super->s_free_bytes >> sb->s_blocksize_bits; | 125 | stats->f_bavail = super->s_free_bytes >> sb->s_blocksize_bits; |
126 | stats->f_files = 0; | 126 | stats->f_files = 0; |
127 | stats->f_ffree = 0; | 127 | stats->f_ffree = 0; |
128 | stats->f_namelen = LOGFS_MAX_NAMELEN; | 128 | stats->f_namelen = LOGFS_MAX_NAMELEN; |
129 | return 0; | 129 | return 0; |
130 | } | 130 | } |
131 | 131 | ||
132 | static int logfs_sb_set(struct super_block *sb, void *_super) | 132 | static int logfs_sb_set(struct super_block *sb, void *_super) |
133 | { | 133 | { |
134 | struct logfs_super *super = _super; | 134 | struct logfs_super *super = _super; |
135 | 135 | ||
136 | sb->s_fs_info = super; | 136 | sb->s_fs_info = super; |
137 | sb->s_mtd = super->s_mtd; | 137 | sb->s_mtd = super->s_mtd; |
138 | sb->s_bdev = super->s_bdev; | 138 | sb->s_bdev = super->s_bdev; |
139 | return 0; | 139 | return 0; |
140 | } | 140 | } |
141 | 141 | ||
142 | static int logfs_sb_test(struct super_block *sb, void *_super) | 142 | static int logfs_sb_test(struct super_block *sb, void *_super) |
143 | { | 143 | { |
144 | struct logfs_super *super = _super; | 144 | struct logfs_super *super = _super; |
145 | struct mtd_info *mtd = super->s_mtd; | 145 | struct mtd_info *mtd = super->s_mtd; |
146 | 146 | ||
147 | if (mtd && sb->s_mtd == mtd) | 147 | if (mtd && sb->s_mtd == mtd) |
148 | return 1; | 148 | return 1; |
149 | if (super->s_bdev && sb->s_bdev == super->s_bdev) | 149 | if (super->s_bdev && sb->s_bdev == super->s_bdev) |
150 | return 1; | 150 | return 1; |
151 | return 0; | 151 | return 0; |
152 | } | 152 | } |
153 | 153 | ||
154 | static void set_segment_header(struct logfs_segment_header *sh, u8 type, | 154 | static void set_segment_header(struct logfs_segment_header *sh, u8 type, |
155 | u8 level, u32 segno, u32 ec) | 155 | u8 level, u32 segno, u32 ec) |
156 | { | 156 | { |
157 | sh->pad = 0; | 157 | sh->pad = 0; |
158 | sh->type = type; | 158 | sh->type = type; |
159 | sh->level = level; | 159 | sh->level = level; |
160 | sh->segno = cpu_to_be32(segno); | 160 | sh->segno = cpu_to_be32(segno); |
161 | sh->ec = cpu_to_be32(ec); | 161 | sh->ec = cpu_to_be32(ec); |
162 | sh->gec = cpu_to_be64(segno); | 162 | sh->gec = cpu_to_be64(segno); |
163 | sh->crc = logfs_crc32(sh, LOGFS_SEGMENT_HEADERSIZE, 4); | 163 | sh->crc = logfs_crc32(sh, LOGFS_SEGMENT_HEADERSIZE, 4); |
164 | } | 164 | } |
165 | 165 | ||
166 | static void logfs_write_ds(struct super_block *sb, struct logfs_disk_super *ds, | 166 | static void logfs_write_ds(struct super_block *sb, struct logfs_disk_super *ds, |
167 | u32 segno, u32 ec) | 167 | u32 segno, u32 ec) |
168 | { | 168 | { |
169 | struct logfs_super *super = logfs_super(sb); | 169 | struct logfs_super *super = logfs_super(sb); |
170 | struct logfs_segment_header *sh = &ds->ds_sh; | 170 | struct logfs_segment_header *sh = &ds->ds_sh; |
171 | int i; | 171 | int i; |
172 | 172 | ||
173 | memset(ds, 0, sizeof(*ds)); | 173 | memset(ds, 0, sizeof(*ds)); |
174 | set_segment_header(sh, SEG_SUPER, 0, segno, ec); | 174 | set_segment_header(sh, SEG_SUPER, 0, segno, ec); |
175 | 175 | ||
176 | ds->ds_ifile_levels = super->s_ifile_levels; | 176 | ds->ds_ifile_levels = super->s_ifile_levels; |
177 | ds->ds_iblock_levels = super->s_iblock_levels; | 177 | ds->ds_iblock_levels = super->s_iblock_levels; |
178 | ds->ds_data_levels = super->s_data_levels; /* XXX: Remove */ | 178 | ds->ds_data_levels = super->s_data_levels; /* XXX: Remove */ |
179 | ds->ds_segment_shift = super->s_segshift; | 179 | ds->ds_segment_shift = super->s_segshift; |
180 | ds->ds_block_shift = sb->s_blocksize_bits; | 180 | ds->ds_block_shift = sb->s_blocksize_bits; |
181 | ds->ds_write_shift = super->s_writeshift; | 181 | ds->ds_write_shift = super->s_writeshift; |
182 | ds->ds_filesystem_size = cpu_to_be64(super->s_size); | 182 | ds->ds_filesystem_size = cpu_to_be64(super->s_size); |
183 | ds->ds_segment_size = cpu_to_be32(super->s_segsize); | 183 | ds->ds_segment_size = cpu_to_be32(super->s_segsize); |
184 | ds->ds_bad_seg_reserve = cpu_to_be32(super->s_bad_seg_reserve); | 184 | ds->ds_bad_seg_reserve = cpu_to_be32(super->s_bad_seg_reserve); |
185 | ds->ds_feature_incompat = cpu_to_be64(super->s_feature_incompat); | 185 | ds->ds_feature_incompat = cpu_to_be64(super->s_feature_incompat); |
186 | ds->ds_feature_ro_compat= cpu_to_be64(super->s_feature_ro_compat); | 186 | ds->ds_feature_ro_compat= cpu_to_be64(super->s_feature_ro_compat); |
187 | ds->ds_feature_compat = cpu_to_be64(super->s_feature_compat); | 187 | ds->ds_feature_compat = cpu_to_be64(super->s_feature_compat); |
188 | ds->ds_feature_flags = cpu_to_be64(super->s_feature_flags); | 188 | ds->ds_feature_flags = cpu_to_be64(super->s_feature_flags); |
189 | ds->ds_root_reserve = cpu_to_be64(super->s_root_reserve); | 189 | ds->ds_root_reserve = cpu_to_be64(super->s_root_reserve); |
190 | ds->ds_speed_reserve = cpu_to_be64(super->s_speed_reserve); | 190 | ds->ds_speed_reserve = cpu_to_be64(super->s_speed_reserve); |
191 | journal_for_each(i) | 191 | journal_for_each(i) |
192 | ds->ds_journal_seg[i] = cpu_to_be32(super->s_journal_seg[i]); | 192 | ds->ds_journal_seg[i] = cpu_to_be32(super->s_journal_seg[i]); |
193 | ds->ds_magic = cpu_to_be64(LOGFS_MAGIC); | 193 | ds->ds_magic = cpu_to_be64(LOGFS_MAGIC); |
194 | ds->ds_crc = logfs_crc32(ds, sizeof(*ds), | 194 | ds->ds_crc = logfs_crc32(ds, sizeof(*ds), |
195 | LOGFS_SEGMENT_HEADERSIZE + 12); | 195 | LOGFS_SEGMENT_HEADERSIZE + 12); |
196 | } | 196 | } |
197 | 197 | ||
198 | static int write_one_sb(struct super_block *sb, | 198 | static int write_one_sb(struct super_block *sb, |
199 | struct page *(*find_sb)(struct super_block *sb, u64 *ofs)) | 199 | struct page *(*find_sb)(struct super_block *sb, u64 *ofs)) |
200 | { | 200 | { |
201 | struct logfs_super *super = logfs_super(sb); | 201 | struct logfs_super *super = logfs_super(sb); |
202 | struct logfs_disk_super *ds; | 202 | struct logfs_disk_super *ds; |
203 | struct logfs_segment_entry se; | 203 | struct logfs_segment_entry se; |
204 | struct page *page; | 204 | struct page *page; |
205 | u64 ofs; | 205 | u64 ofs; |
206 | u32 ec, segno; | 206 | u32 ec, segno; |
207 | int err; | 207 | int err; |
208 | 208 | ||
209 | page = find_sb(sb, &ofs); | 209 | page = find_sb(sb, &ofs); |
210 | if (!page) | 210 | if (!page) |
211 | return -EIO; | 211 | return -EIO; |
212 | ds = page_address(page); | 212 | ds = page_address(page); |
213 | segno = seg_no(sb, ofs); | 213 | segno = seg_no(sb, ofs); |
214 | logfs_get_segment_entry(sb, segno, &se); | 214 | logfs_get_segment_entry(sb, segno, &se); |
215 | ec = be32_to_cpu(se.ec_level) >> 4; | 215 | ec = be32_to_cpu(se.ec_level) >> 4; |
216 | ec++; | 216 | ec++; |
217 | logfs_set_segment_erased(sb, segno, ec, 0); | 217 | logfs_set_segment_erased(sb, segno, ec, 0); |
218 | logfs_write_ds(sb, ds, segno, ec); | 218 | logfs_write_ds(sb, ds, segno, ec); |
219 | err = super->s_devops->write_sb(sb, page); | 219 | err = super->s_devops->write_sb(sb, page); |
220 | page_cache_release(page); | 220 | page_cache_release(page); |
221 | return err; | 221 | return err; |
222 | } | 222 | } |
223 | 223 | ||
224 | int logfs_write_sb(struct super_block *sb) | 224 | int logfs_write_sb(struct super_block *sb) |
225 | { | 225 | { |
226 | struct logfs_super *super = logfs_super(sb); | 226 | struct logfs_super *super = logfs_super(sb); |
227 | int err; | 227 | int err; |
228 | 228 | ||
229 | /* First superblock */ | 229 | /* First superblock */ |
230 | err = write_one_sb(sb, super->s_devops->find_first_sb); | 230 | err = write_one_sb(sb, super->s_devops->find_first_sb); |
231 | if (err) | 231 | if (err) |
232 | return err; | 232 | return err; |
233 | 233 | ||
234 | /* Last superblock */ | 234 | /* Last superblock */ |
235 | err = write_one_sb(sb, super->s_devops->find_last_sb); | 235 | err = write_one_sb(sb, super->s_devops->find_last_sb); |
236 | if (err) | 236 | if (err) |
237 | return err; | 237 | return err; |
238 | return 0; | 238 | return 0; |
239 | } | 239 | } |
240 | 240 | ||
241 | static int ds_cmp(const void *ds0, const void *ds1) | 241 | static int ds_cmp(const void *ds0, const void *ds1) |
242 | { | 242 | { |
243 | size_t len = sizeof(struct logfs_disk_super); | 243 | size_t len = sizeof(struct logfs_disk_super); |
244 | 244 | ||
245 | /* We know the segment headers differ, so ignore them */ | 245 | /* We know the segment headers differ, so ignore them */ |
246 | len -= LOGFS_SEGMENT_HEADERSIZE; | 246 | len -= LOGFS_SEGMENT_HEADERSIZE; |
247 | ds0 += LOGFS_SEGMENT_HEADERSIZE; | 247 | ds0 += LOGFS_SEGMENT_HEADERSIZE; |
248 | ds1 += LOGFS_SEGMENT_HEADERSIZE; | 248 | ds1 += LOGFS_SEGMENT_HEADERSIZE; |
249 | return memcmp(ds0, ds1, len); | 249 | return memcmp(ds0, ds1, len); |
250 | } | 250 | } |
251 | 251 | ||
252 | static int logfs_recover_sb(struct super_block *sb) | 252 | static int logfs_recover_sb(struct super_block *sb) |
253 | { | 253 | { |
254 | struct logfs_super *super = logfs_super(sb); | 254 | struct logfs_super *super = logfs_super(sb); |
255 | struct logfs_disk_super _ds0, *ds0 = &_ds0; | 255 | struct logfs_disk_super _ds0, *ds0 = &_ds0; |
256 | struct logfs_disk_super _ds1, *ds1 = &_ds1; | 256 | struct logfs_disk_super _ds1, *ds1 = &_ds1; |
257 | int err, valid0, valid1; | 257 | int err, valid0, valid1; |
258 | 258 | ||
259 | /* read first superblock */ | 259 | /* read first superblock */ |
260 | err = wbuf_read(sb, super->s_sb_ofs[0], sizeof(*ds0), ds0); | 260 | err = wbuf_read(sb, super->s_sb_ofs[0], sizeof(*ds0), ds0); |
261 | if (err) | 261 | if (err) |
262 | return err; | 262 | return err; |
263 | /* read last superblock */ | 263 | /* read last superblock */ |
264 | err = wbuf_read(sb, super->s_sb_ofs[1], sizeof(*ds1), ds1); | 264 | err = wbuf_read(sb, super->s_sb_ofs[1], sizeof(*ds1), ds1); |
265 | if (err) | 265 | if (err) |
266 | return err; | 266 | return err; |
267 | valid0 = logfs_check_ds(ds0) == 0; | 267 | valid0 = logfs_check_ds(ds0) == 0; |
268 | valid1 = logfs_check_ds(ds1) == 0; | 268 | valid1 = logfs_check_ds(ds1) == 0; |
269 | 269 | ||
270 | if (!valid0 && valid1) { | 270 | if (!valid0 && valid1) { |
271 | printk(KERN_INFO"First superblock is invalid - fixing.\n"); | 271 | printk(KERN_INFO"First superblock is invalid - fixing.\n"); |
272 | return write_one_sb(sb, super->s_devops->find_first_sb); | 272 | return write_one_sb(sb, super->s_devops->find_first_sb); |
273 | } | 273 | } |
274 | if (valid0 && !valid1) { | 274 | if (valid0 && !valid1) { |
275 | printk(KERN_INFO"Last superblock is invalid - fixing.\n"); | 275 | printk(KERN_INFO"Last superblock is invalid - fixing.\n"); |
276 | return write_one_sb(sb, super->s_devops->find_last_sb); | 276 | return write_one_sb(sb, super->s_devops->find_last_sb); |
277 | } | 277 | } |
278 | if (valid0 && valid1 && ds_cmp(ds0, ds1)) { | 278 | if (valid0 && valid1 && ds_cmp(ds0, ds1)) { |
279 | printk(KERN_INFO"Superblocks don't match - fixing.\n"); | 279 | printk(KERN_INFO"Superblocks don't match - fixing.\n"); |
280 | return write_one_sb(sb, super->s_devops->find_last_sb); | 280 | return write_one_sb(sb, super->s_devops->find_last_sb); |
281 | } | 281 | } |
282 | /* If neither is valid now, something's wrong. Didn't we properly | 282 | /* If neither is valid now, something's wrong. Didn't we properly |
283 | * check them before?!? */ | 283 | * check them before?!? */ |
284 | BUG_ON(!valid0 && !valid1); | 284 | BUG_ON(!valid0 && !valid1); |
285 | return 0; | 285 | return 0; |
286 | } | 286 | } |
287 | 287 | ||
288 | static int logfs_make_writeable(struct super_block *sb) | 288 | static int logfs_make_writeable(struct super_block *sb) |
289 | { | 289 | { |
290 | int err; | 290 | int err; |
291 | 291 | ||
292 | /* Repair any broken superblock copies */ | 292 | /* Repair any broken superblock copies */ |
293 | err = logfs_recover_sb(sb); | 293 | err = logfs_recover_sb(sb); |
294 | if (err) | 294 | if (err) |
295 | return err; | 295 | return err; |
296 | 296 | ||
297 | /* Check areas for trailing unaccounted data */ | 297 | /* Check areas for trailing unaccounted data */ |
298 | err = logfs_check_areas(sb); | 298 | err = logfs_check_areas(sb); |
299 | if (err) | 299 | if (err) |
300 | return err; | 300 | return err; |
301 | 301 | ||
302 | err = logfs_open_segfile(sb); | 302 | err = logfs_open_segfile(sb); |
303 | if (err) | 303 | if (err) |
304 | return err; | 304 | return err; |
305 | 305 | ||
306 | /* Do one GC pass before any data gets dirtied */ | 306 | /* Do one GC pass before any data gets dirtied */ |
307 | logfs_gc_pass(sb); | 307 | logfs_gc_pass(sb); |
308 | 308 | ||
309 | /* after all initializations are done, replay the journal | 309 | /* after all initializations are done, replay the journal |
310 | * for rw-mounts, if necessary */ | 310 | * for rw-mounts, if necessary */ |
311 | err = logfs_replay_journal(sb); | 311 | err = logfs_replay_journal(sb); |
312 | if (err) | 312 | if (err) |
313 | return err; | 313 | return err; |
314 | 314 | ||
315 | return 0; | 315 | return 0; |
316 | } | 316 | } |
317 | 317 | ||
318 | static int logfs_get_sb_final(struct super_block *sb, struct vfsmount *mnt) | 318 | static int logfs_get_sb_final(struct super_block *sb, struct vfsmount *mnt) |
319 | { | 319 | { |
320 | struct logfs_super *super = logfs_super(sb); | ||
320 | struct inode *rootdir; | 321 | struct inode *rootdir; |
321 | int err; | 322 | int err; |
322 | 323 | ||
323 | /* root dir */ | 324 | /* root dir */ |
324 | rootdir = logfs_iget(sb, LOGFS_INO_ROOT); | 325 | rootdir = logfs_iget(sb, LOGFS_INO_ROOT); |
325 | if (IS_ERR(rootdir)) | 326 | if (IS_ERR(rootdir)) |
326 | goto fail; | 327 | goto fail; |
327 | 328 | ||
328 | sb->s_root = d_alloc_root(rootdir); | 329 | sb->s_root = d_alloc_root(rootdir); |
329 | if (!sb->s_root) | 330 | if (!sb->s_root) |
330 | goto fail; | 331 | goto fail; |
331 | 332 | ||
333 | super->s_erase_page = alloc_pages(GFP_KERNEL, 0); | ||
334 | if (!super->s_erase_page) | ||
335 | goto fail2; | ||
336 | memset(page_address(super->s_erase_page), 0xFF, PAGE_SIZE); | ||
337 | |||
332 | /* FIXME: check for read-only mounts */ | 338 | /* FIXME: check for read-only mounts */ |
333 | err = logfs_make_writeable(sb); | 339 | err = logfs_make_writeable(sb); |
334 | if (err) | 340 | if (err) |
335 | goto fail2; | 341 | goto fail3; |
336 | 342 | ||
337 | log_super("LogFS: Finished mounting\n"); | 343 | log_super("LogFS: Finished mounting\n"); |
338 | simple_set_mnt(mnt, sb); | 344 | simple_set_mnt(mnt, sb); |
339 | return 0; | 345 | return 0; |
340 | 346 | ||
347 | fail3: | ||
348 | __free_page(super->s_erase_page); | ||
341 | fail2: | 349 | fail2: |
342 | iput(rootdir); | 350 | iput(rootdir); |
343 | fail: | 351 | fail: |
344 | iput(logfs_super(sb)->s_master_inode); | 352 | iput(logfs_super(sb)->s_master_inode); |
345 | return -EIO; | 353 | return -EIO; |
346 | } | 354 | } |
347 | 355 | ||
348 | int logfs_check_ds(struct logfs_disk_super *ds) | 356 | int logfs_check_ds(struct logfs_disk_super *ds) |
349 | { | 357 | { |
350 | struct logfs_segment_header *sh = &ds->ds_sh; | 358 | struct logfs_segment_header *sh = &ds->ds_sh; |
351 | 359 | ||
352 | if (ds->ds_magic != cpu_to_be64(LOGFS_MAGIC)) | 360 | if (ds->ds_magic != cpu_to_be64(LOGFS_MAGIC)) |
353 | return -EINVAL; | 361 | return -EINVAL; |
354 | if (sh->crc != logfs_crc32(sh, LOGFS_SEGMENT_HEADERSIZE, 4)) | 362 | if (sh->crc != logfs_crc32(sh, LOGFS_SEGMENT_HEADERSIZE, 4)) |
355 | return -EINVAL; | 363 | return -EINVAL; |
356 | if (ds->ds_crc != logfs_crc32(ds, sizeof(*ds), | 364 | if (ds->ds_crc != logfs_crc32(ds, sizeof(*ds), |
357 | LOGFS_SEGMENT_HEADERSIZE + 12)) | 365 | LOGFS_SEGMENT_HEADERSIZE + 12)) |
358 | return -EINVAL; | 366 | return -EINVAL; |
359 | return 0; | 367 | return 0; |
360 | } | 368 | } |
361 | 369 | ||
362 | static struct page *find_super_block(struct super_block *sb) | 370 | static struct page *find_super_block(struct super_block *sb) |
363 | { | 371 | { |
364 | struct logfs_super *super = logfs_super(sb); | 372 | struct logfs_super *super = logfs_super(sb); |
365 | struct page *first, *last; | 373 | struct page *first, *last; |
366 | 374 | ||
367 | first = super->s_devops->find_first_sb(sb, &super->s_sb_ofs[0]); | 375 | first = super->s_devops->find_first_sb(sb, &super->s_sb_ofs[0]); |
368 | if (!first || IS_ERR(first)) | 376 | if (!first || IS_ERR(first)) |
369 | return NULL; | 377 | return NULL; |
370 | last = super->s_devops->find_last_sb(sb, &super->s_sb_ofs[1]); | 378 | last = super->s_devops->find_last_sb(sb, &super->s_sb_ofs[1]); |
371 | if (!last || IS_ERR(first)) { | 379 | if (!last || IS_ERR(first)) { |
372 | page_cache_release(first); | 380 | page_cache_release(first); |
373 | return NULL; | 381 | return NULL; |
374 | } | 382 | } |
375 | 383 | ||
376 | if (!logfs_check_ds(page_address(first))) { | 384 | if (!logfs_check_ds(page_address(first))) { |
377 | page_cache_release(last); | 385 | page_cache_release(last); |
378 | return first; | 386 | return first; |
379 | } | 387 | } |
380 | 388 | ||
381 | /* First one didn't work, try the second superblock */ | 389 | /* First one didn't work, try the second superblock */ |
382 | if (!logfs_check_ds(page_address(last))) { | 390 | if (!logfs_check_ds(page_address(last))) { |
383 | page_cache_release(first); | 391 | page_cache_release(first); |
384 | return last; | 392 | return last; |
385 | } | 393 | } |
386 | 394 | ||
387 | /* Neither worked, sorry folks */ | 395 | /* Neither worked, sorry folks */ |
388 | page_cache_release(first); | 396 | page_cache_release(first); |
389 | page_cache_release(last); | 397 | page_cache_release(last); |
390 | return NULL; | 398 | return NULL; |
391 | } | 399 | } |
392 | 400 | ||
393 | static int __logfs_read_sb(struct super_block *sb) | 401 | static int __logfs_read_sb(struct super_block *sb) |
394 | { | 402 | { |
395 | struct logfs_super *super = logfs_super(sb); | 403 | struct logfs_super *super = logfs_super(sb); |
396 | struct page *page; | 404 | struct page *page; |
397 | struct logfs_disk_super *ds; | 405 | struct logfs_disk_super *ds; |
398 | int i; | 406 | int i; |
399 | 407 | ||
400 | page = find_super_block(sb); | 408 | page = find_super_block(sb); |
401 | if (!page) | 409 | if (!page) |
402 | return -EIO; | 410 | return -EIO; |
403 | 411 | ||
404 | ds = page_address(page); | 412 | ds = page_address(page); |
405 | super->s_size = be64_to_cpu(ds->ds_filesystem_size); | 413 | super->s_size = be64_to_cpu(ds->ds_filesystem_size); |
406 | super->s_root_reserve = be64_to_cpu(ds->ds_root_reserve); | 414 | super->s_root_reserve = be64_to_cpu(ds->ds_root_reserve); |
407 | super->s_speed_reserve = be64_to_cpu(ds->ds_speed_reserve); | 415 | super->s_speed_reserve = be64_to_cpu(ds->ds_speed_reserve); |
408 | super->s_bad_seg_reserve = be32_to_cpu(ds->ds_bad_seg_reserve); | 416 | super->s_bad_seg_reserve = be32_to_cpu(ds->ds_bad_seg_reserve); |
409 | super->s_segsize = 1 << ds->ds_segment_shift; | 417 | super->s_segsize = 1 << ds->ds_segment_shift; |
410 | super->s_segmask = (1 << ds->ds_segment_shift) - 1; | 418 | super->s_segmask = (1 << ds->ds_segment_shift) - 1; |
411 | super->s_segshift = ds->ds_segment_shift; | 419 | super->s_segshift = ds->ds_segment_shift; |
412 | sb->s_blocksize = 1 << ds->ds_block_shift; | 420 | sb->s_blocksize = 1 << ds->ds_block_shift; |
413 | sb->s_blocksize_bits = ds->ds_block_shift; | 421 | sb->s_blocksize_bits = ds->ds_block_shift; |
414 | super->s_writesize = 1 << ds->ds_write_shift; | 422 | super->s_writesize = 1 << ds->ds_write_shift; |
415 | super->s_writeshift = ds->ds_write_shift; | 423 | super->s_writeshift = ds->ds_write_shift; |
416 | super->s_no_segs = super->s_size >> super->s_segshift; | 424 | super->s_no_segs = super->s_size >> super->s_segshift; |
417 | super->s_no_blocks = super->s_segsize >> sb->s_blocksize_bits; | 425 | super->s_no_blocks = super->s_segsize >> sb->s_blocksize_bits; |
418 | super->s_feature_incompat = be64_to_cpu(ds->ds_feature_incompat); | 426 | super->s_feature_incompat = be64_to_cpu(ds->ds_feature_incompat); |
419 | super->s_feature_ro_compat = be64_to_cpu(ds->ds_feature_ro_compat); | 427 | super->s_feature_ro_compat = be64_to_cpu(ds->ds_feature_ro_compat); |
420 | super->s_feature_compat = be64_to_cpu(ds->ds_feature_compat); | 428 | super->s_feature_compat = be64_to_cpu(ds->ds_feature_compat); |
421 | super->s_feature_flags = be64_to_cpu(ds->ds_feature_flags); | 429 | super->s_feature_flags = be64_to_cpu(ds->ds_feature_flags); |
422 | 430 | ||
423 | journal_for_each(i) | 431 | journal_for_each(i) |
424 | super->s_journal_seg[i] = be32_to_cpu(ds->ds_journal_seg[i]); | 432 | super->s_journal_seg[i] = be32_to_cpu(ds->ds_journal_seg[i]); |
425 | 433 | ||
426 | super->s_ifile_levels = ds->ds_ifile_levels; | 434 | super->s_ifile_levels = ds->ds_ifile_levels; |
427 | super->s_iblock_levels = ds->ds_iblock_levels; | 435 | super->s_iblock_levels = ds->ds_iblock_levels; |
428 | super->s_data_levels = ds->ds_data_levels; | 436 | super->s_data_levels = ds->ds_data_levels; |
429 | super->s_total_levels = super->s_ifile_levels + super->s_iblock_levels | 437 | super->s_total_levels = super->s_ifile_levels + super->s_iblock_levels |
430 | + super->s_data_levels; | 438 | + super->s_data_levels; |
431 | page_cache_release(page); | 439 | page_cache_release(page); |
432 | return 0; | 440 | return 0; |
433 | } | 441 | } |
434 | 442 | ||
435 | static int logfs_read_sb(struct super_block *sb) | 443 | static int logfs_read_sb(struct super_block *sb) |
436 | { | 444 | { |
437 | struct logfs_super *super = logfs_super(sb); | 445 | struct logfs_super *super = logfs_super(sb); |
438 | int ret; | 446 | int ret; |
439 | 447 | ||
440 | super->s_btree_pool = mempool_create(32, btree_alloc, btree_free, NULL); | 448 | super->s_btree_pool = mempool_create(32, btree_alloc, btree_free, NULL); |
441 | if (!super->s_btree_pool) | 449 | if (!super->s_btree_pool) |
442 | return -ENOMEM; | 450 | return -ENOMEM; |
443 | 451 | ||
444 | btree_init_mempool64(&super->s_shadow_tree.new, super->s_btree_pool); | 452 | btree_init_mempool64(&super->s_shadow_tree.new, super->s_btree_pool); |
445 | btree_init_mempool64(&super->s_shadow_tree.old, super->s_btree_pool); | 453 | btree_init_mempool64(&super->s_shadow_tree.old, super->s_btree_pool); |
446 | 454 | ||
447 | ret = logfs_init_mapping(sb); | 455 | ret = logfs_init_mapping(sb); |
448 | if (ret) | 456 | if (ret) |
449 | return ret; | 457 | return ret; |
450 | 458 | ||
451 | ret = __logfs_read_sb(sb); | 459 | ret = __logfs_read_sb(sb); |
452 | if (ret) | 460 | if (ret) |
453 | return ret; | 461 | return ret; |
454 | 462 | ||
455 | mutex_init(&super->s_dirop_mutex); | 463 | mutex_init(&super->s_dirop_mutex); |
456 | mutex_init(&super->s_object_alias_mutex); | 464 | mutex_init(&super->s_object_alias_mutex); |
457 | INIT_LIST_HEAD(&super->s_freeing_list); | 465 | INIT_LIST_HEAD(&super->s_freeing_list); |
458 | 466 | ||
459 | ret = logfs_init_rw(sb); | 467 | ret = logfs_init_rw(sb); |
460 | if (ret) | 468 | if (ret) |
461 | return ret; | 469 | return ret; |
462 | 470 | ||
463 | ret = logfs_init_areas(sb); | 471 | ret = logfs_init_areas(sb); |
464 | if (ret) | 472 | if (ret) |
465 | return ret; | 473 | return ret; |
466 | 474 | ||
467 | ret = logfs_init_gc(sb); | 475 | ret = logfs_init_gc(sb); |
468 | if (ret) | 476 | if (ret) |
469 | return ret; | 477 | return ret; |
470 | 478 | ||
471 | ret = logfs_init_journal(sb); | 479 | ret = logfs_init_journal(sb); |
472 | if (ret) | 480 | if (ret) |
473 | return ret; | 481 | return ret; |
474 | 482 | ||
475 | return 0; | 483 | return 0; |
476 | } | 484 | } |
477 | 485 | ||
478 | static void logfs_kill_sb(struct super_block *sb) | 486 | static void logfs_kill_sb(struct super_block *sb) |
479 | { | 487 | { |
480 | struct logfs_super *super = logfs_super(sb); | 488 | struct logfs_super *super = logfs_super(sb); |
481 | 489 | ||
482 | log_super("LogFS: Start unmounting\n"); | 490 | log_super("LogFS: Start unmounting\n"); |
483 | /* Alias entries slow down mount, so evict as many as possible */ | 491 | /* Alias entries slow down mount, so evict as many as possible */ |
484 | sync_filesystem(sb); | 492 | sync_filesystem(sb); |
485 | logfs_write_anchor(super->s_master_inode); | 493 | logfs_write_anchor(super->s_master_inode); |
486 | 494 | ||
487 | /* | 495 | /* |
488 | * From this point on alias entries are simply dropped - and any | 496 | * From this point on alias entries are simply dropped - and any |
489 | * writes to the object store are considered bugs. | 497 | * writes to the object store are considered bugs. |
490 | */ | 498 | */ |
491 | super->s_flags |= LOGFS_SB_FLAG_SHUTDOWN; | 499 | super->s_flags |= LOGFS_SB_FLAG_SHUTDOWN; |
492 | log_super("LogFS: Now in shutdown\n"); | 500 | log_super("LogFS: Now in shutdown\n"); |
493 | generic_shutdown_super(sb); | 501 | generic_shutdown_super(sb); |
494 | 502 | ||
495 | BUG_ON(super->s_dirty_used_bytes || super->s_dirty_free_bytes); | 503 | BUG_ON(super->s_dirty_used_bytes || super->s_dirty_free_bytes); |
496 | 504 | ||
497 | logfs_cleanup_gc(sb); | 505 | logfs_cleanup_gc(sb); |
498 | logfs_cleanup_journal(sb); | 506 | logfs_cleanup_journal(sb); |
499 | logfs_cleanup_areas(sb); | 507 | logfs_cleanup_areas(sb); |
500 | logfs_cleanup_rw(sb); | 508 | logfs_cleanup_rw(sb); |
509 | if (super->s_erase_page) | ||
510 | __free_page(super->s_erase_page); | ||
501 | super->s_devops->put_device(sb); | 511 | super->s_devops->put_device(sb); |
502 | mempool_destroy(super->s_btree_pool); | 512 | mempool_destroy(super->s_btree_pool); |
503 | mempool_destroy(super->s_alias_pool); | 513 | mempool_destroy(super->s_alias_pool); |
504 | kfree(super); | 514 | kfree(super); |
505 | log_super("LogFS: Finished unmounting\n"); | 515 | log_super("LogFS: Finished unmounting\n"); |
506 | } | 516 | } |
507 | 517 | ||
508 | int logfs_get_sb_device(struct file_system_type *type, int flags, | 518 | int logfs_get_sb_device(struct file_system_type *type, int flags, |
509 | struct mtd_info *mtd, struct block_device *bdev, | 519 | struct mtd_info *mtd, struct block_device *bdev, |
510 | const struct logfs_device_ops *devops, struct vfsmount *mnt) | 520 | const struct logfs_device_ops *devops, struct vfsmount *mnt) |
511 | { | 521 | { |
512 | struct logfs_super *super; | 522 | struct logfs_super *super; |
513 | struct super_block *sb; | 523 | struct super_block *sb; |
514 | int err = -ENOMEM; | 524 | int err = -ENOMEM; |
515 | static int mount_count; | 525 | static int mount_count; |
516 | 526 | ||
517 | log_super("LogFS: Start mount %x\n", mount_count++); | 527 | log_super("LogFS: Start mount %x\n", mount_count++); |
518 | super = kzalloc(sizeof(*super), GFP_KERNEL); | 528 | super = kzalloc(sizeof(*super), GFP_KERNEL); |
519 | if (!super) | 529 | if (!super) |
520 | goto err0; | 530 | goto err0; |
521 | 531 | ||
522 | super->s_mtd = mtd; | 532 | super->s_mtd = mtd; |
523 | super->s_bdev = bdev; | 533 | super->s_bdev = bdev; |
524 | err = -EINVAL; | 534 | err = -EINVAL; |
525 | sb = sget(type, logfs_sb_test, logfs_sb_set, super); | 535 | sb = sget(type, logfs_sb_test, logfs_sb_set, super); |
526 | if (IS_ERR(sb)) | 536 | if (IS_ERR(sb)) |
527 | goto err0; | 537 | goto err0; |
528 | 538 | ||
529 | if (sb->s_root) { | 539 | if (sb->s_root) { |
530 | /* Device is already in use */ | 540 | /* Device is already in use */ |
531 | err = 0; | 541 | err = 0; |
532 | simple_set_mnt(mnt, sb); | 542 | simple_set_mnt(mnt, sb); |
533 | goto err0; | 543 | goto err0; |
534 | } | 544 | } |
535 | 545 | ||
536 | super->s_devops = devops; | 546 | super->s_devops = devops; |
537 | 547 | ||
538 | /* | 548 | /* |
539 | * sb->s_maxbytes is limited to 8TB. On 32bit systems, the page cache | 549 | * sb->s_maxbytes is limited to 8TB. On 32bit systems, the page cache |
540 | * only covers 16TB and the upper 8TB are used for indirect blocks. | 550 | * only covers 16TB and the upper 8TB are used for indirect blocks. |
541 | * On 64bit system we could bump up the limit, but that would make | 551 | * On 64bit system we could bump up the limit, but that would make |
542 | * the filesystem incompatible with 32bit systems. | 552 | * the filesystem incompatible with 32bit systems. |
543 | */ | 553 | */ |
544 | sb->s_maxbytes = (1ull << 43) - 1; | 554 | sb->s_maxbytes = (1ull << 43) - 1; |
545 | sb->s_op = &logfs_super_operations; | 555 | sb->s_op = &logfs_super_operations; |
546 | sb->s_flags = flags | MS_NOATIME; | 556 | sb->s_flags = flags | MS_NOATIME; |
547 | 557 | ||
548 | err = logfs_read_sb(sb); | 558 | err = logfs_read_sb(sb); |
549 | if (err) | 559 | if (err) |
550 | goto err1; | 560 | goto err1; |
551 | 561 | ||
552 | sb->s_flags |= MS_ACTIVE; | 562 | sb->s_flags |= MS_ACTIVE; |
553 | err = logfs_get_sb_final(sb, mnt); | 563 | err = logfs_get_sb_final(sb, mnt); |
554 | if (err) | 564 | if (err) |
555 | goto err1; | 565 | goto err1; |
556 | return 0; | 566 | return 0; |
557 | 567 | ||
558 | err1: | 568 | err1: |
559 | up_write(&sb->s_umount); | 569 | up_write(&sb->s_umount); |
560 | deactivate_super(sb); | 570 | deactivate_super(sb); |
561 | return err; | 571 | return err; |
562 | err0: | 572 | err0: |
563 | kfree(super); | 573 | kfree(super); |
564 | //devops->put_device(sb); | 574 | //devops->put_device(sb); |
565 | return err; | 575 | return err; |
566 | } | 576 | } |
567 | 577 | ||
568 | static int logfs_get_sb(struct file_system_type *type, int flags, | 578 | static int logfs_get_sb(struct file_system_type *type, int flags, |
569 | const char *devname, void *data, struct vfsmount *mnt) | 579 | const char *devname, void *data, struct vfsmount *mnt) |
570 | { | 580 | { |
571 | ulong mtdnr; | 581 | ulong mtdnr; |
572 | 582 | ||
573 | if (!devname) | 583 | if (!devname) |
574 | return logfs_get_sb_bdev(type, flags, devname, mnt); | 584 | return logfs_get_sb_bdev(type, flags, devname, mnt); |
575 | if (strncmp(devname, "mtd", 3)) | 585 | if (strncmp(devname, "mtd", 3)) |
576 | return logfs_get_sb_bdev(type, flags, devname, mnt); | 586 | return logfs_get_sb_bdev(type, flags, devname, mnt); |
577 | 587 | ||
578 | { | 588 | { |
579 | char *garbage; | 589 | char *garbage; |
580 | mtdnr = simple_strtoul(devname+3, &garbage, 0); | 590 | mtdnr = simple_strtoul(devname+3, &garbage, 0); |
581 | if (*garbage) | 591 | if (*garbage) |
582 | return -EINVAL; | 592 | return -EINVAL; |
583 | } | 593 | } |
584 | 594 | ||
585 | return logfs_get_sb_mtd(type, flags, mtdnr, mnt); | 595 | return logfs_get_sb_mtd(type, flags, mtdnr, mnt); |
586 | } | 596 | } |
587 | 597 | ||
588 | static struct file_system_type logfs_fs_type = { | 598 | static struct file_system_type logfs_fs_type = { |
589 | .owner = THIS_MODULE, | 599 | .owner = THIS_MODULE, |
590 | .name = "logfs", | 600 | .name = "logfs", |
591 | .get_sb = logfs_get_sb, | 601 | .get_sb = logfs_get_sb, |
592 | .kill_sb = logfs_kill_sb, | 602 | .kill_sb = logfs_kill_sb, |
593 | .fs_flags = FS_REQUIRES_DEV, | 603 | .fs_flags = FS_REQUIRES_DEV, |
594 | 604 | ||
595 | }; | 605 | }; |
596 | 606 | ||
597 | static int __init logfs_init(void) | 607 | static int __init logfs_init(void) |
598 | { | 608 | { |
599 | int ret; | 609 | int ret; |
600 | 610 | ||
601 | emergency_page = alloc_pages(GFP_KERNEL, 0); | 611 | emergency_page = alloc_pages(GFP_KERNEL, 0); |
602 | if (!emergency_page) | 612 | if (!emergency_page) |
603 | return -ENOMEM; | 613 | return -ENOMEM; |
604 | 614 | ||
605 | ret = logfs_compr_init(); | 615 | ret = logfs_compr_init(); |
606 | if (ret) | 616 | if (ret) |
607 | goto out1; | 617 | goto out1; |
608 | 618 | ||
609 | ret = logfs_init_inode_cache(); | 619 | ret = logfs_init_inode_cache(); |
610 | if (ret) | 620 | if (ret) |
611 | goto out2; | 621 | goto out2; |
612 | 622 | ||
613 | return register_filesystem(&logfs_fs_type); | 623 | return register_filesystem(&logfs_fs_type); |
614 | out2: | 624 | out2: |
615 | logfs_compr_exit(); | 625 | logfs_compr_exit(); |
616 | out1: | 626 | out1: |
617 | __free_pages(emergency_page, 0); | 627 | __free_pages(emergency_page, 0); |
618 | return ret; | 628 | return ret; |
619 | } | 629 | } |
620 | 630 | ||
621 | static void __exit logfs_exit(void) | 631 | static void __exit logfs_exit(void) |
622 | { | 632 | { |
623 | unregister_filesystem(&logfs_fs_type); | 633 | unregister_filesystem(&logfs_fs_type); |
624 | logfs_destroy_inode_cache(); | 634 | logfs_destroy_inode_cache(); |
625 | logfs_compr_exit(); | 635 | logfs_compr_exit(); |
626 | __free_pages(emergency_page, 0); | 636 | __free_pages(emergency_page, 0); |
627 | } | 637 | } |
628 | 638 | ||
629 | module_init(logfs_init); | 639 | module_init(logfs_init); |
630 | module_exit(logfs_exit); | 640 | module_exit(logfs_exit); |
631 | 641 | ||
632 | MODULE_LICENSE("GPL v2"); | 642 | MODULE_LICENSE("GPL v2"); |
633 | MODULE_AUTHOR("Joern Engel <joern@logfs.org>"); | 643 | MODULE_AUTHOR("Joern Engel <joern@logfs.org>"); |
634 | MODULE_DESCRIPTION("scalable flash filesystem"); | 644 | MODULE_DESCRIPTION("scalable flash filesystem"); |
635 | 645 |