e43eaf133f10e0ce9200500de568eab1e31f1afc
[pandora-kernel.git] / fs / gfs2 / jdata.c
1 /*
2  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
3  * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
4  *
5  * This copyrighted material is made available to anyone wishing to use,
6  * modify, copy, or redistribute it subject to the terms and conditions
7  * of the GNU General Public License v.2.
8  */
9
10 #include <linux/sched.h>
11 #include <linux/slab.h>
12 #include <linux/spinlock.h>
13 #include <linux/completion.h>
14 #include <linux/buffer_head.h>
15 #include <asm/semaphore.h>
16 #include <asm/uaccess.h>
17
18 #include "gfs2.h"
19 #include "bmap.h"
20 #include "inode.h"
21 #include "jdata.h"
22 #include "meta_io.h"
23 #include "trans.h"
24
25 int gfs2_internal_read(struct gfs2_inode *ip,
26                        struct file_ra_state *ra_state,
27                        char *buf, loff_t *pos, unsigned size)
28 {
29         return gfs2_jdata_read_mem(ip, buf, *pos, size);
30 }
31
32 int gfs2_jdata_get_buffer(struct gfs2_inode *ip, uint64_t block, int new,
33                           struct buffer_head **bhp)
34 {
35         struct buffer_head *bh;
36         int error = 0;
37
38         if (new) {
39                 bh = gfs2_meta_new(ip->i_gl, block);
40                 gfs2_trans_add_bh(ip->i_gl, bh, 1);
41                 gfs2_metatype_set(bh, GFS2_METATYPE_JD, GFS2_FORMAT_JD);
42                 gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
43         } else {
44                 error = gfs2_meta_read(ip->i_gl, block,
45                                        DIO_START | DIO_WAIT, &bh);
46                 if (error)
47                         return error;
48                 if (gfs2_metatype_check(ip->i_sbd, bh, GFS2_METATYPE_JD)) {
49                         brelse(bh);
50                         return -EIO;
51                 }
52         }
53
54         *bhp = bh;
55
56         return 0;
57 }
58
59 /**
60  * gfs2_copy2mem - Trivial copy function for gfs2_jdata_read()
61  * @bh: The buffer to copy from, or NULL meaning zero the buffer
62  * @buf: The buffer to copy/zero
63  * @offset: The offset in the buffer to copy from
64  * @size: The amount of data to copy/zero
65  *
66  * Returns: errno
67  */
68
69 int gfs2_copy2mem(struct buffer_head *bh, char **buf, unsigned int offset,
70                   unsigned int size)
71 {
72         if (bh)
73                 memcpy(*buf, bh->b_data + offset, size);
74         else
75                 memset(*buf, 0, size);
76         *buf += size;
77         return 0;
78 }
79
80 /**
81  * gfs2_copy2user - Copy bytes to user space for gfs2_jdata_read()
82  * @bh: The buffer
83  * @buf: The destination of the data
84  * @offset: The offset into the buffer
85  * @size: The amount of data to copy
86  *
87  * Returns: errno
88  */
89
90 int gfs2_copy2user(struct buffer_head *bh, char **buf, unsigned int offset,
91                    unsigned int size)
92 {
93         int error;
94
95         if (bh)
96                 error = copy_to_user(*buf, bh->b_data + offset, size);
97         else
98                 error = clear_user(*buf, size);
99
100         if (error)
101                 error = -EFAULT;
102         else
103                 *buf += size;
104
105         return error;
106 }
107
108 static int jdata_read_stuffed(struct gfs2_inode *ip, char *buf,
109                               unsigned int offset, unsigned int size,
110                               read_copy_fn_t copy_fn)
111 {
112         struct buffer_head *dibh;
113         int error;
114
115         error = gfs2_meta_inode_buffer(ip, &dibh);
116         if (!error) {
117                 error = copy_fn(dibh, &buf,
118                                 offset + sizeof(struct gfs2_dinode), size);
119                 brelse(dibh);
120         }
121
122         return (error) ? error : size;
123 }
124
125 /**
126  * gfs2_jdata_read - Read a jdata file
127  * @ip: The GFS2 Inode
128  * @buf: The buffer to place result into
129  * @offset: File offset to begin jdata_readng from
130  * @size: Amount of data to transfer
131  * @copy_fn: Function to actually perform the copy
132  *
133  * The @copy_fn only copies a maximum of a single block at once so
134  * we are safe calling it with int arguments. It is done so that
135  * we don't needlessly put 64bit arguments on the stack and it
136  * also makes the code in the @copy_fn nicer too.
137  *
138  * Returns: The amount of data actually copied or the error
139  */
140
141 int gfs2_jdata_read(struct gfs2_inode *ip, char __user *buf, uint64_t offset,
142                     unsigned int size, read_copy_fn_t copy_fn)
143 {
144         struct gfs2_sbd *sdp = ip->i_sbd;
145         uint64_t lblock, dblock;
146         uint32_t extlen = 0;
147         unsigned int o;
148         int copied = 0;
149         int error = 0;
150
151         if (offset >= ip->i_di.di_size)
152                 return 0;
153
154         if ((offset + size) > ip->i_di.di_size)
155                 size = ip->i_di.di_size - offset;
156
157         if (!size)
158                 return 0;
159
160         if (gfs2_is_stuffed(ip))
161                 return jdata_read_stuffed(ip, buf, (unsigned int)offset, size,
162                                           copy_fn);
163
164         if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
165                 return -EINVAL;
166
167         lblock = offset;
168         o = do_div(lblock, sdp->sd_jbsize) +
169                 sizeof(struct gfs2_meta_header);
170
171         while (copied < size) {
172                 unsigned int amount;
173                 struct buffer_head *bh;
174                 int new;
175
176                 amount = size - copied;
177                 if (amount > sdp->sd_sb.sb_bsize - o)
178                         amount = sdp->sd_sb.sb_bsize - o;
179
180                 if (!extlen) {
181                         new = 0;
182                         error = gfs2_block_map(ip, lblock, &new,
183                                                &dblock, &extlen);
184                         if (error)
185                                 goto fail;
186                 }
187
188                 if (extlen > 1)
189                         gfs2_meta_ra(ip->i_gl, dblock, extlen);
190
191                 if (dblock) {
192                         error = gfs2_jdata_get_buffer(ip, dblock, new, &bh);
193                         if (error)
194                                 goto fail;
195                         dblock++;
196                         extlen--;
197                 } else
198                         bh = NULL;
199
200                 error = copy_fn(bh, &buf, o, amount);
201                 brelse(bh);
202                 if (error)
203                         goto fail;
204
205                 copied += amount;
206                 lblock++;
207
208                 o = sizeof(struct gfs2_meta_header);
209         }
210
211         return copied;
212
213  fail:
214         return (copied) ? copied : error;
215 }
216
217 /**
218  * gfs2_copy_from_mem - Trivial copy function for gfs2_jdata_write()
219  * @bh: The buffer to copy to or clear
220  * @buf: The buffer to copy from
221  * @offset: The offset in the buffer to write to
222  * @size: The amount of data to write
223  *
224  * Returns: errno
225  */
226
227 int gfs2_copy_from_mem(struct gfs2_inode *ip, struct buffer_head *bh,
228                        const char **buf, unsigned int offset, unsigned int size)
229 {
230         gfs2_trans_add_bh(ip->i_gl, bh, 1);
231         memcpy(bh->b_data + offset, *buf, size);
232
233         *buf += size;
234
235         return 0;
236 }
237
238 /**
239  * gfs2_copy_from_user - Copy bytes from user space for gfs2_jdata_write()
240  * @bh: The buffer to copy to or clear
241  * @buf: The buffer to copy from
242  * @offset: The offset in the buffer to write to
243  * @size: The amount of data to write
244  *
245  * Returns: errno
246  */
247
248 int gfs2_copy_from_user(struct gfs2_inode *ip, struct buffer_head *bh,
249                         const char __user **buf, unsigned int offset, unsigned int size)
250 {
251         int error = 0;
252
253         gfs2_trans_add_bh(ip->i_gl, bh, 1);
254         if (copy_from_user(bh->b_data + offset, *buf, size))
255                 error = -EFAULT;
256         else
257                 *buf += size;
258
259         return error;
260 }
261
262 static int jdata_write_stuffed(struct gfs2_inode *ip, char *buf,
263                                unsigned int offset, unsigned int size,
264                                write_copy_fn_t copy_fn)
265 {
266         struct buffer_head *dibh;
267         int error;
268
269         error = gfs2_meta_inode_buffer(ip, &dibh);
270         if (error)
271                 return error;
272
273         error = copy_fn(ip,
274                         dibh, &buf,
275                         offset + sizeof(struct gfs2_dinode), size);
276         if (!error) {
277                 if (ip->i_di.di_size < offset + size)
278                         ip->i_di.di_size = offset + size;
279                 ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
280                 gfs2_dinode_out(&ip->i_di, dibh->b_data);
281         }
282
283         brelse(dibh);
284
285         return (error) ? error : size;
286 }
287
288 /**
289  * gfs2_jdata_write - Write bytes to a file
290  * @ip: The GFS2 inode
291  * @buf: The buffer containing information to be written
292  * @offset: The file offset to start writing at
293  * @size: The amount of data to write
294  * @copy_fn: Function to do the actual copying
295  *
296  * Returns: The number of bytes correctly written or error code
297  */
298
299 int gfs2_jdata_write(struct gfs2_inode *ip, const char __user *buf, uint64_t offset,
300                      unsigned int size, write_copy_fn_t copy_fn)
301 {
302         struct gfs2_sbd *sdp = ip->i_sbd;
303         struct buffer_head *dibh;
304         uint64_t lblock, dblock;
305         uint32_t extlen = 0;
306         unsigned int o;
307         int copied = 0;
308         int error = 0;
309
310         if (!size)
311                 return 0;
312
313         if (gfs2_is_stuffed(ip) &&
314             offset + size <= sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode))
315                 return jdata_write_stuffed(ip, buf, (unsigned int)offset, size,
316                                            copy_fn);
317
318         if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
319                 return -EINVAL;
320
321         if (gfs2_is_stuffed(ip)) {
322                 error = gfs2_unstuff_dinode(ip, NULL, NULL);
323                 if (error)
324                         return error;
325         }
326
327         lblock = offset;
328         o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header);
329
330         while (copied < size) {
331                 unsigned int amount;
332                 struct buffer_head *bh;
333                 int new;
334
335                 amount = size - copied;
336                 if (amount > sdp->sd_sb.sb_bsize - o)
337                         amount = sdp->sd_sb.sb_bsize - o;
338
339                 if (!extlen) {
340                         new = 1;
341                         error = gfs2_block_map(ip, lblock, &new,
342                                                &dblock, &extlen);
343                         if (error)
344                                 goto fail;
345                         error = -EIO;
346                         if (gfs2_assert_withdraw(sdp, dblock))
347                                 goto fail;
348                 }
349
350                 error = gfs2_jdata_get_buffer(ip, dblock,
351                                 (amount == sdp->sd_jbsize) ? 1 : new,
352                                 &bh);
353                 if (error)
354                         goto fail;
355
356                 error = copy_fn(ip, bh, &buf, o, amount);
357                 brelse(bh);
358                 if (error)
359                         goto fail;
360
361                 copied += amount;
362                 lblock++;
363                 dblock++;
364                 extlen--;
365
366                 o = sizeof(struct gfs2_meta_header);
367         }
368
369  out:
370         error = gfs2_meta_inode_buffer(ip, &dibh);
371         if (error)
372                 return error;
373
374         if (ip->i_di.di_size < offset + copied)
375                 ip->i_di.di_size = offset + copied;
376         ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
377
378         gfs2_trans_add_bh(ip->i_gl, dibh, 1);
379         gfs2_dinode_out(&ip->i_di, dibh->b_data);
380         brelse(dibh);
381
382         return copied;
383
384  fail:
385         if (copied)
386                 goto out;
387         return error;
388 }
389