]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/patches/suse-2.6.27.31/patches.fixes/udf-faster_anchor_detection.patch
Add a patch to fix Intel E100 wake-on-lan problems.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.fixes / udf-faster_anchor_detection.patch
CommitLineData
2cb7cef9
BS
1From: Jan Kara <jack@suse.cz>
2Subject: [PATCH] udf: Try anchor in block 256 first
3References: bnc#467174
4Patch-mainline: 2.6.30
5
6Anchor block can be located at several places on the medium. Two of the
7locations are relative to media end which is problematic to detect. Also
8some drives report some block as last but are not able to read it or any
9block nearby before it. So let's first try block 256 and if it is all fine,
10don't look at other possible locations of anchor blocks to avoid IO errors.
11This change required a larger reorganization of code but the new code is
12hopefully more readable and definitely shorter.
13
14Signed-off-by: Jan Kara <jack@suse.cz>
15
16diff -rupX /home/jack/.kerndiffexclude linux-2.6.27-SLE11_BRANCH/fs/udf/super.c linux-2.6.27-SLE11_BRANCH-1-udf_anchor_detection//fs/udf/super.c
17--- linux-2.6.27-SLE11_BRANCH/fs/udf/super.c 2008-10-10 00:13:53.000000000 +0200
18+++ linux-2.6.27-SLE11_BRANCH-1-udf_anchor_detection/fs/udf/super.c 2009-03-19 16:44:56.000000000 +0100
19@@ -83,10 +83,7 @@ static int udf_fill_super(struct super_b
20 static void udf_put_super(struct super_block *);
21 static void udf_write_super(struct super_block *);
22 static int udf_remount_fs(struct super_block *, int *, char *);
23-static int udf_check_valid(struct super_block *, int, int);
24-static int udf_vrs(struct super_block *sb, int silent);
25 static void udf_load_logicalvolint(struct super_block *, kernel_extent_ad);
26-static void udf_find_anchor(struct super_block *);
27 static int udf_find_fileset(struct super_block *, kernel_lb_addr *,
28 kernel_lb_addr *);
29 static void udf_load_fileset(struct super_block *, struct buffer_head *,
30@@ -286,14 +283,8 @@ static int udf_show_options(struct seq_f
31 seq_printf(seq, ",session=%u", sbi->s_session);
32 if (UDF_QUERY_FLAG(sb, UDF_FLAG_LASTBLOCK_SET))
33 seq_printf(seq, ",lastblock=%u", sbi->s_last_block);
34- /*
35- * s_anchor[2] could be zeroed out in case there is no anchor
36- * in the specified block, but then the "anchor=N" option
37- * originally given by the user wasn't effective, so it's OK
38- * if we don't show it.
39- */
40- if (sbi->s_anchor[2] != 0)
41- seq_printf(seq, ",anchor=%u", sbi->s_anchor[2]);
42+ if (sbi->s_anchor != 0)
43+ seq_printf(seq, ",anchor=%u", sbi->s_anchor);
44 /*
45 * volume, partition, fileset and rootdir seem to be ignored
46 * currently
47@@ -585,22 +576,19 @@ static int udf_remount_fs(struct super_b
48 return 0;
49 }
50
51-static int udf_vrs(struct super_block *sb, int silent)
52+/* Check Volume Structure Descriptors (ECMA 167 2/9.1) */
53+/* We also check any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */
54+static loff_t udf_check_vsd(struct super_block *sb)
55 {
56 struct volStructDesc *vsd = NULL;
57 loff_t sector = 32768;
58 int sectorsize;
59 struct buffer_head *bh = NULL;
60- int iso9660 = 0;
61 int nsr02 = 0;
62 int nsr03 = 0;
63 struct udf_sb_info *sbi;
64
65- /* Block size must be a multiple of 512 */
66- if (sb->s_blocksize & 511)
67- return 0;
68 sbi = UDF_SB(sb);
69-
70 if (sb->s_blocksize < sizeof(struct volStructDesc))
71 sectorsize = sizeof(struct volStructDesc);
72 else
73@@ -627,7 +615,6 @@ static int udf_vrs(struct super_block *s
74 break;
75 } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001,
76 VSD_STD_ID_LEN)) {
77- iso9660 = sector;
78 switch (vsd->structType) {
79 case 0:
80 udf_debug("ISO9660 Boot Record found\n");
81@@ -679,136 +666,6 @@ static int udf_vrs(struct super_block *s
82 return 0;
83 }
84
85-/*
86- * Check whether there is an anchor block in the given block
87- */
88-static int udf_check_anchor_block(struct super_block *sb, sector_t block)
89-{
90- struct buffer_head *bh;
91- uint16_t ident;
92-
93- if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) &&
94- udf_fixed_to_variable(block) >=
95- sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits)
96- return 0;
97-
98- bh = udf_read_tagged(sb, block, block, &ident);
99- if (!bh)
100- return 0;
101- brelse(bh);
102-
103- return ident == TAG_IDENT_AVDP;
104-}
105-
106-/* Search for an anchor volume descriptor pointer */
107-static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock)
108-{
109- sector_t last[6];
110- int i;
111- struct udf_sb_info *sbi = UDF_SB(sb);
112-
113- last[0] = lastblock;
114- last[1] = last[0] - 1;
115- last[2] = last[0] + 1;
116- last[3] = last[0] - 2;
117- last[4] = last[0] - 150;
118- last[5] = last[0] - 152;
119-
120- /* according to spec, anchor is in either:
121- * block 256
122- * lastblock-256
123- * lastblock
124- * however, if the disc isn't closed, it could be 512 */
125-
126- for (i = 0; i < ARRAY_SIZE(last); i++) {
127- if (last[i] < 0)
128- continue;
129- if (last[i] >= sb->s_bdev->bd_inode->i_size >>
130- sb->s_blocksize_bits)
131- continue;
132-
133- if (udf_check_anchor_block(sb, last[i])) {
134- sbi->s_anchor[0] = last[i];
135- sbi->s_anchor[1] = last[i] - 256;
136- return last[i];
137- }
138-
139- if (last[i] < 256)
140- continue;
141-
142- if (udf_check_anchor_block(sb, last[i] - 256)) {
143- sbi->s_anchor[1] = last[i] - 256;
144- return last[i];
145- }
146- }
147-
148- if (udf_check_anchor_block(sb, sbi->s_session + 256)) {
149- sbi->s_anchor[0] = sbi->s_session + 256;
150- return last[0];
151- }
152- if (udf_check_anchor_block(sb, sbi->s_session + 512)) {
153- sbi->s_anchor[0] = sbi->s_session + 512;
154- return last[0];
155- }
156- return 0;
157-}
158-
159-/*
160- * Find an anchor volume descriptor. The function expects sbi->s_lastblock to
161- * be the last block on the media.
162- *
163- * Return 1 if not found, 0 if ok
164- *
165- */
166-static void udf_find_anchor(struct super_block *sb)
167-{
168- sector_t lastblock;
169- struct buffer_head *bh = NULL;
170- uint16_t ident;
171- int i;
172- struct udf_sb_info *sbi = UDF_SB(sb);
173-
174- lastblock = udf_scan_anchors(sb, sbi->s_last_block);
175- if (lastblock)
176- goto check_anchor;
177-
178- /* No anchor found? Try VARCONV conversion of block numbers */
179- UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
180- /* Firstly, we try to not convert number of the last block */
181- lastblock = udf_scan_anchors(sb,
182- udf_variable_to_fixed(sbi->s_last_block));
183- if (lastblock)
184- goto check_anchor;
185-
186- /* Secondly, we try with converted number of the last block */
187- lastblock = udf_scan_anchors(sb, sbi->s_last_block);
188- if (!lastblock) {
189- /* VARCONV didn't help. Clear it. */
190- UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV);
191- }
192-
193-check_anchor:
194- /*
195- * Check located anchors and the anchor block supplied via
196- * mount options
197- */
198- for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) {
199- if (!sbi->s_anchor[i])
200- continue;
201- bh = udf_read_tagged(sb, sbi->s_anchor[i],
202- sbi->s_anchor[i], &ident);
203- if (!bh)
204- sbi->s_anchor[i] = 0;
205- else {
206- brelse(bh);
207- if (ident != TAG_IDENT_AVDP)
208- sbi->s_anchor[i] = 0;
209- }
210- }
211-
212- sbi->s_last_block = lastblock;
213-}
214-
215 static int udf_find_fileset(struct super_block *sb,
216 kernel_lb_addr *fileset,
217 kernel_lb_addr *root)
218@@ -1655,86 +1512,201 @@ static noinline int udf_process_sequence
219 return 0;
220 }
221
222+static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh,
223+ kernel_lb_addr *fileset)
224+{
225+ struct anchorVolDescPtr *anchor;
226+ long main_s, main_e, reserve_s, reserve_e;
227+ struct udf_sb_info *sbi;
228+
229+ sbi = UDF_SB(sb);
230+ anchor = (struct anchorVolDescPtr *)bh->b_data;
231+
232+ /* Locate the main sequence */
233+ main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation);
234+ main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength);
235+ main_e = main_e >> sb->s_blocksize_bits;
236+ main_e += main_s;
237+
238+ /* Locate the reserve sequence */
239+ reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation);
240+ reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength);
241+ reserve_e = reserve_e >> sb->s_blocksize_bits;
242+ reserve_e += reserve_s;
243+
244+ /* Process the main & reserve sequences */
245+ /* responsible for finding the PartitionDesc(s) */
246+ if (!udf_process_sequence(sb, main_s, main_e, fileset))
247+ return 1;
248+ return !udf_process_sequence(sb, reserve_s, reserve_e, fileset);
249+}
250+
251 /*
252- * udf_check_valid()
253+ * Check whether there is an anchor block in the given block and
254+ * load Volume Descriptor Sequence if so.
255 */
256-static int udf_check_valid(struct super_block *sb, int novrs, int silent)
257+static int udf_check_anchor_block(struct super_block *sb, sector_t block,
258+ kernel_lb_addr *fileset)
259 {
260- long block;
261- struct udf_sb_info *sbi = UDF_SB(sb);
262+ struct buffer_head *bh;
263+ uint16_t ident;
264+ int ret;
265
266- if (novrs) {
267- udf_debug("Validity check skipped because of novrs option\n");
268+ if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) &&
269+ udf_fixed_to_variable(block) >=
270+ sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits)
271+ return 0;
272+
273+ bh = udf_read_tagged(sb, block, block, &ident);
274+ if (!bh)
275+ return 0;
276+ if (ident != TAG_IDENT_AVDP) {
277+ brelse(bh);
278 return 0;
279 }
280- /* Check that it is NSR02 compliant */
281- /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */
282- block = udf_vrs(sb, silent);
283- if (block == -1)
284- udf_debug("Failed to read byte 32768. Assuming open "
285- "disc. Skipping validity check\n");
286- if (block && !sbi->s_last_block)
287- sbi->s_last_block = udf_get_last_block(sb);
288- return !block;
289+ ret = udf_load_sequence(sb, bh, fileset);
290+ brelse(bh);
291+ return ret;
292 }
293
294-static int udf_load_sequence(struct super_block *sb, kernel_lb_addr *fileset)
295+/* Search for an anchor volume descriptor pointer */
296+static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock,
297+ kernel_lb_addr *fileset)
298 {
299- struct anchorVolDescPtr *anchor;
300- uint16_t ident;
301- struct buffer_head *bh;
302- long main_s, main_e, reserve_s, reserve_e;
303+ sector_t last[6];
304 int i;
305- struct udf_sb_info *sbi;
306+ struct udf_sb_info *sbi = UDF_SB(sb);
307+ int last_count = 0;
308
309- if (!sb)
310- return 1;
311- sbi = UDF_SB(sb);
312+ /* First try user provided anchor */
313+ if (sbi->s_anchor) {
314+ if (udf_check_anchor_block(sb, sbi->s_anchor, fileset))
315+ return lastblock;
316+ }
317+ /*
318+ * according to spec, anchor is in either:
319+ * block 256
320+ * lastblock-256
321+ * lastblock
322+ * however, if the disc isn't closed, it could be 512.
323+ */
324+ if (udf_check_anchor_block(sb, sbi->s_session + 256, fileset))
325+ return lastblock;
326+ /*
327+ * The trouble is which block is the last one. Drives often misreport
328+ * this so we try various possibilities.
329+ */
330+ last[last_count++] = lastblock;
331+ if (lastblock >= 1)
332+ last[last_count++] = lastblock - 1;
333+ last[last_count++] = lastblock + 1;
334+ if (lastblock >= 2)
335+ last[last_count++] = lastblock - 2;
336+ if (lastblock >= 150)
337+ last[last_count++] = lastblock - 150;
338+ if (lastblock >= 152)
339+ last[last_count++] = lastblock - 152;
340
341- for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) {
342- if (!sbi->s_anchor[i])
343+ for (i = 0; i < last_count; i++) {
344+ if (last[i] >= sb->s_bdev->bd_inode->i_size >>
345+ sb->s_blocksize_bits)
346 continue;
347-
348- bh = udf_read_tagged(sb, sbi->s_anchor[i], sbi->s_anchor[i],
349- &ident);
350- if (!bh)
351+ if (udf_check_anchor_block(sb, last[i], fileset))
352+ return last[i];
353+ if (last[i] < 256)
354 continue;
355+ if (udf_check_anchor_block(sb, last[i] - 256, fileset))
356+ return last[i];
357+ }
358+
359+ /* Finally try block 512 in case media is open */
360+ if (udf_check_anchor_block(sb, sbi->s_session + 512, fileset))
361+ return last[0];
362+ return 0;
363+}
364
365- anchor = (struct anchorVolDescPtr *)bh->b_data;
366+/*
367+ * Find an anchor volume descriptor and load Volume Descriptor Sequence from
368+ * area specified by it. The function expects sbi->s_lastblock to be the last
369+ * block on the media.
370+ *
371+ * Return 1 if ok, 0 if not found.
372+ *
373+ */
374+static int udf_find_anchor(struct super_block *sb,
375+ kernel_lb_addr *fileset)
376+{
377+ sector_t lastblock;
378+ struct udf_sb_info *sbi = UDF_SB(sb);
379
380- /* Locate the main sequence */
381- main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation);
382- main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength);
383- main_e = main_e >> sb->s_blocksize_bits;
384- main_e += main_s;
385-
386- /* Locate the reserve sequence */
387- reserve_s = le32_to_cpu(
388- anchor->reserveVolDescSeqExt.extLocation);
389- reserve_e = le32_to_cpu(
390- anchor->reserveVolDescSeqExt.extLength);
391- reserve_e = reserve_e >> sb->s_blocksize_bits;
392- reserve_e += reserve_s;
393+ lastblock = udf_scan_anchors(sb, sbi->s_last_block, fileset);
394+ if (lastblock)
395+ goto out;
396
397- brelse(bh);
398+ /* No anchor found? Try VARCONV conversion of block numbers */
399+ UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
400+ /* Firstly, we try to not convert number of the last block */
401+ lastblock = udf_scan_anchors(sb,
402+ udf_variable_to_fixed(sbi->s_last_block),
403+ fileset);
404+ if (lastblock)
405+ goto out;
406
407- /* Process the main & reserve sequences */
408- /* responsible for finding the PartitionDesc(s) */
409- if (!(udf_process_sequence(sb, main_s, main_e,
410- fileset) &&
411- udf_process_sequence(sb, reserve_s, reserve_e,
412- fileset)))
413- break;
414+ /* Secondly, we try with converted number of the last block */
415+ lastblock = udf_scan_anchors(sb, sbi->s_last_block, fileset);
416+ if (!lastblock) {
417+ /* VARCONV didn't help. Clear it. */
418+ UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV);
419+ return 0;
420 }
421+out:
422+ sbi->s_last_block = lastblock;
423+ return 1;
424+}
425
426- if (i == ARRAY_SIZE(sbi->s_anchor)) {
427- udf_debug("No Anchor block found\n");
428- return 1;
429+/*
430+ * Check Volume Structure Descriptor, find Anchor block and load Volume
431+ * Descriptor Sequence
432+ */
433+static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt,
434+ int silent, kernel_lb_addr *fileset)
435+{
436+ struct udf_sb_info *sbi = UDF_SB(sb);
437+ loff_t nsr_off;
438+
439+ if (!sb_set_blocksize(sb, uopt->blocksize)) {
440+ if (!silent)
441+ printk(KERN_WARNING "UDF-fs: Bad block size\n");
442+ return 0;
443+ }
444+ sbi->s_last_block = uopt->lastblock;
445+ if (!uopt->novrs) {
446+ /* Check that it is NSR02 compliant */
447+ nsr_off = udf_check_vsd(sb);
448+ if (!nsr_off) {
449+ if (!silent)
450+ printk(KERN_WARNING "UDF-fs: No VRS found\n");
451+ return 0;
452+ }
453+ if (nsr_off == -1)
454+ udf_debug("Failed to read byte 32768. Assuming open "
455+ "disc. Skipping validity check\n");
456+ if (!sbi->s_last_block)
457+ sbi->s_last_block = udf_get_last_block(sb);
458+ } else {
459+ udf_debug("Validity check skipped because of novrs option\n");
460 }
461- udf_debug("Using anchor in block %d\n", sbi->s_anchor[i]);
462
463- return 0;
464+ /* Look for anchor block and load Volume Descriptor Sequence */
465+ sbi->s_anchor = uopt->anchor;
466+ if (!udf_find_anchor(sb, fileset)) {
467+ if (!silent)
468+ printk(KERN_WARNING "UDF-fs: No anchor found\n");
469+ return 0;
470+ }
471+ return 1;
472 }
473+
474
475 static void udf_open_lvid(struct super_block *sb)
476 {
477@@ -1908,18 +1880,6 @@ static int udf_fill_super(struct super_b
478
479 udf_debug("Multi-session=%d\n", sbi->s_session);
480
481- sbi->s_last_block = uopt.lastblock;
482- sbi->s_anchor[0] = sbi->s_anchor[1] = 0;
483- sbi->s_anchor[2] = uopt.anchor;
484-
485- if (udf_check_valid(sb, uopt.novrs, silent)) {
486- /* read volume recognition sequences */
487- printk(KERN_WARNING "UDF-fs: No VRS found\n");
488- goto error_out;
489- }
490-
491- udf_find_anchor(sb);
492-
493 /* Fill in the rest of the superblock */
494 sb->s_op = &udf_sb_ops;
495 sb->s_export_op = &udf_export_ops;
496@@ -1928,7 +1888,7 @@ static int udf_fill_super(struct super_b
497 sb->s_magic = UDF_SUPER_MAGIC;
498 sb->s_time_gran = 1000;
499
500- if (udf_load_sequence(sb, &fileset)) {
501+ if (!udf_load_vrs(sb, &uopt, silent, &fileset)) {
502 printk(KERN_WARNING "UDF-fs: No partition found (1)\n");
503 goto error_out;
504 }
505diff -rupX /home/jack/.kerndiffexclude linux-2.6.27-SLE11_BRANCH/fs/udf/udf_sb.h linux-2.6.27-SLE11_BRANCH-1-udf_anchor_detection//fs/udf/udf_sb.h
506--- linux-2.6.27-SLE11_BRANCH/fs/udf/udf_sb.h 2008-10-10 00:13:53.000000000 +0200
507+++ linux-2.6.27-SLE11_BRANCH-1-udf_anchor_detection/fs/udf/udf_sb.h 2009-03-19 16:33:24.000000000 +0100
508@@ -114,7 +114,7 @@ struct udf_sb_info {
509
510 /* Sector headers */
511 __s32 s_session;
512- __u32 s_anchor[3];
513+ __u32 s_anchor;
514 __u32 s_last_block;
515
516 struct buffer_head *s_lvid_bh;