Blame view
fs/nilfs2/dat.c
13.2 KB
a17564f58 nilfs2: disk addr... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
/* * dat.c - NILFS disk address translation. * * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Written by Koji Sato <koji@osrg.net>. */ #include <linux/types.h> #include <linux/buffer_head.h> #include <linux/string.h> #include <linux/errno.h> #include "nilfs.h" #include "mdt.h" #include "alloc.h" #include "dat.h" #define NILFS_CNO_MIN ((__u64)1) #define NILFS_CNO_MAX (~(__u64)0) |
f5974c8f8 nilfs2: add omitt... |
35 36 37 38 39 40 |
/** * struct nilfs_dat_info - on-memory private data of DAT file * @mi: on-memory private data of metadata file * @palloc_cache: persistent object allocator cache of DAT file * @shadow: shadow map of DAT file */ |
8908b2f70 nilfs2: add pallo... |
41 42 43 |
struct nilfs_dat_info { struct nilfs_mdt_info mi; struct nilfs_palloc_cache palloc_cache; |
c1c1d7092 nilfs2: get rid o... |
44 |
struct nilfs_shadow_map shadow; |
8908b2f70 nilfs2: add pallo... |
45 46 47 48 49 50 |
}; static inline struct nilfs_dat_info *NILFS_DAT_I(struct inode *dat) { return (struct nilfs_dat_info *)NILFS_MDT(dat); } |
a17564f58 nilfs2: disk addr... |
51 52 53 54 55 56 57 58 59 60 |
static int nilfs_dat_prepare_entry(struct inode *dat, struct nilfs_palloc_req *req, int create) { return nilfs_palloc_get_entry_block(dat, req->pr_entry_nr, create, &req->pr_entry_bh); } static void nilfs_dat_commit_entry(struct inode *dat, struct nilfs_palloc_req *req) { |
5fc7b1417 nilfs2: use mark_... |
61 |
mark_buffer_dirty(req->pr_entry_bh); |
a17564f58 nilfs2: disk addr... |
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
nilfs_mdt_mark_dirty(dat); brelse(req->pr_entry_bh); } static void nilfs_dat_abort_entry(struct inode *dat, struct nilfs_palloc_req *req) { brelse(req->pr_entry_bh); } int nilfs_dat_prepare_alloc(struct inode *dat, struct nilfs_palloc_req *req) { int ret; ret = nilfs_palloc_prepare_alloc_entry(dat, req); if (ret < 0) return ret; ret = nilfs_dat_prepare_entry(dat, req, 1); if (ret < 0) nilfs_palloc_abort_alloc_entry(dat, req); return ret; } void nilfs_dat_commit_alloc(struct inode *dat, struct nilfs_palloc_req *req) { struct nilfs_dat_entry *entry; void *kaddr; |
7b9c0976a nilfs2: remove th... |
91 |
kaddr = kmap_atomic(req->pr_entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
92 93 94 95 96 |
entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, req->pr_entry_bh, kaddr); entry->de_start = cpu_to_le64(NILFS_CNO_MIN); entry->de_end = cpu_to_le64(NILFS_CNO_MAX); entry->de_blocknr = cpu_to_le64(0); |
7b9c0976a nilfs2: remove th... |
97 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
98 99 100 101 102 103 104 105 106 107 |
nilfs_palloc_commit_alloc_entry(dat, req); nilfs_dat_commit_entry(dat, req); } void nilfs_dat_abort_alloc(struct inode *dat, struct nilfs_palloc_req *req) { nilfs_dat_abort_entry(dat, req); nilfs_palloc_abort_alloc_entry(dat, req); } |
abc0b50b6 nilfs2: eliminate... |
108 109 |
static void nilfs_dat_commit_free(struct inode *dat, struct nilfs_palloc_req *req) |
a17564f58 nilfs2: disk addr... |
110 111 112 |
{ struct nilfs_dat_entry *entry; void *kaddr; |
7b9c0976a nilfs2: remove th... |
113 |
kaddr = kmap_atomic(req->pr_entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
114 115 116 117 118 |
entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, req->pr_entry_bh, kaddr); entry->de_start = cpu_to_le64(NILFS_CNO_MIN); entry->de_end = cpu_to_le64(NILFS_CNO_MIN); entry->de_blocknr = cpu_to_le64(0); |
7b9c0976a nilfs2: remove th... |
119 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
120 121 122 123 |
nilfs_dat_commit_entry(dat, req); nilfs_palloc_commit_free_entry(dat, req); } |
a17564f58 nilfs2: disk addr... |
124 125 126 127 128 |
int nilfs_dat_prepare_start(struct inode *dat, struct nilfs_palloc_req *req) { int ret; ret = nilfs_dat_prepare_entry(dat, req, 0); |
1f5abe7e7 nilfs2: replace B... |
129 |
WARN_ON(ret == -ENOENT); |
a17564f58 nilfs2: disk addr... |
130 131 132 133 134 135 136 137 |
return ret; } void nilfs_dat_commit_start(struct inode *dat, struct nilfs_palloc_req *req, sector_t blocknr) { struct nilfs_dat_entry *entry; void *kaddr; |
7b9c0976a nilfs2: remove th... |
138 |
kaddr = kmap_atomic(req->pr_entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
139 140 141 |
entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, req->pr_entry_bh, kaddr); entry->de_start = cpu_to_le64(nilfs_mdt_cno(dat)); |
a17564f58 nilfs2: disk addr... |
142 |
entry->de_blocknr = cpu_to_le64(blocknr); |
7b9c0976a nilfs2: remove th... |
143 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
144 145 146 |
nilfs_dat_commit_entry(dat, req); } |
a17564f58 nilfs2: disk addr... |
147 148 149 150 151 152 153 154 155 156 |
int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req) { struct nilfs_dat_entry *entry; __u64 start; sector_t blocknr; void *kaddr; int ret; ret = nilfs_dat_prepare_entry(dat, req, 0); if (ret < 0) { |
1f5abe7e7 nilfs2: replace B... |
157 |
WARN_ON(ret == -ENOENT); |
a17564f58 nilfs2: disk addr... |
158 159 |
return ret; } |
7b9c0976a nilfs2: remove th... |
160 |
kaddr = kmap_atomic(req->pr_entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
161 162 163 164 |
entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, req->pr_entry_bh, kaddr); start = le64_to_cpu(entry->de_start); blocknr = le64_to_cpu(entry->de_blocknr); |
7b9c0976a nilfs2: remove th... |
165 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
if (blocknr == 0) { ret = nilfs_palloc_prepare_free_entry(dat, req); if (ret < 0) { nilfs_dat_abort_entry(dat, req); return ret; } } return 0; } void nilfs_dat_commit_end(struct inode *dat, struct nilfs_palloc_req *req, int dead) { struct nilfs_dat_entry *entry; __u64 start, end; sector_t blocknr; void *kaddr; |
7b9c0976a nilfs2: remove th... |
185 |
kaddr = kmap_atomic(req->pr_entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
186 187 188 189 190 |
entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, req->pr_entry_bh, kaddr); end = start = le64_to_cpu(entry->de_start); if (!dead) { end = nilfs_mdt_cno(dat); |
1f5abe7e7 nilfs2: replace B... |
191 |
WARN_ON(start > end); |
a17564f58 nilfs2: disk addr... |
192 193 194 |
} entry->de_end = cpu_to_le64(end); blocknr = le64_to_cpu(entry->de_blocknr); |
7b9c0976a nilfs2: remove th... |
195 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
196 197 198 199 200 201 202 203 204 205 206 207 208 |
if (blocknr == 0) nilfs_dat_commit_free(dat, req); else nilfs_dat_commit_entry(dat, req); } void nilfs_dat_abort_end(struct inode *dat, struct nilfs_palloc_req *req) { struct nilfs_dat_entry *entry; __u64 start; sector_t blocknr; void *kaddr; |
7b9c0976a nilfs2: remove th... |
209 |
kaddr = kmap_atomic(req->pr_entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
210 211 212 213 |
entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, req->pr_entry_bh, kaddr); start = le64_to_cpu(entry->de_start); blocknr = le64_to_cpu(entry->de_blocknr); |
7b9c0976a nilfs2: remove th... |
214 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
215 216 217 218 219 |
if (start == nilfs_mdt_cno(dat) && blocknr == 0) nilfs_palloc_abort_free_entry(dat, req); nilfs_dat_abort_entry(dat, req); } |
bd8169efa nilfs2: add updat... |
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
int nilfs_dat_prepare_update(struct inode *dat, struct nilfs_palloc_req *oldreq, struct nilfs_palloc_req *newreq) { int ret; ret = nilfs_dat_prepare_end(dat, oldreq); if (!ret) { ret = nilfs_dat_prepare_alloc(dat, newreq); if (ret < 0) nilfs_dat_abort_end(dat, oldreq); } return ret; } void nilfs_dat_commit_update(struct inode *dat, struct nilfs_palloc_req *oldreq, struct nilfs_palloc_req *newreq, int dead) { nilfs_dat_commit_end(dat, oldreq, dead); nilfs_dat_commit_alloc(dat, newreq); } void nilfs_dat_abort_update(struct inode *dat, struct nilfs_palloc_req *oldreq, struct nilfs_palloc_req *newreq) { nilfs_dat_abort_end(dat, oldreq); nilfs_dat_abort_alloc(dat, newreq); } |
a17564f58 nilfs2: disk addr... |
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
/** * nilfs_dat_mark_dirty - * @dat: DAT file inode * @vblocknr: virtual block number * * Description: * * Return Value: On success, 0 is returned. On error, one of the following * negative error codes is returned. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. */ int nilfs_dat_mark_dirty(struct inode *dat, __u64 vblocknr) { struct nilfs_palloc_req req; int ret; req.pr_entry_nr = vblocknr; ret = nilfs_dat_prepare_entry(dat, &req, 0); if (ret == 0) nilfs_dat_commit_entry(dat, &req); return ret; } /** * nilfs_dat_freev - free virtual block numbers * @dat: DAT file inode * @vblocknrs: array of virtual block numbers * @nitems: number of virtual block numbers * * Description: nilfs_dat_freev() frees the virtual block numbers specified by * @vblocknrs and @nitems. * * Return Value: On success, 0 is returned. On error, one of the following |
7a65004bb nilfs2: fix vario... |
286 |
* negative error codes is returned. |
a17564f58 nilfs2: disk addr... |
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
* * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. * * %-ENOENT - The virtual block number have not been allocated. */ int nilfs_dat_freev(struct inode *dat, __u64 *vblocknrs, size_t nitems) { return nilfs_palloc_freev(dat, vblocknrs, nitems); } /** * nilfs_dat_move - change a block number * @dat: DAT file inode * @vblocknr: virtual block number * @blocknr: block number * * Description: nilfs_dat_move() changes the block number associated with * @vblocknr to @blocknr. * * Return Value: On success, 0 is returned. On error, one of the following * negative error codes is returned. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. */ int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr) { struct buffer_head *entry_bh; struct nilfs_dat_entry *entry; void *kaddr; int ret; ret = nilfs_palloc_get_entry_block(dat, vblocknr, 0, &entry_bh); if (ret < 0) return ret; |
c1c1d7092 nilfs2: get rid o... |
325 326 327 328 329 330 |
/* * The given disk block number (blocknr) is not yet written to * the device at this point. * * To prevent nilfs_dat_translate() from returning the |
f6c26ec50 nilfs2: fix typo ... |
331 |
* uncommitted block number, this makes a copy of the entry |
c1c1d7092 nilfs2: get rid o... |
332 333 334 335 336 337 338 339 340 |
* buffer and redirects nilfs_dat_translate() to the copy. */ if (!buffer_nilfs_redirected(entry_bh)) { ret = nilfs_mdt_freeze_buffer(dat, entry_bh); if (ret) { brelse(entry_bh); return ret; } } |
7b9c0976a nilfs2: remove th... |
341 |
kaddr = kmap_atomic(entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
342 |
entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr); |
1f5abe7e7 nilfs2: replace B... |
343 |
if (unlikely(entry->de_blocknr == cpu_to_le64(0))) { |
a17564f58 nilfs2: disk addr... |
344 345 346 347 348 |
printk(KERN_CRIT "%s: vbn = %llu, [%llu, %llu) ", __func__, (unsigned long long)vblocknr, (unsigned long long)le64_to_cpu(entry->de_start), (unsigned long long)le64_to_cpu(entry->de_end)); |
7b9c0976a nilfs2: remove th... |
349 |
kunmap_atomic(kaddr); |
1f5abe7e7 nilfs2: replace B... |
350 351 |
brelse(entry_bh); return -EINVAL; |
a17564f58 nilfs2: disk addr... |
352 |
} |
1f5abe7e7 nilfs2: replace B... |
353 |
WARN_ON(blocknr == 0); |
a17564f58 nilfs2: disk addr... |
354 |
entry->de_blocknr = cpu_to_le64(blocknr); |
7b9c0976a nilfs2: remove th... |
355 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
356 |
|
5fc7b1417 nilfs2: use mark_... |
357 |
mark_buffer_dirty(entry_bh); |
a17564f58 nilfs2: disk addr... |
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
nilfs_mdt_mark_dirty(dat); brelse(entry_bh); return 0; } /** * nilfs_dat_translate - translate a virtual block number to a block number * @dat: DAT file inode * @vblocknr: virtual block number * @blocknrp: pointer to a block number * * Description: nilfs_dat_translate() maps the virtual block number @vblocknr * to the corresponding block number. * * Return Value: On success, 0 is returned and the block number associated * with @vblocknr is stored in the place pointed by @blocknrp. On error, one * of the following negative error codes is returned. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. * * %-ENOENT - A block number associated with @vblocknr does not exist. */ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) { |
c1c1d7092 nilfs2: get rid o... |
386 |
struct buffer_head *entry_bh, *bh; |
a17564f58 nilfs2: disk addr... |
387 388 389 390 391 392 393 394 |
struct nilfs_dat_entry *entry; sector_t blocknr; void *kaddr; int ret; ret = nilfs_palloc_get_entry_block(dat, vblocknr, 0, &entry_bh); if (ret < 0) return ret; |
c1c1d7092 nilfs2: get rid o... |
395 396 397 398 399 400 401 402 |
if (!nilfs_doing_gc() && buffer_nilfs_redirected(entry_bh)) { bh = nilfs_mdt_get_frozen_buffer(dat, entry_bh); if (bh) { WARN_ON(!buffer_uptodate(bh)); brelse(entry_bh); entry_bh = bh; } } |
7b9c0976a nilfs2: remove th... |
403 |
kaddr = kmap_atomic(entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
404 405 406 407 408 409 |
entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr); blocknr = le64_to_cpu(entry->de_blocknr); if (blocknr == 0) { ret = -ENOENT; goto out; } |
086d1764b nilfs2: delete un... |
410 |
*blocknrp = blocknr; |
a17564f58 nilfs2: disk addr... |
411 412 |
out: |
7b9c0976a nilfs2: remove th... |
413 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
414 415 416 |
brelse(entry_bh); return ret; } |
003ff182f nilfs2: allow fut... |
417 |
ssize_t nilfs_dat_get_vinfo(struct inode *dat, void *buf, unsigned visz, |
a17564f58 nilfs2: disk addr... |
418 419 420 421 |
size_t nvi) { struct buffer_head *entry_bh; struct nilfs_dat_entry *entry; |
003ff182f nilfs2: allow fut... |
422 |
struct nilfs_vinfo *vinfo = buf; |
a17564f58 nilfs2: disk addr... |
423 424 425 426 427 428 |
__u64 first, last; void *kaddr; unsigned long entries_per_block = NILFS_MDT(dat)->mi_entries_per_block; int i, j, n, ret; for (i = 0; i < nvi; i += n) { |
003ff182f nilfs2: allow fut... |
429 |
ret = nilfs_palloc_get_entry_block(dat, vinfo->vi_vblocknr, |
a17564f58 nilfs2: disk addr... |
430 431 432 |
0, &entry_bh); if (ret < 0) return ret; |
7b9c0976a nilfs2: remove th... |
433 |
kaddr = kmap_atomic(entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
434 |
/* last virtual block number in this block */ |
003ff182f nilfs2: allow fut... |
435 |
first = vinfo->vi_vblocknr; |
a17564f58 nilfs2: disk addr... |
436 437 438 439 |
do_div(first, entries_per_block); first *= entries_per_block; last = first + entries_per_block - 1; for (j = i, n = 0; |
003ff182f nilfs2: allow fut... |
440 441 442 |
j < nvi && vinfo->vi_vblocknr >= first && vinfo->vi_vblocknr <= last; j++, n++, vinfo = (void *)vinfo + visz) { |
a17564f58 nilfs2: disk addr... |
443 |
entry = nilfs_palloc_block_get_entry( |
003ff182f nilfs2: allow fut... |
444 445 446 447 |
dat, vinfo->vi_vblocknr, entry_bh, kaddr); vinfo->vi_start = le64_to_cpu(entry->de_start); vinfo->vi_end = le64_to_cpu(entry->de_end); vinfo->vi_blocknr = le64_to_cpu(entry->de_blocknr); |
a17564f58 nilfs2: disk addr... |
448 |
} |
7b9c0976a nilfs2: remove th... |
449 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
450 451 452 453 454 |
brelse(entry_bh); } return nvi; } |
79739565e nilfs2: separate ... |
455 456 |
/** |
f1e89c86f nilfs2: use iget ... |
457 458 |
* nilfs_dat_read - read or get dat inode * @sb: super block instance |
79739565e nilfs2: separate ... |
459 |
* @entry_size: size of a dat entry |
f1e89c86f nilfs2: use iget ... |
460 461 |
* @raw_inode: on-disk dat inode * @inodep: buffer to store the inode |
79739565e nilfs2: separate ... |
462 |
*/ |
f1e89c86f nilfs2: use iget ... |
463 464 |
int nilfs_dat_read(struct super_block *sb, size_t entry_size, struct nilfs_inode *raw_inode, struct inode **inodep) |
79739565e nilfs2: separate ... |
465 466 467 |
{ static struct lock_class_key dat_lock_key; struct inode *dat; |
8908b2f70 nilfs2: add pallo... |
468 |
struct nilfs_dat_info *di; |
79739565e nilfs2: separate ... |
469 |
int err; |
f1e89c86f nilfs2: use iget ... |
470 471 472 473 474 |
dat = nilfs_iget_locked(sb, NULL, NILFS_DAT_INO); if (unlikely(!dat)) return -ENOMEM; if (!(dat->i_state & I_NEW)) goto out; |
8908b2f70 nilfs2: add pallo... |
475 |
|
f1e89c86f nilfs2: use iget ... |
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 |
err = nilfs_mdt_init(dat, NILFS_MDT_GFP, sizeof(*di)); if (err) goto failed; err = nilfs_palloc_init_blockgroup(dat, entry_size); if (err) goto failed; di = NILFS_DAT_I(dat); lockdep_set_class(&di->mi.mi_sem, &dat_lock_key); nilfs_palloc_setup_cache(dat, &di->palloc_cache); nilfs_mdt_setup_shadow_map(dat, &di->shadow); err = nilfs_read_inode_common(dat, raw_inode); if (err) goto failed; unlock_new_inode(dat); out: *inodep = dat; return 0; failed: iget_failed(dat); return err; |
79739565e nilfs2: separate ... |
500 |
} |