diff options
Diffstat (limited to 'fs/gfs2/jdata.c')
-rw-r--r-- | fs/gfs2/jdata.c | 389 |
1 files changed, 0 insertions, 389 deletions
diff --git a/fs/gfs2/jdata.c b/fs/gfs2/jdata.c deleted file mode 100644 index e43eaf133f10..000000000000 --- a/fs/gfs2/jdata.c +++ /dev/null | |||
@@ -1,389 +0,0 @@ | |||
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 | |||