File: /usr/src/linux/fs/udf/partition.c

1     /*
2      * partition.c
3      *
4      * PURPOSE
5      *      Partition handling routines for the OSTA-UDF(tm) filesystem.
6      *
7      * CONTACTS
8      *      E-mail regarding any portion of the Linux UDF file system should be
9      *      directed to the development team mailing list (run by majordomo):
10      *              linux_udf@hpesjro.fc.hp.com
11      *
12      * COPYRIGHT
13      *      This file is distributed under the terms of the GNU General Public
14      *      License (GPL). Copies of the GPL can be obtained from:
15      *              ftp://prep.ai.mit.edu/pub/gnu/GPL
16      *      Each contributing author retains all rights to their own work.
17      *
18      *  (C) 1998-2000 Ben Fennema
19      *
20      * HISTORY
21      *
22      * 12/06/98 blf  Created file. 
23      *
24      */
25     
26     #include "udfdecl.h"
27     #include "udf_sb.h"
28     #include "udf_i.h"
29     
30     #include <linux/fs.h>
31     #include <linux/string.h>
32     #include <linux/udf_fs.h>
33     #include <linux/slab.h>
34     
35     inline Uint32 udf_get_pblock(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
36     {
37     	if (partition >= UDF_SB_NUMPARTS(sb))
38     	{
39     		udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n",
40     			block, partition, offset);
41     		return 0xFFFFFFFF;
42     	}
43     	if (UDF_SB_PARTFUNC(sb, partition))
44     		return UDF_SB_PARTFUNC(sb, partition)(sb, block, partition, offset);
45     	else
46     		return UDF_SB_PARTROOT(sb, partition) + block + offset;
47     }
48     
49     Uint32 udf_get_pblock_virt15(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
50     {
51     	struct buffer_head *bh = NULL;
52     	Uint32 newblock;
53     	Uint32 index;
54     	Uint32 loc;
55     
56     	index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(Uint32);
57     
58     	if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries)
59     	{
60     		udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
61     			block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
62     		return 0xFFFFFFFF;
63     	}
64     
65     	if (block >= index)
66     	{
67     		block -= index;
68     		newblock = 1 + (block / (sb->s_blocksize / sizeof(Uint32)));
69     		index = block % (sb->s_blocksize / sizeof(Uint32));
70     	}
71     	else
72     	{
73     		newblock = 0;
74     		index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(Uint32) + block;
75     	}
76     
77     	loc = udf_block_map(UDF_SB_VAT(sb), newblock);
78     
79     	if (!(bh = bread(sb->s_dev, loc, sb->s_blocksize)))
80     	{
81     		udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
82     			sb, block, partition, loc, index);
83     		return 0xFFFFFFFF;
84     	}
85     
86     	loc = le32_to_cpu(((Uint32 *)bh->b_data)[index]);
87     
88     	udf_release_data(bh);
89     
90     	if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
91     	{
92     		udf_debug("recursive call to udf_get_pblock!\n");
93     		return 0xFFFFFFFF;
94     	}
95     
96     	return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset);
97     }
98     
99     inline Uint32 udf_get_pblock_virt20(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
100     {
101     	return udf_get_pblock_virt15(sb, block, partition, offset);
102     }
103     
104     Uint32 udf_get_pblock_spar15(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
105     {
106     	int i;
107     	struct SparingTable *st = NULL;
108     	Uint32 packet = (block + offset) & ~(UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1);
109     
110     	for (i=0; i<4; i++)
111     	{
112     		if (UDF_SB_TYPESPAR(sb,partition).s_spar_map[i] != NULL)
113     		{
114     			st = (struct SparingTable *)UDF_SB_TYPESPAR(sb,partition).s_spar_map[i]->b_data;
115     			break;
116     		}
117     	}
118     
119     	if (st)
120     	{
121     		for (i=0; i<st->reallocationTableLen; i++)
122     		{
123     			if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0)
124     				break;
125     			else if (le32_to_cpu(st->mapEntry[i].origLocation) == packet)
126     			{
127     				return le32_to_cpu(st->mapEntry[i].mappedLocation) +
128     					((block + offset) & (UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1));
129     			}
130     			else if (le32_to_cpu(st->mapEntry[i].origLocation) > packet)
131     				break;
132     		}
133     	}
134     	return UDF_SB_PARTROOT(sb,partition) + block + offset;
135     }
136     
137     int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
138     {
139     	struct udf_sparing_data *sdata;
140     	struct SparingTable *st = NULL;
141     	SparingEntry mapEntry;
142     	Uint32 packet;
143     	int i, j, k, l;
144     
145     	for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
146     	{
147     		if (old_block > UDF_SB_PARTROOT(sb,i) &&
148     		    old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i))
149     		{
150     			sdata = &UDF_SB_TYPESPAR(sb,i);
151     			packet = (old_block - UDF_SB_PARTROOT(sb,i)) & ~(sdata->s_packet_len - 1);
152     
153     			for (j=0; j<4; j++)
154     			{
155     				if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL)
156     				{
157     					st = (struct SparingTable *)sdata->s_spar_map[j]->b_data;
158     					break;
159     				}
160     			}
161     
162     			if (!st)
163     				return 1;
164     
165     			for (k=0; k<st->reallocationTableLen; k++)
166     			{
167     				if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF)
168     				{
169     					for (; j<4; j++)
170     					{
171     						if (sdata->s_spar_map[j])
172     						{
173     							st = (struct SparingTable *)sdata->s_spar_map[j]->b_data;
174     							st->mapEntry[k].origLocation = cpu_to_le32(packet);
175     							udf_update_tag((char *)st, sizeof(struct SparingTable) + st->reallocationTableLen * sizeof(SparingEntry));
176     							mark_buffer_dirty(sdata->s_spar_map[j]);
177     						}
178     					}
179     					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
180     						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
181     					return 0;
182     				}
183     				else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet)
184     				{
185     					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
186     						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
187     					return 0;
188     				}
189     				else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet)
190     					break;
191     			}
192     			for (l=k; l<st->reallocationTableLen; l++)
193     			{
194     				if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF)
195     				{
196     					for (; j<4; j++)
197     					{
198     						if (sdata->s_spar_map[j])
199     						{
200     							st = (struct SparingTable *)sdata->s_spar_map[j]->b_data;
201     							mapEntry = st->mapEntry[l];
202     							mapEntry.origLocation = cpu_to_le32(packet);
203     							memmove(&st->mapEntry[k+1], &st->mapEntry[k], (l-k)*sizeof(SparingEntry));
204     							st->mapEntry[k] = mapEntry;
205     							udf_update_tag((char *)st, sizeof(struct SparingTable) + st->reallocationTableLen * sizeof(SparingEntry));
206     							mark_buffer_dirty(sdata->s_spar_map[j]);
207     						}
208     					}
209     					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
210     						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
211     					return 0;
212     				}
213     			}
214     			return 1;
215     		}
216     	}
217     	if (i == UDF_SB_NUMPARTS(sb))
218     	{
219     		/* outside of partitions */
220     		/* for now, fail =) */
221     		return 1;
222     	}
223     
224     	return 0;
225     }
226