inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset) { if (partition >= UDF_SB_NUMPARTS(sb)) { udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n", block, partition, offset); return 0xFFFFFFFF; } if (UDF_SB_PARTFUNC(sb, partition)) return UDF_SB_PARTFUNC(sb, partition)(sb, block, partition, offset); else return UDF_SB_PARTROOT(sb, partition) + block + offset; }
int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block) { struct udf_sparing_data *sdata; struct sparingTable *st = NULL; struct sparingEntry mapEntry; uint32_t packet; int i, j, k, l; for (i = 0; i < UDF_SB_NUMPARTS(sb); i++) { if (old_block > UDF_SB_PARTROOT(sb,i) && old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i)) { sdata = &UDF_SB_TYPESPAR(sb,i); packet = (old_block - UDF_SB_PARTROOT(sb,i)) & ~(sdata->s_packet_len - 1); for (j = 0; j < 4; j++) { if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL) { st = (struct sparingTable *)sdata->s_spar_map[j]->b_data; break; } } if (!st) return 1; for (k = 0; k < le16_to_cpu(st->reallocationTableLen); k++) { if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF) { for (; j < 4; j++) { if (sdata->s_spar_map[j]) { st = (struct sparingTable *)sdata->s_spar_map[j]->b_data; st->mapEntry[k].origLocation = cpu_to_le32(packet); udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry)); mark_buffer_dirty(sdata->s_spar_map[j]); } } *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) + ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1)); return 0; } else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet) { *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) + ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1)); return 0; } else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet) { break; } } for (l = k; l < le16_to_cpu(st->reallocationTableLen); l++) { if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF) { for (; j < 4; j++) { if (sdata->s_spar_map[j]) { st = (struct sparingTable *)sdata->s_spar_map[j]->b_data; mapEntry = st->mapEntry[l]; mapEntry.origLocation = cpu_to_le32(packet); memmove(&st->mapEntry[k + 1], &st->mapEntry[k], (l - k) * sizeof(struct sparingEntry)); st->mapEntry[k] = mapEntry; udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry)); mark_buffer_dirty(sdata->s_spar_map[j]); } } *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) + ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1)); return 0; } } return 1; } /* if old_block */ } if (i == UDF_SB_NUMPARTS(sb)) { /* outside of partitions */ /* for now, fail =) */ return 1; } return 0; }
static int udf_find_fileset(struct super_block *sb, lb_addr *fileset, lb_addr *root) { struct buffer_head *bh = NULL; long lastblock; Uint16 ident; if (fileset->logicalBlockNum != 0xFFFFFFFF || fileset->partitionReferenceNum != 0xFFFF) { bh = udf_read_ptagged(sb, *fileset, 0, &ident); if (!bh) return 1; else if (ident != TID_FILE_SET_DESC) { udf_release_data(bh); return 1; } } if (!bh) /* Search backwards through the partitions */ { lb_addr newfileset; return 1; for (newfileset.partitionReferenceNum=UDF_SB_NUMPARTS(sb)-1; (newfileset.partitionReferenceNum != 0xFFFF && fileset->logicalBlockNum == 0xFFFFFFFF && fileset->partitionReferenceNum == 0xFFFF); newfileset.partitionReferenceNum--) { lastblock = UDF_SB_PARTLEN(sb, newfileset.partitionReferenceNum); newfileset.logicalBlockNum = 0; do { bh = udf_read_ptagged(sb, newfileset, 0, &ident); if (!bh) { newfileset.logicalBlockNum ++; continue; } switch (ident) { case TID_SPACE_BITMAP_DESC: { struct SpaceBitmapDesc *sp; sp = (struct SpaceBitmapDesc *)bh->b_data; newfileset.logicalBlockNum += 1 + ((le32_to_cpu(sp->numOfBytes) + sizeof(struct SpaceBitmapDesc) - 1) >> sb->s_blocksize_bits); udf_release_data(bh); break; } case TID_FILE_SET_DESC: { *fileset = newfileset; break; } default: { newfileset.logicalBlockNum ++; udf_release_data(bh); bh = NULL; break; } } } while (newfileset.logicalBlockNum < lastblock && fileset->logicalBlockNum == 0xFFFFFFFF && fileset->partitionReferenceNum == 0xFFFF); } }