Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/paulus/ppc64-2.6
[linux-2.6] / fs / freevxfs / vxfs_bmap.c
1 /*
2  * Copyright (c) 2000-2001 Christoph Hellwig.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions, and the following disclaimer,
10  *    without modification.
11  * 2. The name of the author may not be used to endorse or promote products
12  *    derived from this software without specific prior written permission.
13  *
14  * Alternatively, this software may be distributed under the terms of the
15  * GNU General Public License ("GPL").
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 /*
31  * Veritas filesystem driver - filesystem to disk block mapping.
32  */
33 #include <linux/fs.h>
34 #include <linux/buffer_head.h>
35 #include <linux/kernel.h>
36
37 #include "vxfs.h"
38 #include "vxfs_inode.h"
39
40
41 #ifdef DIAGNOSTIC
42 static void
43 vxfs_typdump(struct vxfs_typed *typ)
44 {
45         printk(KERN_DEBUG "type=%Lu ", typ->vt_hdr >> VXFS_TYPED_TYPESHIFT);
46         printk("offset=%Lx ", typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
47         printk("block=%x ", typ->vt_block);
48         printk("size=%x\n", typ->vt_size);
49 }
50 #endif
51
52 /**
53  * vxfs_bmap_ext4 - do bmap for ext4 extents
54  * @ip:         pointer to the inode we do bmap for
55  * @iblock:     logical block.
56  *
57  * Description:
58  *   vxfs_bmap_ext4 performs the bmap operation for inodes with
59  *   ext4-style extents (which are much like the traditional UNIX
60  *   inode organisation).
61  *
62  * Returns:
63  *   The physical block number on success, else Zero.
64  */
65 static daddr_t
66 vxfs_bmap_ext4(struct inode *ip, long bn)
67 {
68         struct super_block *sb = ip->i_sb;
69         struct vxfs_inode_info *vip = VXFS_INO(ip);
70         unsigned long bsize = sb->s_blocksize;
71         u32 indsize = vip->vii_ext4.ve4_indsize;
72         int i;
73
74         if (indsize > sb->s_blocksize)
75                 goto fail_size;
76
77         for (i = 0; i < VXFS_NDADDR; i++) {
78                 struct direct *d = vip->vii_ext4.ve4_direct + i;
79                 if (bn >= 0 && bn < d->size)
80                         return (bn + d->extent);
81                 bn -= d->size;
82         }
83
84         if ((bn / (indsize * indsize * bsize / 4)) == 0) {
85                 struct buffer_head *buf;
86                 daddr_t bno;
87                 u32 *indir;
88
89                 buf = sb_bread(sb, vip->vii_ext4.ve4_indir[0]);
90                 if (!buf || !buffer_mapped(buf))
91                         goto fail_buf;
92
93                 indir = (u32 *)buf->b_data;
94                 bno = indir[(bn/indsize) % (indsize*bn)] + (bn%indsize);
95
96                 brelse(buf);
97                 return bno;
98         } else
99                 printk(KERN_WARNING "no matching indir?");
100
101         return 0;
102
103 fail_size:
104         printk("vxfs: indirect extent too big!\n");
105 fail_buf:
106         return 0;
107 }
108
109 /**
110  * vxfs_bmap_indir - recursion for vxfs_bmap_typed
111  * @ip:         pointer to the inode we do bmap for
112  * @indir:      indirect block we start reading at
113  * @size:       size of the typed area to search
114  * @block:      partially result from further searches
115  *
116  * Description:
117  *   vxfs_bmap_indir reads a &struct vxfs_typed at @indir
118  *   and performs the type-defined action.
119  *
120  * Return Value:
121  *   The physical block number on success, else Zero.
122  *
123  * Note:
124  *   Kernelstack is rare.  Unrecurse?
125  */
126 static daddr_t
127 vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
128 {
129         struct buffer_head              *bp = NULL;
130         daddr_t                         pblock = 0;
131         int                             i;
132
133         for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) {
134                 struct vxfs_typed       *typ;
135                 int64_t                 off;
136
137                 bp = sb_bread(ip->i_sb,
138                                 indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)));
139                 if (!buffer_mapped(bp))
140                         return 0;
141
142                 typ = ((struct vxfs_typed *)bp->b_data) +
143                         (i % VXFS_TYPED_PER_BLOCK(ip->i_sb));
144                 off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
145
146                 if (block < off) {
147                         brelse(bp);
148                         continue;
149                 }
150
151                 switch ((u_int32_t)(typ->vt_hdr >> VXFS_TYPED_TYPESHIFT)) {
152                 case VXFS_TYPED_INDIRECT:
153                         pblock = vxfs_bmap_indir(ip, typ->vt_block,
154                                         typ->vt_size, block - off);
155                         if (pblock == -2)
156                                 break;
157                         goto out;
158                 case VXFS_TYPED_DATA:
159                         if ((block - off) >= typ->vt_size)
160                                 break;
161                         pblock = (typ->vt_block + block - off);
162                         goto out;
163                 case VXFS_TYPED_INDIRECT_DEV4:
164                 case VXFS_TYPED_DATA_DEV4: {
165                         struct vxfs_typed_dev4  *typ4 =
166                                 (struct vxfs_typed_dev4 *)typ;
167
168                         printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
169                         printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
170                                (unsigned long long) typ4->vd4_block,
171                                (unsigned long long) typ4->vd4_size,
172                                typ4->vd4_dev);
173                         goto fail;
174                 }
175                 default:
176                         BUG();
177                 }
178                 brelse(bp);
179         }
180
181 fail:
182         pblock = 0;
183 out:
184         brelse(bp);
185         return (pblock);
186 }
187
188 /**
189  * vxfs_bmap_typed - bmap for typed extents
190  * @ip:         pointer to the inode we do bmap for
191  * @iblock:     logical block
192  *
193  * Description:
194  *   Performs the bmap operation for typed extents.
195  *
196  * Return Value:
197  *   The physical block number on success, else Zero.
198  */
199 static daddr_t
200 vxfs_bmap_typed(struct inode *ip, long iblock)
201 {
202         struct vxfs_inode_info          *vip = VXFS_INO(ip);
203         daddr_t                         pblock = 0;
204         int                             i;
205
206         for (i = 0; i < VXFS_NTYPED; i++) {
207                 struct vxfs_typed       *typ = vip->vii_org.typed + i;
208                 int64_t                 off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
209
210 #ifdef DIAGNOSTIC
211                 vxfs_typdump(typ);
212 #endif
213                 if (iblock < off)
214                         continue;
215                 switch ((u_int32_t)(typ->vt_hdr >> VXFS_TYPED_TYPESHIFT)) {
216                 case VXFS_TYPED_INDIRECT:
217                         pblock = vxfs_bmap_indir(ip, typ->vt_block,
218                                         typ->vt_size, iblock - off);
219                         if (pblock == -2)
220                                 break;
221                         return (pblock);
222                 case VXFS_TYPED_DATA:
223                         if ((iblock - off) < typ->vt_size)
224                                 return (typ->vt_block + iblock - off);
225                         break;
226                 case VXFS_TYPED_INDIRECT_DEV4:
227                 case VXFS_TYPED_DATA_DEV4: {
228                         struct vxfs_typed_dev4  *typ4 =
229                                 (struct vxfs_typed_dev4 *)typ;
230
231                         printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
232                         printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
233                                (unsigned long long) typ4->vd4_block,
234                                (unsigned long long) typ4->vd4_size,
235                                typ4->vd4_dev);
236                         return 0;
237                 }
238                 default:
239                         BUG();
240                 }
241         }
242
243         return 0;
244 }
245
246 /**
247  * vxfs_bmap1 - vxfs-internal bmap operation
248  * @ip:                 pointer to the inode we do bmap for
249  * @iblock:             logical block
250  *
251  * Description:
252  *   vxfs_bmap1 perfoms a logical to physical block mapping
253  *   for vxfs-internal purposes.
254  *
255  * Return Value:
256  *   The physical block number on success, else Zero.
257  */
258 daddr_t
259 vxfs_bmap1(struct inode *ip, long iblock)
260 {
261         struct vxfs_inode_info          *vip = VXFS_INO(ip);
262
263         if (VXFS_ISEXT4(vip))
264                 return vxfs_bmap_ext4(ip, iblock);
265         if (VXFS_ISTYPED(vip))
266                 return vxfs_bmap_typed(ip, iblock);
267         if (VXFS_ISNONE(vip))
268                 goto unsupp;
269         if (VXFS_ISIMMED(vip))
270                 goto unsupp;
271
272         printk(KERN_WARNING "vxfs: inode %ld has no valid orgtype (%x)\n",
273                         ip->i_ino, vip->vii_orgtype);
274         BUG();
275
276 unsupp:
277         printk(KERN_WARNING "vxfs: inode %ld has an unsupported orgtype (%x)\n",
278                         ip->i_ino, vip->vii_orgtype);
279         return 0;
280 }