datastream.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. /*
  2. * linux/fs/befs/datastream.c
  3. *
  4. * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com>
  5. *
  6. * Based on portions of file.c by Makoto Kato <m_kato@ga2.so-net.ne.jp>
  7. *
  8. * Many thanks to Dominic Giampaolo, author of "Practical File System
  9. * Design with the Be File System", for such a helpful book.
  10. *
  11. */
  12. #include <linux/kernel.h>
  13. #include <linux/buffer_head.h>
  14. #include <linux/string.h>
  15. #include "befs.h"
  16. #include "datastream.h"
  17. #include "io.h"
  18. const befs_inode_addr BAD_IADDR = { 0, 0, 0 };
  19. static int befs_find_brun_direct(struct super_block *sb,
  20. const befs_data_stream *data,
  21. befs_blocknr_t blockno, befs_block_run *run);
  22. static int befs_find_brun_indirect(struct super_block *sb,
  23. const befs_data_stream *data,
  24. befs_blocknr_t blockno,
  25. befs_block_run *run);
  26. static int befs_find_brun_dblindirect(struct super_block *sb,
  27. const befs_data_stream *data,
  28. befs_blocknr_t blockno,
  29. befs_block_run *run);
  30. /**
  31. * befs_read_datastream - get buffer_head containing data, starting from pos.
  32. * @sb: Filesystem superblock
  33. * @ds: datastream to find data with
  34. * @pos: start of data
  35. * @off: offset of data in buffer_head->b_data
  36. *
  37. * Returns pointer to buffer_head containing data starting with offset @off,
  38. * if you don't need to know offset just set @off = NULL.
  39. */
  40. struct buffer_head *
  41. befs_read_datastream(struct super_block *sb, const befs_data_stream *ds,
  42. befs_off_t pos, uint *off)
  43. {
  44. struct buffer_head *bh;
  45. befs_block_run run;
  46. befs_blocknr_t block; /* block coresponding to pos */
  47. befs_debug(sb, "---> %s %llu", __func__, pos);
  48. block = pos >> BEFS_SB(sb)->block_shift;
  49. if (off)
  50. *off = pos - (block << BEFS_SB(sb)->block_shift);
  51. if (befs_fblock2brun(sb, ds, block, &run) != BEFS_OK) {
  52. befs_error(sb, "BeFS: Error finding disk addr of block %lu",
  53. (unsigned long)block);
  54. befs_debug(sb, "<--- %s ERROR", __func__);
  55. return NULL;
  56. }
  57. bh = befs_bread_iaddr(sb, run);
  58. if (!bh) {
  59. befs_error(sb, "BeFS: Error reading block %lu from datastream",
  60. (unsigned long)block);
  61. return NULL;
  62. }
  63. befs_debug(sb, "<--- %s read data, starting at %llu", __func__, pos);
  64. return bh;
  65. }
  66. /**
  67. * befs_fblock2brun - give back block run for fblock
  68. * @sb: the superblock
  69. * @data: datastream to read from
  70. * @fblock: the blocknumber with the file position to find
  71. * @run: The found run is passed back through this pointer
  72. *
  73. * Takes a file position and gives back a brun who's starting block
  74. * is block number fblock of the file.
  75. *
  76. * Returns BEFS_OK or BEFS_ERR.
  77. *
  78. * Calls specialized functions for each of the three possible
  79. * datastream regions.
  80. */
  81. int
  82. befs_fblock2brun(struct super_block *sb, const befs_data_stream *data,
  83. befs_blocknr_t fblock, befs_block_run *run)
  84. {
  85. int err;
  86. befs_off_t pos = fblock << BEFS_SB(sb)->block_shift;
  87. if (pos < data->max_direct_range) {
  88. err = befs_find_brun_direct(sb, data, fblock, run);
  89. } else if (pos < data->max_indirect_range) {
  90. err = befs_find_brun_indirect(sb, data, fblock, run);
  91. } else if (pos < data->max_double_indirect_range) {
  92. err = befs_find_brun_dblindirect(sb, data, fblock, run);
  93. } else {
  94. befs_error(sb,
  95. "befs_fblock2brun() was asked to find block %lu, "
  96. "which is not mapped by the datastream\n",
  97. (unsigned long)fblock);
  98. err = BEFS_ERR;
  99. }
  100. return err;
  101. }
  102. /**
  103. * befs_read_lsmylink - read long symlink from datastream.
  104. * @sb: Filesystem superblock
  105. * @ds: Datastream to read from
  106. * @buff: Buffer in which to place long symlink data
  107. * @len: Length of the long symlink in bytes
  108. *
  109. * Returns the number of bytes read
  110. */
  111. size_t
  112. befs_read_lsymlink(struct super_block *sb, const befs_data_stream *ds,
  113. void *buff, befs_off_t len)
  114. {
  115. befs_off_t bytes_read = 0; /* bytes readed */
  116. u16 plen;
  117. struct buffer_head *bh;
  118. befs_debug(sb, "---> %s length: %llu", __func__, len);
  119. while (bytes_read < len) {
  120. bh = befs_read_datastream(sb, ds, bytes_read, NULL);
  121. if (!bh) {
  122. befs_error(sb, "BeFS: Error reading datastream block "
  123. "starting from %llu", bytes_read);
  124. befs_debug(sb, "<--- %s ERROR", __func__);
  125. return bytes_read;
  126. }
  127. plen = ((bytes_read + BEFS_SB(sb)->block_size) < len) ?
  128. BEFS_SB(sb)->block_size : len - bytes_read;
  129. memcpy(buff + bytes_read, bh->b_data, plen);
  130. brelse(bh);
  131. bytes_read += plen;
  132. }
  133. befs_debug(sb, "<--- %s read %u bytes", __func__, (unsigned int)
  134. bytes_read);
  135. return bytes_read;
  136. }
  137. /**
  138. * befs_count_blocks - blocks used by a file
  139. * @sb: Filesystem superblock
  140. * @ds: Datastream of the file
  141. *
  142. * Counts the number of fs blocks that the file represented by
  143. * inode occupies on the filesystem, counting both regular file
  144. * data and filesystem metadata (and eventually attribute data
  145. * when we support attributes)
  146. */
  147. befs_blocknr_t
  148. befs_count_blocks(struct super_block *sb, const befs_data_stream *ds)
  149. {
  150. befs_blocknr_t blocks;
  151. befs_blocknr_t datablocks; /* File data blocks */
  152. befs_blocknr_t metablocks; /* FS metadata blocks */
  153. struct befs_sb_info *befs_sb = BEFS_SB(sb);
  154. befs_debug(sb, "---> %s", __func__);
  155. datablocks = ds->size >> befs_sb->block_shift;
  156. if (ds->size & (befs_sb->block_size - 1))
  157. datablocks += 1;
  158. metablocks = 1; /* Start with 1 block for inode */
  159. /* Size of indirect block */
  160. if (ds->size > ds->max_direct_range)
  161. metablocks += ds->indirect.len;
  162. /*
  163. * Double indir block, plus all the indirect blocks it maps.
  164. * In the double-indirect range, all block runs of data are
  165. * BEFS_DBLINDIR_BRUN_LEN blocks long. Therefore, we know
  166. * how many data block runs are in the double-indirect region,
  167. * and from that we know how many indirect blocks it takes to
  168. * map them. We assume that the indirect blocks are also
  169. * BEFS_DBLINDIR_BRUN_LEN blocks long.
  170. */
  171. if (ds->size > ds->max_indirect_range && ds->max_indirect_range != 0) {
  172. uint dbl_bytes;
  173. uint dbl_bruns;
  174. uint indirblocks;
  175. dbl_bytes =
  176. ds->max_double_indirect_range - ds->max_indirect_range;
  177. dbl_bruns =
  178. dbl_bytes / (befs_sb->block_size * BEFS_DBLINDIR_BRUN_LEN);
  179. indirblocks = dbl_bruns / befs_iaddrs_per_block(sb);
  180. metablocks += ds->double_indirect.len;
  181. metablocks += indirblocks;
  182. }
  183. blocks = datablocks + metablocks;
  184. befs_debug(sb, "<--- %s %u blocks", __func__, (unsigned int)blocks);
  185. return blocks;
  186. }
  187. /**
  188. * befs_find_brun_direct - find a direct block run in the datastream
  189. * @sb: the superblock
  190. * @data: the datastream
  191. * @blockno: the blocknumber to find
  192. * @run: The found run is passed back through this pointer
  193. *
  194. * Finds the block run that starts at file block number blockno
  195. * in the file represented by the datastream data, if that
  196. * blockno is in the direct region of the datastream.
  197. *
  198. * Return value is BEFS_OK if the blockrun is found, BEFS_ERR
  199. * otherwise.
  200. *
  201. * Algorithm:
  202. * Linear search. Checks each element of array[] to see if it
  203. * contains the blockno-th filesystem block. This is necessary
  204. * because the block runs map variable amounts of data. Simply
  205. * keeps a count of the number of blocks searched so far (sum),
  206. * incrementing this by the length of each block run as we come
  207. * across it. Adds sum to *count before returning (this is so
  208. * you can search multiple arrays that are logicaly one array,
  209. * as in the indirect region code).
  210. *
  211. * When/if blockno is found, if blockno is inside of a block
  212. * run as stored on disk, we offset the start and length members
  213. * of the block run, so that blockno is the start and len is
  214. * still valid (the run ends in the same place).
  215. */
  216. static int
  217. befs_find_brun_direct(struct super_block *sb, const befs_data_stream *data,
  218. befs_blocknr_t blockno, befs_block_run *run)
  219. {
  220. int i;
  221. const befs_block_run *array = data->direct;
  222. befs_blocknr_t sum;
  223. befs_debug(sb, "---> %s, find %lu", __func__, (unsigned long)blockno);
  224. for (i = 0, sum = 0; i < BEFS_NUM_DIRECT_BLOCKS;
  225. sum += array[i].len, i++) {
  226. if (blockno >= sum && blockno < sum + (array[i].len)) {
  227. int offset = blockno - sum;
  228. run->allocation_group = array[i].allocation_group;
  229. run->start = array[i].start + offset;
  230. run->len = array[i].len - offset;
  231. befs_debug(sb, "---> %s, "
  232. "found %lu at direct[%d]", __func__,
  233. (unsigned long)blockno, i);
  234. return BEFS_OK;
  235. }
  236. }
  237. befs_error(sb, "%s failed to find file block %lu", __func__,
  238. (unsigned long)blockno);
  239. befs_debug(sb, "---> %s ERROR", __func__);
  240. return BEFS_ERR;
  241. }
  242. /**
  243. * befs_find_brun_indirect - find a block run in the datastream
  244. * @sb: the superblock
  245. * @data: the datastream
  246. * @blockno: the blocknumber to find
  247. * @run: The found run is passed back through this pointer
  248. *
  249. * Finds the block run that starts at file block number blockno
  250. * in the file represented by the datastream data, if that
  251. * blockno is in the indirect region of the datastream.
  252. *
  253. * Return value is BEFS_OK if the blockrun is found, BEFS_ERR
  254. * otherwise.
  255. *
  256. * Algorithm:
  257. * For each block in the indirect run of the datastream, read
  258. * it in and search through it for search_blk.
  259. *
  260. * XXX:
  261. * Really should check to make sure blockno is inside indirect
  262. * region.
  263. */
  264. static int
  265. befs_find_brun_indirect(struct super_block *sb,
  266. const befs_data_stream *data,
  267. befs_blocknr_t blockno,
  268. befs_block_run *run)
  269. {
  270. int i, j;
  271. befs_blocknr_t sum = 0;
  272. befs_blocknr_t indir_start_blk;
  273. befs_blocknr_t search_blk;
  274. struct buffer_head *indirblock;
  275. befs_disk_block_run *array;
  276. befs_block_run indirect = data->indirect;
  277. befs_blocknr_t indirblockno = iaddr2blockno(sb, &indirect);
  278. int arraylen = befs_iaddrs_per_block(sb);
  279. befs_debug(sb, "---> %s, find %lu", __func__, (unsigned long)blockno);
  280. indir_start_blk = data->max_direct_range >> BEFS_SB(sb)->block_shift;
  281. search_blk = blockno - indir_start_blk;
  282. /* Examine blocks of the indirect run one at a time */
  283. for (i = 0; i < indirect.len; i++) {
  284. indirblock = sb_bread(sb, indirblockno + i);
  285. if (indirblock == NULL) {
  286. befs_error(sb, "---> %s failed to read "
  287. "disk block %lu from the indirect brun",
  288. __func__, (unsigned long)indirblockno + i);
  289. befs_debug(sb, "<--- %s ERROR", __func__);
  290. return BEFS_ERR;
  291. }
  292. array = (befs_disk_block_run *) indirblock->b_data;
  293. for (j = 0; j < arraylen; ++j) {
  294. int len = fs16_to_cpu(sb, array[j].len);
  295. if (search_blk >= sum && search_blk < sum + len) {
  296. int offset = search_blk - sum;
  297. run->allocation_group =
  298. fs32_to_cpu(sb, array[j].allocation_group);
  299. run->start =
  300. fs16_to_cpu(sb, array[j].start) + offset;
  301. run->len =
  302. fs16_to_cpu(sb, array[j].len) - offset;
  303. brelse(indirblock);
  304. befs_debug(sb,
  305. "<--- %s found file block "
  306. "%lu at indirect[%d]", __func__,
  307. (unsigned long)blockno,
  308. j + (i * arraylen));
  309. return BEFS_OK;
  310. }
  311. sum += len;
  312. }
  313. brelse(indirblock);
  314. }
  315. /* Only fallthrough is an error */
  316. befs_error(sb, "BeFS: %s failed to find "
  317. "file block %lu", __func__, (unsigned long)blockno);
  318. befs_debug(sb, "<--- %s ERROR", __func__);
  319. return BEFS_ERR;
  320. }
  321. /**
  322. * befs_find_brun_dblindirect - find a block run in the datastream
  323. * @sb: the superblock
  324. * @data: the datastream
  325. * @blockno: the blocknumber to find
  326. * @run: The found run is passed back through this pointer
  327. *
  328. * Finds the block run that starts at file block number blockno
  329. * in the file represented by the datastream data, if that
  330. * blockno is in the double-indirect region of the datastream.
  331. *
  332. * Return value is BEFS_OK if the blockrun is found, BEFS_ERR
  333. * otherwise.
  334. *
  335. * Algorithm:
  336. * The block runs in the double-indirect region are different.
  337. * They are always allocated 4 fs blocks at a time, so each
  338. * block run maps a constant amount of file data. This means
  339. * that we can directly calculate how many block runs into the
  340. * double-indirect region we need to go to get to the one that
  341. * maps a particular filesystem block.
  342. *
  343. * We do this in two stages. First we calculate which of the
  344. * inode addresses in the double-indirect block will point us
  345. * to the indirect block that contains the mapping for the data,
  346. * then we calculate which of the inode addresses in that
  347. * indirect block maps the data block we are after.
  348. *
  349. * Oh, and once we've done that, we actually read in the blocks
  350. * that contain the inode addresses we calculated above. Even
  351. * though the double-indirect run may be several blocks long,
  352. * we can calculate which of those blocks will contain the index
  353. * we are after and only read that one. We then follow it to
  354. * the indirect block and perform a similar process to find
  355. * the actual block run that maps the data block we are interested
  356. * in.
  357. *
  358. * Then we offset the run as in befs_find_brun_array() and we are
  359. * done.
  360. */
  361. static int
  362. befs_find_brun_dblindirect(struct super_block *sb,
  363. const befs_data_stream *data,
  364. befs_blocknr_t blockno,
  365. befs_block_run *run)
  366. {
  367. int dblindir_indx;
  368. int indir_indx;
  369. int offset;
  370. int dbl_which_block;
  371. int which_block;
  372. int dbl_block_indx;
  373. int block_indx;
  374. off_t dblindir_leftover;
  375. befs_blocknr_t blockno_at_run_start;
  376. struct buffer_head *dbl_indir_block;
  377. struct buffer_head *indir_block;
  378. befs_block_run indir_run;
  379. befs_disk_inode_addr *iaddr_array;
  380. befs_blocknr_t indir_start_blk =
  381. data->max_indirect_range >> BEFS_SB(sb)->block_shift;
  382. off_t dbl_indir_off = blockno - indir_start_blk;
  383. /* number of data blocks mapped by each of the iaddrs in
  384. * the indirect block pointed to by the double indirect block
  385. */
  386. size_t iblklen = BEFS_DBLINDIR_BRUN_LEN;
  387. /* number of data blocks mapped by each of the iaddrs in
  388. * the double indirect block
  389. */
  390. size_t diblklen = iblklen * befs_iaddrs_per_block(sb)
  391. * BEFS_DBLINDIR_BRUN_LEN;
  392. befs_debug(sb, "---> %s find %lu", __func__, (unsigned long)blockno);
  393. /* First, discover which of the double_indir->indir blocks
  394. * contains pos. Then figure out how much of pos that
  395. * accounted for. Then discover which of the iaddrs in
  396. * the indirect block contains pos.
  397. */
  398. dblindir_indx = dbl_indir_off / diblklen;
  399. dblindir_leftover = dbl_indir_off % diblklen;
  400. indir_indx = dblindir_leftover / diblklen;
  401. /* Read double indirect block */
  402. dbl_which_block = dblindir_indx / befs_iaddrs_per_block(sb);
  403. if (dbl_which_block > data->double_indirect.len) {
  404. befs_error(sb, "The double-indirect index calculated by "
  405. "%s, %d, is outside the range "
  406. "of the double-indirect block", __func__,
  407. dblindir_indx);
  408. return BEFS_ERR;
  409. }
  410. dbl_indir_block =
  411. sb_bread(sb, iaddr2blockno(sb, &data->double_indirect) +
  412. dbl_which_block);
  413. if (dbl_indir_block == NULL) {
  414. befs_error(sb, "%s couldn't read the "
  415. "double-indirect block at blockno %lu", __func__,
  416. (unsigned long)
  417. iaddr2blockno(sb, &data->double_indirect) +
  418. dbl_which_block);
  419. return BEFS_ERR;
  420. }
  421. dbl_block_indx =
  422. dblindir_indx - (dbl_which_block * befs_iaddrs_per_block(sb));
  423. iaddr_array = (befs_disk_inode_addr *) dbl_indir_block->b_data;
  424. indir_run = fsrun_to_cpu(sb, iaddr_array[dbl_block_indx]);
  425. brelse(dbl_indir_block);
  426. /* Read indirect block */
  427. which_block = indir_indx / befs_iaddrs_per_block(sb);
  428. if (which_block > indir_run.len) {
  429. befs_error(sb, "The indirect index calculated by "
  430. "%s, %d, is outside the range "
  431. "of the indirect block", __func__, indir_indx);
  432. return BEFS_ERR;
  433. }
  434. indir_block =
  435. sb_bread(sb, iaddr2blockno(sb, &indir_run) + which_block);
  436. if (indir_block == NULL) {
  437. befs_error(sb, "%s couldn't read the indirect block "
  438. "at blockno %lu", __func__, (unsigned long)
  439. iaddr2blockno(sb, &indir_run) + which_block);
  440. return BEFS_ERR;
  441. }
  442. block_indx = indir_indx - (which_block * befs_iaddrs_per_block(sb));
  443. iaddr_array = (befs_disk_inode_addr *) indir_block->b_data;
  444. *run = fsrun_to_cpu(sb, iaddr_array[block_indx]);
  445. brelse(indir_block);
  446. blockno_at_run_start = indir_start_blk;
  447. blockno_at_run_start += diblklen * dblindir_indx;
  448. blockno_at_run_start += iblklen * indir_indx;
  449. offset = blockno - blockno_at_run_start;
  450. run->start += offset;
  451. run->len -= offset;
  452. befs_debug(sb, "Found file block %lu in double_indirect[%d][%d],"
  453. " double_indirect_leftover = %lu", (unsigned long)
  454. blockno, dblindir_indx, indir_indx, dblindir_leftover);
  455. return BEFS_OK;
  456. }