Backport upstream patch: udf-use-hw-sector-size.diff
[kernel-power] / kernel-power-2.6.28 / debian / patches / udf-use-hw-sector-size.diff
1 From 1197e4dfcf4ac17d763a59e5de1d4d4b9781a555 Mon Sep 17 00:00:00 2001
2 From: Clemens Ladisch <clemens@ladisch.de>
3 Date: Wed, 11 Mar 2009 15:57:47 +0100
4 Subject: [PATCH] udf: use hardware sector size
5
6 This patch makes the UDF FS driver use the hardware sector size as the
7 default logical block size, which is required by the UDF specifications.
8 While the previous default of 2048 bytes was correct for optical disks,
9 it was not for hard disks or USB storage devices, and made it impossible
10 to use such a device with the default mount options.  (The Linux mkudffs
11 tool uses a default block size of 2048 bytes even on devices with
12 smaller hardware sectors, so this bug is unlikely to be noticed unless
13 UDF-formatted USB storage devices are exchanged with other OSs.)
14
15 To avoid regressions for people who use loopback optical disk images or
16 who used the (sometimes wrong) defaults of mkudffs, we also try with
17 a block size of 2048 bytes if no anchor was found with the hardware
18 sector size.
19
20 Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
21 Signed-off-by: Jan Kara <jack@suse.cz>
22 ---
23  fs/udf/super.c  |   70 ++++++++++++++++++++++++++++++++++++++----------------
24  fs/udf/udf_sb.h |    1 +
25  2 files changed, 50 insertions(+), 21 deletions(-)
26
27 diff --git a/fs/udf/super.c b/fs/udf/super.c
28 index 36a467c..f8fece4 100644
29 --- a/fs/udf/super.c
30 +++ b/fs/udf/super.c
31 @@ -86,7 +86,6 @@ static int udf_remount_fs(struct super_block *, int *, char *);
32  static int udf_check_valid(struct super_block *, int, int);
33  static int udf_vrs(struct super_block *sb, int silent);
34  static void udf_load_logicalvolint(struct super_block *, struct kernel_extent_ad);
35 -static void udf_find_anchor(struct super_block *);
36  static int udf_find_fileset(struct super_block *, struct kernel_lb_addr *,
37                             struct kernel_lb_addr *);
38  static void udf_load_fileset(struct super_block *, struct buffer_head *,
39 @@ -260,7 +259,7 @@ static int udf_show_options(struct seq_file *seq, struct vfsmount *mnt)
40  
41         if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT))
42                 seq_puts(seq, ",nostrict");
43 -       if (sb->s_blocksize != UDF_DEFAULT_BLOCKSIZE)
44 +       if (UDF_QUERY_FLAG(sb, UDF_FLAG_BLOCKSIZE_SET))
45                 seq_printf(seq, ",bs=%lu", sb->s_blocksize);
46         if (UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE))
47                 seq_puts(seq, ",unhide");
48 @@ -416,7 +415,6 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
49         int option;
50  
51         uopt->novrs = 0;
52 -       uopt->blocksize = UDF_DEFAULT_BLOCKSIZE;
53         uopt->partition = 0xFFFF;
54         uopt->session = 0xFFFFFFFF;
55         uopt->lastblock = 0;
56 @@ -444,6 +442,7 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
57                         if (match_int(&args[0], &option))
58                                 return 0;
59                         uopt->blocksize = option;
60 +                       uopt->flags |= (1 << UDF_FLAG_BLOCKSIZE_SET);
61                         break;
62                 case Opt_unhide:
63                         uopt->flags |= (1 << UDF_FLAG_UNHIDE);
64 @@ -789,12 +788,13 @@ static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock)
65   * Return 1 if not found, 0 if ok
66   *
67   */
68 -static void udf_find_anchor(struct super_block *sb)
69 +static int udf_find_anchor(struct super_block *sb)
70  {
71         sector_t lastblock;
72         struct buffer_head *bh = NULL;
73         uint16_t ident;
74         int i;
75 +       int anchor_found = 0;
76         struct udf_sb_info *sbi = UDF_SB(sb);
77  
78         lastblock = udf_scan_anchors(sb, sbi->s_last_block);
79 @@ -832,10 +832,13 @@ check_anchor:
80                         brelse(bh);
81                         if (ident != TAG_IDENT_AVDP)
82                                 sbi->s_anchor[i] = 0;
83 +                       else
84 +                               anchor_found = 1;
85                 }
86         }
87  
88         sbi->s_last_block = lastblock;
89 +       return anchor_found;
90  }
91  
92  static int udf_find_fileset(struct super_block *sb,
93 @@ -1721,6 +1724,32 @@ static int udf_check_valid(struct super_block *sb, int novrs, int silent)
94         return !block;
95  }
96  
97 +static int udf_check_volume(struct super_block *sb,
98 +                           struct udf_options *uopt, int silent)
99 +{
100 +       struct udf_sb_info *sbi = UDF_SB(sb);
101 +
102 +       if (!sb_set_blocksize(sb, uopt->blocksize)) {
103 +               if (!silent)
104 +                       printk(KERN_WARNING "UDF-fs: Bad block size\n");
105 +               return 0;
106 +       }
107 +       sbi->s_last_block = uopt->lastblock;
108 +       if (udf_check_valid(sb, uopt->novrs, silent)) {
109 +               if (!silent)
110 +                       printk(KERN_WARNING "UDF-fs: No VRS found\n");
111 +               return 0;
112 +       }
113 +       sbi->s_anchor[0] = sbi->s_anchor[1] = 0;
114 +       sbi->s_anchor[2] = uopt->anchor;
115 +       if (!udf_find_anchor(sb)) {
116 +               if (!silent)
117 +                       printk(KERN_WARNING "UDF-fs: No anchor found\n");
118 +               return 0;
119 +       }
120 +       return 1;
121 +}
122 +
123  static int udf_load_sequence(struct super_block *sb, struct kernel_lb_addr *fileset)
124  {
125         struct anchorVolDescPtr *anchor;
126 @@ -1889,6 +1918,7 @@ static void udf_free_partition(struct udf_part_map *map)
127  static int udf_fill_super(struct super_block *sb, void *options, int silent)
128  {
129         int i;
130 +       int found_anchor;
131         struct inode *inode = NULL;
132         struct udf_options uopt;
133         struct kernel_lb_addr rootdir, fileset;
134 @@ -1941,13 +1971,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
135         sbi->s_dmode = uopt.dmode;
136         sbi->s_nls_map = uopt.nls_map;
137  
138 -       /* Set the block size for all transfers */
139 -       if (!sb_min_blocksize(sb, uopt.blocksize)) {
140 -               udf_debug("Bad block size (%d)\n", uopt.blocksize);
141 -               printk(KERN_ERR "udf: bad block size (%d)\n", uopt.blocksize);
142 -               goto error_out;
143 -       }
144 -
145         if (uopt.session == 0xFFFFFFFF)
146                 sbi->s_session = udf_get_last_session(sb);
147         else
148 @@ -1955,17 +1978,22 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
149  
150         udf_debug("Multi-session=%d\n", sbi->s_session);
151  
152 -       sbi->s_last_block = uopt.lastblock;
153 -       sbi->s_anchor[0] = sbi->s_anchor[1] = 0;
154 -       sbi->s_anchor[2] = uopt.anchor;
155 -
156 -       if (udf_check_valid(sb, uopt.novrs, silent)) {
157 -               /* read volume recognition sequences */
158 -               printk(KERN_WARNING "UDF-fs: No VRS found\n");
159 -               goto error_out;
160 +       if (uopt.flags & (1 << UDF_FLAG_BLOCKSIZE_SET)) {
161 +               found_anchor = udf_check_volume(sb, &uopt, silent);
162 +       } else {
163 +               uopt.blocksize = bdev_hardsect_size(sb->s_bdev);
164 +               found_anchor = udf_check_volume(sb, &uopt, silent);
165 +               if (!found_anchor && uopt.blocksize != UDF_DEFAULT_BLOCKSIZE) {
166 +                       if (!silent)
167 +                               printk(KERN_NOTICE
168 +                                      "UDF-fs: Rescanning with blocksize "
169 +                                      "%d\n", UDF_DEFAULT_BLOCKSIZE);
170 +                       uopt.blocksize = UDF_DEFAULT_BLOCKSIZE;
171 +                       found_anchor = udf_check_volume(sb, &uopt, silent);
172 +               }
173         }
174 -
175 -       udf_find_anchor(sb);
176 +       if (!found_anchor)
177 +               goto error_out;
178  
179         /* Fill in the rest of the superblock */
180         sb->s_op = &udf_sb_ops;
181 diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h
182 index 158221e..2dd9219 100644
183 --- a/fs/udf/udf_sb.h
184 +++ b/fs/udf/udf_sb.h
185 @@ -30,6 +30,7 @@
186  #define UDF_FLAG_GID_SET       16
187  #define UDF_FLAG_SESSION_SET   17
188  #define UDF_FLAG_LASTBLOCK_SET 18
189 +#define UDF_FLAG_BLOCKSIZE_SET 19
190  
191  #define UDF_PART_FLAG_UNALLOC_BITMAP   0x0001
192  #define UDF_PART_FLAG_UNALLOC_TABLE    0x0002
193 -- 
194 1.7.7.6
195