[GFS2] Update truncate function (shrinking partial blocks)
[linux-block.git] / fs / gfs2 / jdata.c
CommitLineData
b3b94faa
DT
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
f42faf4f
SW
25int 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
b3b94faa
DT
32int 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);
d4e9c4c3 40 gfs2_trans_add_bh(ip->i_gl, bh, 1);
b3b94faa
DT
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
69int 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
90int 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
108static 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
141int 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
227int gfs2_copy_from_mem(struct gfs2_inode *ip, struct buffer_head *bh,
228 const char **buf, unsigned int offset, unsigned int size)
229{
d4e9c4c3 230 gfs2_trans_add_bh(ip->i_gl, bh, 1);
b3b94faa
DT
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
248int 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
d4e9c4c3 253 gfs2_trans_add_bh(ip->i_gl, bh, 1);
b3b94faa
DT
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
262static 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
299int 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
d4e9c4c3 378 gfs2_trans_add_bh(ip->i_gl, dibh, 1);
b3b94faa
DT
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