blob: 740fabcd57c0a6a47fdda8f3a74c4b328d6021a9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
13#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/buffer_head.h>
15#include <linux/string.h>
16
17#include "befs.h"
18#include "datastream.h"
19#include "io.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
21const befs_inode_addr BAD_IADDR = { 0, 0, 0 };
22
23static int befs_find_brun_direct(struct super_block *sb,
Al Viro22341d82016-05-10 14:24:06 -040024 const befs_data_stream *data,
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 befs_blocknr_t blockno, befs_block_run * run);
26
27static int befs_find_brun_indirect(struct super_block *sb,
Al Viro22341d82016-05-10 14:24:06 -040028 const befs_data_stream *data,
Linus Torvalds1da177e2005-04-16 15:20:36 -070029 befs_blocknr_t blockno,
30 befs_block_run * run);
31
32static int befs_find_brun_dblindirect(struct super_block *sb,
Al Viro22341d82016-05-10 14:24:06 -040033 const befs_data_stream *data,
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 befs_blocknr_t blockno,
35 befs_block_run * run);
36
37/**
38 * befs_read_datastream - get buffer_head containing data, starting from pos.
39 * @sb: Filesystem superblock
40 * @ds: datastrem to find data with
41 * @pos: start of data
42 * @off: offset of data in buffer_head->b_data
43 *
44 * Returns pointer to buffer_head containing data starting with offset @off,
45 * if you don't need to know offset just set @off = NULL.
46 */
47struct buffer_head *
Al Viro22341d82016-05-10 14:24:06 -040048befs_read_datastream(struct super_block *sb, const befs_data_stream *ds,
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 befs_off_t pos, uint * off)
50{
Salah Trikiff2fe0a2016-05-23 16:22:32 -070051 struct buffer_head *bh;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 befs_block_run run;
53 befs_blocknr_t block; /* block coresponding to pos */
54
Fabian Frederickdac52fc2014-04-03 14:50:23 -070055 befs_debug(sb, "---> %s %llu", __func__, pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 block = pos >> BEFS_SB(sb)->block_shift;
57 if (off)
58 *off = pos - (block << BEFS_SB(sb)->block_shift);
59
60 if (befs_fblock2brun(sb, ds, block, &run) != BEFS_OK) {
61 befs_error(sb, "BeFS: Error finding disk addr of block %lu",
Fabian Frederickdac52fc2014-04-03 14:50:23 -070062 (unsigned long)block);
63 befs_debug(sb, "<--- %s ERROR", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 return NULL;
65 }
66 bh = befs_bread_iaddr(sb, run);
67 if (!bh) {
68 befs_error(sb, "BeFS: Error reading block %lu from datastream",
Fabian Frederickdac52fc2014-04-03 14:50:23 -070069 (unsigned long)block);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 return NULL;
71 }
72
Fabian Frederickdac52fc2014-04-03 14:50:23 -070073 befs_debug(sb, "<--- %s read data, starting at %llu", __func__, pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
75 return bh;
76}
77
78/*
79 * Takes a file position and gives back a brun who's starting block
80 * is block number fblock of the file.
81 *
82 * Returns BEFS_OK or BEFS_ERR.
83 *
84 * Calls specialized functions for each of the three possible
85 * datastream regions.
86 *
87 * 2001-11-15 Will Dyson
88 */
89int
Al Viro22341d82016-05-10 14:24:06 -040090befs_fblock2brun(struct super_block *sb, const befs_data_stream *data,
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 befs_blocknr_t fblock, befs_block_run * run)
92{
93 int err;
94 befs_off_t pos = fblock << BEFS_SB(sb)->block_shift;
95
96 if (pos < data->max_direct_range) {
97 err = befs_find_brun_direct(sb, data, fblock, run);
98
99 } else if (pos < data->max_indirect_range) {
100 err = befs_find_brun_indirect(sb, data, fblock, run);
101
102 } else if (pos < data->max_double_indirect_range) {
103 err = befs_find_brun_dblindirect(sb, data, fblock, run);
104
105 } else {
106 befs_error(sb,
107 "befs_fblock2brun() was asked to find block %lu, "
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700108 "which is not mapped by the datastream\n",
109 (unsigned long)fblock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 err = BEFS_ERR;
111 }
112 return err;
113}
114
115/**
116 * befs_read_lsmylink - read long symlink from datastream.
117 * @sb: Filesystem superblock
118 * @ds: Datastrem to read from
Fabian Frederick817e1d92014-06-06 14:36:17 -0700119 * @buff: Buffer in which to place long symlink data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 * @len: Length of the long symlink in bytes
121 *
122 * Returns the number of bytes read
123 */
124size_t
Al Viro22341d82016-05-10 14:24:06 -0400125befs_read_lsymlink(struct super_block *sb, const befs_data_stream *ds,
126 void *buff, befs_off_t len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127{
128 befs_off_t bytes_read = 0; /* bytes readed */
129 u16 plen;
Salah Triki3080ea92016-05-23 16:22:35 -0700130 struct buffer_head *bh;
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700131 befs_debug(sb, "---> %s length: %llu", __func__, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
133 while (bytes_read < len) {
134 bh = befs_read_datastream(sb, ds, bytes_read, NULL);
135 if (!bh) {
136 befs_error(sb, "BeFS: Error reading datastream block "
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700137 "starting from %llu", bytes_read);
138 befs_debug(sb, "<--- %s ERROR", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 return bytes_read;
140
141 }
142 plen = ((bytes_read + BEFS_SB(sb)->block_size) < len) ?
143 BEFS_SB(sb)->block_size : len - bytes_read;
144 memcpy(buff + bytes_read, bh->b_data, plen);
145 brelse(bh);
146 bytes_read += plen;
147 }
148
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700149 befs_debug(sb, "<--- %s read %u bytes", __func__, (unsigned int)
150 bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 return bytes_read;
152}
153
154/**
155 * befs_count_blocks - blocks used by a file
156 * @sb: Filesystem superblock
157 * @ds: Datastream of the file
158 *
159 * Counts the number of fs blocks that the file represented by
160 * inode occupies on the filesystem, counting both regular file
161 * data and filesystem metadata (and eventually attribute data
162 * when we support attributes)
163*/
164
165befs_blocknr_t
Al Viro22341d82016-05-10 14:24:06 -0400166befs_count_blocks(struct super_block *sb, const befs_data_stream *ds)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167{
168 befs_blocknr_t blocks;
169 befs_blocknr_t datablocks; /* File data blocks */
170 befs_blocknr_t metablocks; /* FS metadata blocks */
Fabian Frederick038428f2015-04-16 12:46:20 -0700171 struct befs_sb_info *befs_sb = BEFS_SB(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700173 befs_debug(sb, "---> %s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
175 datablocks = ds->size >> befs_sb->block_shift;
176 if (ds->size & (befs_sb->block_size - 1))
177 datablocks += 1;
178
179 metablocks = 1; /* Start with 1 block for inode */
180
181 /* Size of indirect block */
182 if (ds->size > ds->max_direct_range)
183 metablocks += ds->indirect.len;
184
185 /*
186 Double indir block, plus all the indirect blocks it mapps
187 In the double-indirect range, all block runs of data are
188 BEFS_DBLINDIR_BRUN_LEN blocks long. Therefore, we know
189 how many data block runs are in the double-indirect region,
190 and from that we know how many indirect blocks it takes to
191 map them. We assume that the indirect blocks are also
192 BEFS_DBLINDIR_BRUN_LEN blocks long.
193 */
194 if (ds->size > ds->max_indirect_range && ds->max_indirect_range != 0) {
195 uint dbl_bytes;
196 uint dbl_bruns;
197 uint indirblocks;
198
199 dbl_bytes =
200 ds->max_double_indirect_range - ds->max_indirect_range;
201 dbl_bruns =
202 dbl_bytes / (befs_sb->block_size * BEFS_DBLINDIR_BRUN_LEN);
203 indirblocks = dbl_bruns / befs_iaddrs_per_block(sb);
204
205 metablocks += ds->double_indirect.len;
206 metablocks += indirblocks;
207 }
208
209 blocks = datablocks + metablocks;
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700210 befs_debug(sb, "<--- %s %u blocks", __func__, (unsigned int)blocks);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
212 return blocks;
213}
214
215/*
216 Finds the block run that starts at file block number blockno
217 in the file represented by the datastream data, if that
218 blockno is in the direct region of the datastream.
219
220 sb: the superblock
221 data: the datastream
222 blockno: the blocknumber to find
223 run: The found run is passed back through this pointer
224
225 Return value is BEFS_OK if the blockrun is found, BEFS_ERR
226 otherwise.
227
228 Algorithm:
229 Linear search. Checks each element of array[] to see if it
230 contains the blockno-th filesystem block. This is necessary
231 because the block runs map variable amounts of data. Simply
232 keeps a count of the number of blocks searched so far (sum),
233 incrementing this by the length of each block run as we come
234 across it. Adds sum to *count before returning (this is so
235 you can search multiple arrays that are logicaly one array,
236 as in the indirect region code).
237
238 When/if blockno is found, if blockno is inside of a block
Paulius Zaleckasefad798b2008-02-03 15:42:53 +0200239 run as stored on disk, we offset the start and length members
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 of the block run, so that blockno is the start and len is
241 still valid (the run ends in the same place).
242
243 2001-11-15 Will Dyson
244*/
245static int
Al Viro22341d82016-05-10 14:24:06 -0400246befs_find_brun_direct(struct super_block *sb, const befs_data_stream *data,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 befs_blocknr_t blockno, befs_block_run * run)
248{
249 int i;
Al Viro22341d82016-05-10 14:24:06 -0400250 const befs_block_run *array = data->direct;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 befs_blocknr_t sum;
252 befs_blocknr_t max_block =
253 data->max_direct_range >> BEFS_SB(sb)->block_shift;
254
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700255 befs_debug(sb, "---> %s, find %lu", __func__, (unsigned long)blockno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
257 if (blockno > max_block) {
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700258 befs_error(sb, "%s passed block outside of direct region",
259 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 return BEFS_ERR;
261 }
262
263 for (i = 0, sum = 0; i < BEFS_NUM_DIRECT_BLOCKS;
264 sum += array[i].len, i++) {
265 if (blockno >= sum && blockno < sum + (array[i].len)) {
266 int offset = blockno - sum;
267 run->allocation_group = array[i].allocation_group;
268 run->start = array[i].start + offset;
269 run->len = array[i].len - offset;
270
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700271 befs_debug(sb, "---> %s, "
272 "found %lu at direct[%d]", __func__,
273 (unsigned long)blockno, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 return BEFS_OK;
275 }
276 }
277
Luis de Bethencourt4c3897c2016-07-03 16:29:44 +0100278 befs_error(sb, "%s failed to find file block %lu", __func__,
279 (unsigned long)blockno);
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700280 befs_debug(sb, "---> %s ERROR", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 return BEFS_ERR;
282}
283
284/*
285 Finds the block run that starts at file block number blockno
286 in the file represented by the datastream data, if that
287 blockno is in the indirect region of the datastream.
288
289 sb: the superblock
290 data: the datastream
291 blockno: the blocknumber to find
292 run: The found run is passed back through this pointer
293
294 Return value is BEFS_OK if the blockrun is found, BEFS_ERR
295 otherwise.
296
297 Algorithm:
298 For each block in the indirect run of the datastream, read
299 it in and search through it for search_blk.
300
301 XXX:
302 Really should check to make sure blockno is inside indirect
303 region.
304
305 2001-11-15 Will Dyson
306*/
307static int
308befs_find_brun_indirect(struct super_block *sb,
Al Viro22341d82016-05-10 14:24:06 -0400309 const befs_data_stream *data,
310 befs_blocknr_t blockno,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 befs_block_run * run)
312{
313 int i, j;
314 befs_blocknr_t sum = 0;
315 befs_blocknr_t indir_start_blk;
316 befs_blocknr_t search_blk;
317 struct buffer_head *indirblock;
Al Viroa9721f32005-12-24 14:28:55 -0500318 befs_disk_block_run *array;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
320 befs_block_run indirect = data->indirect;
321 befs_blocknr_t indirblockno = iaddr2blockno(sb, &indirect);
322 int arraylen = befs_iaddrs_per_block(sb);
323
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700324 befs_debug(sb, "---> %s, find %lu", __func__, (unsigned long)blockno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 indir_start_blk = data->max_direct_range >> BEFS_SB(sb)->block_shift;
327 search_blk = blockno - indir_start_blk;
328
329 /* Examine blocks of the indirect run one at a time */
330 for (i = 0; i < indirect.len; i++) {
Salah Trikif7f67542016-07-23 22:36:42 +1000331 indirblock = sb_bread(sb, indirblockno + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 if (indirblock == NULL) {
Luis de Bethencourt4c3897c2016-07-03 16:29:44 +0100333 befs_error(sb, "---> %s failed to read "
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700334 "disk block %lu from the indirect brun",
335 __func__, (unsigned long)indirblockno + i);
Luis de Bethencourt4c3897c2016-07-03 16:29:44 +0100336 befs_debug(sb, "<--- %s ERROR", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 return BEFS_ERR;
338 }
339
Al Viroa9721f32005-12-24 14:28:55 -0500340 array = (befs_disk_block_run *) indirblock->b_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
342 for (j = 0; j < arraylen; ++j) {
343 int len = fs16_to_cpu(sb, array[j].len);
344
345 if (search_blk >= sum && search_blk < sum + len) {
346 int offset = search_blk - sum;
347 run->allocation_group =
348 fs32_to_cpu(sb, array[j].allocation_group);
349 run->start =
350 fs16_to_cpu(sb, array[j].start) + offset;
351 run->len =
352 fs16_to_cpu(sb, array[j].len) - offset;
353
354 brelse(indirblock);
355 befs_debug(sb,
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700356 "<--- %s found file block "
357 "%lu at indirect[%d]", __func__,
358 (unsigned long)blockno,
359 j + (i * arraylen));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 return BEFS_OK;
361 }
362 sum += len;
363 }
364
365 brelse(indirblock);
366 }
367
368 /* Only fallthrough is an error */
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700369 befs_error(sb, "BeFS: %s failed to find "
370 "file block %lu", __func__, (unsigned long)blockno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700372 befs_debug(sb, "<--- %s ERROR", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 return BEFS_ERR;
374}
375
376/*
377 Finds the block run that starts at file block number blockno
378 in the file represented by the datastream data, if that
379 blockno is in the double-indirect region of the datastream.
380
381 sb: the superblock
382 data: the datastream
383 blockno: the blocknumber to find
384 run: The found run is passed back through this pointer
385
386 Return value is BEFS_OK if the blockrun is found, BEFS_ERR
387 otherwise.
388
389 Algorithm:
390 The block runs in the double-indirect region are different.
391 They are always allocated 4 fs blocks at a time, so each
392 block run maps a constant amount of file data. This means
393 that we can directly calculate how many block runs into the
394 double-indirect region we need to go to get to the one that
395 maps a particular filesystem block.
396
397 We do this in two stages. First we calculate which of the
398 inode addresses in the double-indirect block will point us
399 to the indirect block that contains the mapping for the data,
400 then we calculate which of the inode addresses in that
401 indirect block maps the data block we are after.
402
403 Oh, and once we've done that, we actually read in the blocks
404 that contain the inode addresses we calculated above. Even
405 though the double-indirect run may be several blocks long,
406 we can calculate which of those blocks will contain the index
407 we are after and only read that one. We then follow it to
408 the indirect block and perform a similar process to find
409 the actual block run that maps the data block we are interested
410 in.
411
412 Then we offset the run as in befs_find_brun_array() and we are
413 done.
414
415 2001-11-15 Will Dyson
416*/
417static int
418befs_find_brun_dblindirect(struct super_block *sb,
Al Viro22341d82016-05-10 14:24:06 -0400419 const befs_data_stream *data,
420 befs_blocknr_t blockno,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 befs_block_run * run)
422{
423 int dblindir_indx;
424 int indir_indx;
425 int offset;
426 int dbl_which_block;
427 int which_block;
428 int dbl_block_indx;
429 int block_indx;
430 off_t dblindir_leftover;
431 befs_blocknr_t blockno_at_run_start;
432 struct buffer_head *dbl_indir_block;
433 struct buffer_head *indir_block;
434 befs_block_run indir_run;
Salah Triki6c8da242016-05-23 16:22:38 -0700435 befs_disk_inode_addr *iaddr_array;
Fabian Frederick038428f2015-04-16 12:46:20 -0700436 struct befs_sb_info *befs_sb = BEFS_SB(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
438 befs_blocknr_t indir_start_blk =
439 data->max_indirect_range >> befs_sb->block_shift;
440
441 off_t dbl_indir_off = blockno - indir_start_blk;
442
443 /* number of data blocks mapped by each of the iaddrs in
444 * the indirect block pointed to by the double indirect block
445 */
446 size_t iblklen = BEFS_DBLINDIR_BRUN_LEN;
447
448 /* number of data blocks mapped by each of the iaddrs in
449 * the double indirect block
450 */
451 size_t diblklen = iblklen * befs_iaddrs_per_block(sb)
452 * BEFS_DBLINDIR_BRUN_LEN;
453
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700454 befs_debug(sb, "---> %s find %lu", __func__, (unsigned long)blockno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
456 /* First, discover which of the double_indir->indir blocks
457 * contains pos. Then figure out how much of pos that
458 * accounted for. Then discover which of the iaddrs in
459 * the indirect block contains pos.
460 */
461
462 dblindir_indx = dbl_indir_off / diblklen;
463 dblindir_leftover = dbl_indir_off % diblklen;
464 indir_indx = dblindir_leftover / diblklen;
465
466 /* Read double indirect block */
467 dbl_which_block = dblindir_indx / befs_iaddrs_per_block(sb);
468 if (dbl_which_block > data->double_indirect.len) {
469 befs_error(sb, "The double-indirect index calculated by "
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700470 "%s, %d, is outside the range "
471 "of the double-indirect block", __func__,
472 dblindir_indx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 return BEFS_ERR;
474 }
475
476 dbl_indir_block =
Salah Trikif7f67542016-07-23 22:36:42 +1000477 sb_bread(sb, iaddr2blockno(sb, &data->double_indirect) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 dbl_which_block);
479 if (dbl_indir_block == NULL) {
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700480 befs_error(sb, "%s couldn't read the "
481 "double-indirect block at blockno %lu", __func__,
482 (unsigned long)
483 iaddr2blockno(sb, &data->double_indirect) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 dbl_which_block);
485 brelse(dbl_indir_block);
486 return BEFS_ERR;
487 }
488
489 dbl_block_indx =
490 dblindir_indx - (dbl_which_block * befs_iaddrs_per_block(sb));
Al Viroa9721f32005-12-24 14:28:55 -0500491 iaddr_array = (befs_disk_inode_addr *) dbl_indir_block->b_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 indir_run = fsrun_to_cpu(sb, iaddr_array[dbl_block_indx]);
493 brelse(dbl_indir_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495 /* Read indirect block */
496 which_block = indir_indx / befs_iaddrs_per_block(sb);
497 if (which_block > indir_run.len) {
498 befs_error(sb, "The indirect index calculated by "
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700499 "%s, %d, is outside the range "
500 "of the indirect block", __func__, indir_indx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 return BEFS_ERR;
502 }
503
504 indir_block =
Salah Trikif7f67542016-07-23 22:36:42 +1000505 sb_bread(sb, iaddr2blockno(sb, &indir_run) + which_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 if (indir_block == NULL) {
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700507 befs_error(sb, "%s couldn't read the indirect block "
508 "at blockno %lu", __func__, (unsigned long)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 iaddr2blockno(sb, &indir_run) + which_block);
510 brelse(indir_block);
511 return BEFS_ERR;
512 }
513
514 block_indx = indir_indx - (which_block * befs_iaddrs_per_block(sb));
Al Viroa9721f32005-12-24 14:28:55 -0500515 iaddr_array = (befs_disk_inode_addr *) indir_block->b_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 *run = fsrun_to_cpu(sb, iaddr_array[block_indx]);
517 brelse(indir_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
519 blockno_at_run_start = indir_start_blk;
520 blockno_at_run_start += diblklen * dblindir_indx;
521 blockno_at_run_start += iblklen * indir_indx;
522 offset = blockno - blockno_at_run_start;
523
524 run->start += offset;
525 run->len -= offset;
526
527 befs_debug(sb, "Found file block %lu in double_indirect[%d][%d],"
Fabian Frederickdac52fc2014-04-03 14:50:23 -0700528 " double_indirect_leftover = %lu", (unsigned long)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 blockno, dblindir_indx, indir_indx, dblindir_leftover);
530
531 return BEFS_OK;
532}