Blame view
fs/nilfs2/dat.c
12.7 KB
ae98043f5 nilfs2: convert t... |
1 |
// SPDX-License-Identifier: GPL-2.0+ |
a17564f58 nilfs2: disk addr... |
2 3 4 5 6 |
/* * dat.c - NILFS disk address translation. * * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation. * |
4b420ab4e nilfs2: clean up ... |
7 |
* Written by Koji Sato. |
a17564f58 nilfs2: disk addr... |
8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
*/ #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... |
22 23 24 25 26 27 |
/** * 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... |
28 29 30 |
struct nilfs_dat_info { struct nilfs_mdt_info mi; struct nilfs_palloc_cache palloc_cache; |
c1c1d7092 nilfs2: get rid o... |
31 |
struct nilfs_shadow_map shadow; |
8908b2f70 nilfs2: add pallo... |
32 33 34 35 36 37 |
}; static inline struct nilfs_dat_info *NILFS_DAT_I(struct inode *dat) { return (struct nilfs_dat_info *)NILFS_MDT(dat); } |
a17564f58 nilfs2: disk addr... |
38 39 40 41 42 43 44 45 46 47 |
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_... |
48 |
mark_buffer_dirty(req->pr_entry_bh); |
a17564f58 nilfs2: disk addr... |
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
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... |
78 |
kaddr = kmap_atomic(req->pr_entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
79 80 81 82 83 |
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... |
84 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
85 86 87 88 89 90 91 92 93 94 |
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... |
95 96 |
static void nilfs_dat_commit_free(struct inode *dat, struct nilfs_palloc_req *req) |
a17564f58 nilfs2: disk addr... |
97 98 99 |
{ struct nilfs_dat_entry *entry; void *kaddr; |
7b9c0976a nilfs2: remove th... |
100 |
kaddr = kmap_atomic(req->pr_entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
101 102 103 104 105 |
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... |
106 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
107 108 109 110 |
nilfs_dat_commit_entry(dat, req); nilfs_palloc_commit_free_entry(dat, req); } |
a17564f58 nilfs2: disk addr... |
111 112 113 114 115 |
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... |
116 |
WARN_ON(ret == -ENOENT); |
a17564f58 nilfs2: disk addr... |
117 118 119 120 121 122 123 124 |
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... |
125 |
kaddr = kmap_atomic(req->pr_entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
126 127 128 |
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... |
129 |
entry->de_blocknr = cpu_to_le64(blocknr); |
7b9c0976a nilfs2: remove th... |
130 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
131 132 133 |
nilfs_dat_commit_entry(dat, req); } |
a17564f58 nilfs2: disk addr... |
134 135 136 |
int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req) { struct nilfs_dat_entry *entry; |
a17564f58 nilfs2: disk addr... |
137 138 139 140 141 142 |
sector_t blocknr; void *kaddr; int ret; ret = nilfs_dat_prepare_entry(dat, req, 0); if (ret < 0) { |
1f5abe7e7 nilfs2: replace B... |
143 |
WARN_ON(ret == -ENOENT); |
a17564f58 nilfs2: disk addr... |
144 145 |
return ret; } |
7b9c0976a nilfs2: remove th... |
146 |
kaddr = kmap_atomic(req->pr_entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
147 148 |
entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, req->pr_entry_bh, kaddr); |
a17564f58 nilfs2: disk addr... |
149 |
blocknr = le64_to_cpu(entry->de_blocknr); |
7b9c0976a nilfs2: remove th... |
150 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
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... |
170 |
kaddr = kmap_atomic(req->pr_entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
171 172 173 174 175 |
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... |
176 |
WARN_ON(start > end); |
a17564f58 nilfs2: disk addr... |
177 178 179 |
} entry->de_end = cpu_to_le64(end); blocknr = le64_to_cpu(entry->de_blocknr); |
7b9c0976a nilfs2: remove th... |
180 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
181 182 183 184 185 186 187 188 189 190 191 192 193 |
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... |
194 |
kaddr = kmap_atomic(req->pr_entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
195 196 197 198 |
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... |
199 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
200 201 202 203 204 |
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... |
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
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... |
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
/** * 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... |
271 |
* negative error codes is returned. |
a17564f58 nilfs2: disk addr... |
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
* * %-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... |
310 311 312 313 314 315 |
/* * 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 ... |
316 |
* uncommitted block number, this makes a copy of the entry |
c1c1d7092 nilfs2: get rid o... |
317 318 319 320 321 322 323 324 325 |
* 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... |
326 |
kaddr = kmap_atomic(entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
327 |
entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr); |
1f5abe7e7 nilfs2: replace B... |
328 |
if (unlikely(entry->de_blocknr == cpu_to_le64(0))) { |
a1d0747a3 nilfs2: use a mor... |
329 330 331 332 333 |
nilfs_crit(dat->i_sb, "%s: invalid vblocknr = %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... |
334 |
kunmap_atomic(kaddr); |
1f5abe7e7 nilfs2: replace B... |
335 336 |
brelse(entry_bh); return -EINVAL; |
a17564f58 nilfs2: disk addr... |
337 |
} |
1f5abe7e7 nilfs2: replace B... |
338 |
WARN_ON(blocknr == 0); |
a17564f58 nilfs2: disk addr... |
339 |
entry->de_blocknr = cpu_to_le64(blocknr); |
7b9c0976a nilfs2: remove th... |
340 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
341 |
|
5fc7b1417 nilfs2: use mark_... |
342 |
mark_buffer_dirty(entry_bh); |
a17564f58 nilfs2: disk addr... |
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
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... |
371 |
struct buffer_head *entry_bh, *bh; |
a17564f58 nilfs2: disk addr... |
372 373 374 375 376 377 378 379 |
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... |
380 381 382 383 384 385 386 387 |
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... |
388 |
kaddr = kmap_atomic(entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
389 390 391 392 393 394 |
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... |
395 |
*blocknrp = blocknr; |
a17564f58 nilfs2: disk addr... |
396 397 |
out: |
7b9c0976a nilfs2: remove th... |
398 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
399 400 401 |
brelse(entry_bh); return ret; } |
0c6c44cb9 nilfs2: avoid bar... |
402 |
ssize_t nilfs_dat_get_vinfo(struct inode *dat, void *buf, unsigned int visz, |
a17564f58 nilfs2: disk addr... |
403 404 405 406 |
size_t nvi) { struct buffer_head *entry_bh; struct nilfs_dat_entry *entry; |
003ff182f nilfs2: allow fut... |
407 |
struct nilfs_vinfo *vinfo = buf; |
a17564f58 nilfs2: disk addr... |
408 409 410 411 412 413 |
__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... |
414 |
ret = nilfs_palloc_get_entry_block(dat, vinfo->vi_vblocknr, |
a17564f58 nilfs2: disk addr... |
415 416 417 |
0, &entry_bh); if (ret < 0) return ret; |
7b9c0976a nilfs2: remove th... |
418 |
kaddr = kmap_atomic(entry_bh->b_page); |
a17564f58 nilfs2: disk addr... |
419 |
/* last virtual block number in this block */ |
003ff182f nilfs2: allow fut... |
420 |
first = vinfo->vi_vblocknr; |
a17564f58 nilfs2: disk addr... |
421 422 423 424 |
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... |
425 426 427 |
j < nvi && vinfo->vi_vblocknr >= first && vinfo->vi_vblocknr <= last; j++, n++, vinfo = (void *)vinfo + visz) { |
a17564f58 nilfs2: disk addr... |
428 |
entry = nilfs_palloc_block_get_entry( |
003ff182f nilfs2: allow fut... |
429 430 431 432 |
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... |
433 |
} |
7b9c0976a nilfs2: remove th... |
434 |
kunmap_atomic(kaddr); |
a17564f58 nilfs2: disk addr... |
435 436 437 438 439 |
brelse(entry_bh); } return nvi; } |
79739565e nilfs2: separate ... |
440 441 |
/** |
f1e89c86f nilfs2: use iget ... |
442 443 |
* nilfs_dat_read - read or get dat inode * @sb: super block instance |
79739565e nilfs2: separate ... |
444 |
* @entry_size: size of a dat entry |
f1e89c86f nilfs2: use iget ... |
445 446 |
* @raw_inode: on-disk dat inode * @inodep: buffer to store the inode |
79739565e nilfs2: separate ... |
447 |
*/ |
f1e89c86f nilfs2: use iget ... |
448 449 |
int nilfs_dat_read(struct super_block *sb, size_t entry_size, struct nilfs_inode *raw_inode, struct inode **inodep) |
79739565e nilfs2: separate ... |
450 451 452 |
{ static struct lock_class_key dat_lock_key; struct inode *dat; |
8908b2f70 nilfs2: add pallo... |
453 |
struct nilfs_dat_info *di; |
79739565e nilfs2: separate ... |
454 |
int err; |
0ec060d18 nilfs2: verify me... |
455 |
if (entry_size > sb->s_blocksize) { |
a1d0747a3 nilfs2: use a mor... |
456 |
nilfs_err(sb, "too large DAT entry size: %zu bytes", |
feee880fa nilfs2: reduce ba... |
457 |
entry_size); |
0ec060d18 nilfs2: verify me... |
458 459 |
return -EINVAL; } else if (entry_size < NILFS_MIN_DAT_ENTRY_SIZE) { |
a1d0747a3 nilfs2: use a mor... |
460 |
nilfs_err(sb, "too small DAT entry size: %zu bytes", |
feee880fa nilfs2: reduce ba... |
461 |
entry_size); |
0ec060d18 nilfs2: verify me... |
462 463 |
return -EINVAL; } |
f1e89c86f nilfs2: use iget ... |
464 465 466 467 468 |
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... |
469 |
|
f1e89c86f nilfs2: use iget ... |
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
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 ... |
494 |
} |