diff options
author | Joel Becker <jlbec@evilplan.org> | 2011-05-26 00:51:55 -0400 |
---|---|---|
committer | Joel Becker <jlbec@evilplan.org> | 2011-05-26 00:51:55 -0400 |
commit | ece928df16494becd43f999aff9bd530182e7e81 (patch) | |
tree | 905042764ea5d8ab6eda63666406e19f607bcf4c /fs/ocfs2/ioctl.c | |
parent | 3d1c1829ebe7e8bb48a997b39b4865abc9197e5e (diff) | |
parent | dda54e76d7dba0532ebdd72e0b4f492a03f83225 (diff) |
Merge branch 'move_extents' of git://oss.oracle.com/git/tye/linux-2.6 into ocfs2-merge-window
Conflicts:
fs/ocfs2/ioctl.c
Diffstat (limited to 'fs/ocfs2/ioctl.c')
-rw-r--r-- | fs/ocfs2/ioctl.c | 468 |
1 files changed, 441 insertions, 27 deletions
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c index 312a28f433a4..bc91072b7219 100644 --- a/fs/ocfs2/ioctl.c +++ b/fs/ocfs2/ioctl.c | |||
@@ -22,6 +22,11 @@ | |||
22 | #include "ioctl.h" | 22 | #include "ioctl.h" |
23 | #include "resize.h" | 23 | #include "resize.h" |
24 | #include "refcounttree.h" | 24 | #include "refcounttree.h" |
25 | #include "sysfile.h" | ||
26 | #include "dir.h" | ||
27 | #include "buffer_head_io.h" | ||
28 | #include "suballoc.h" | ||
29 | #include "move_extents.h" | ||
25 | 30 | ||
26 | #include <linux/ext2_fs.h> | 31 | #include <linux/ext2_fs.h> |
27 | 32 | ||
@@ -35,31 +40,27 @@ | |||
35 | * be -EFAULT. The error will be returned from the ioctl(2) call. It's | 40 | * be -EFAULT. The error will be returned from the ioctl(2) call. It's |
36 | * just a best-effort to tell userspace that this request caused the error. | 41 | * just a best-effort to tell userspace that this request caused the error. |
37 | */ | 42 | */ |
38 | static inline void __o2info_set_request_error(struct ocfs2_info_request *kreq, | 43 | static inline void o2info_set_request_error(struct ocfs2_info_request *kreq, |
39 | struct ocfs2_info_request __user *req) | 44 | struct ocfs2_info_request __user *req) |
40 | { | 45 | { |
41 | kreq->ir_flags |= OCFS2_INFO_FL_ERROR; | 46 | kreq->ir_flags |= OCFS2_INFO_FL_ERROR; |
42 | (void)put_user(kreq->ir_flags, (__u32 __user *)&(req->ir_flags)); | 47 | (void)put_user(kreq->ir_flags, (__u32 __user *)&(req->ir_flags)); |
43 | } | 48 | } |
44 | 49 | ||
45 | #define o2info_set_request_error(a, b) \ | 50 | static inline void o2info_set_request_filled(struct ocfs2_info_request *req) |
46 | __o2info_set_request_error((struct ocfs2_info_request *)&(a), b) | ||
47 | |||
48 | static inline void __o2info_set_request_filled(struct ocfs2_info_request *req) | ||
49 | { | 51 | { |
50 | req->ir_flags |= OCFS2_INFO_FL_FILLED; | 52 | req->ir_flags |= OCFS2_INFO_FL_FILLED; |
51 | } | 53 | } |
52 | 54 | ||
53 | #define o2info_set_request_filled(a) \ | 55 | static inline void o2info_clear_request_filled(struct ocfs2_info_request *req) |
54 | __o2info_set_request_filled((struct ocfs2_info_request *)&(a)) | ||
55 | |||
56 | static inline void __o2info_clear_request_filled(struct ocfs2_info_request *req) | ||
57 | { | 56 | { |
58 | req->ir_flags &= ~OCFS2_INFO_FL_FILLED; | 57 | req->ir_flags &= ~OCFS2_INFO_FL_FILLED; |
59 | } | 58 | } |
60 | 59 | ||
61 | #define o2info_clear_request_filled(a) \ | 60 | static inline int o2info_coherent(struct ocfs2_info_request *req) |
62 | __o2info_clear_request_filled((struct ocfs2_info_request *)&(a)) | 61 | { |
62 | return (!(req->ir_flags & OCFS2_INFO_FL_NON_COHERENT)); | ||
63 | } | ||
63 | 64 | ||
64 | static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags) | 65 | static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags) |
65 | { | 66 | { |
@@ -153,7 +154,7 @@ int ocfs2_info_handle_blocksize(struct inode *inode, | |||
153 | 154 | ||
154 | oib.ib_blocksize = inode->i_sb->s_blocksize; | 155 | oib.ib_blocksize = inode->i_sb->s_blocksize; |
155 | 156 | ||
156 | o2info_set_request_filled(oib); | 157 | o2info_set_request_filled(&oib.ib_req); |
157 | 158 | ||
158 | if (o2info_to_user(oib, req)) | 159 | if (o2info_to_user(oib, req)) |
159 | goto bail; | 160 | goto bail; |
@@ -161,7 +162,7 @@ int ocfs2_info_handle_blocksize(struct inode *inode, | |||
161 | status = 0; | 162 | status = 0; |
162 | bail: | 163 | bail: |
163 | if (status) | 164 | if (status) |
164 | o2info_set_request_error(oib, req); | 165 | o2info_set_request_error(&oib.ib_req, req); |
165 | 166 | ||
166 | return status; | 167 | return status; |
167 | } | 168 | } |
@@ -178,7 +179,7 @@ int ocfs2_info_handle_clustersize(struct inode *inode, | |||
178 | 179 | ||
179 | oic.ic_clustersize = osb->s_clustersize; | 180 | oic.ic_clustersize = osb->s_clustersize; |
180 | 181 | ||
181 | o2info_set_request_filled(oic); | 182 | o2info_set_request_filled(&oic.ic_req); |
182 | 183 | ||
183 | if (o2info_to_user(oic, req)) | 184 | if (o2info_to_user(oic, req)) |
184 | goto bail; | 185 | goto bail; |
@@ -186,7 +187,7 @@ int ocfs2_info_handle_clustersize(struct inode *inode, | |||
186 | status = 0; | 187 | status = 0; |
187 | bail: | 188 | bail: |
188 | if (status) | 189 | if (status) |
189 | o2info_set_request_error(oic, req); | 190 | o2info_set_request_error(&oic.ic_req, req); |
190 | 191 | ||
191 | return status; | 192 | return status; |
192 | } | 193 | } |
@@ -203,7 +204,7 @@ int ocfs2_info_handle_maxslots(struct inode *inode, | |||
203 | 204 | ||
204 | oim.im_max_slots = osb->max_slots; | 205 | oim.im_max_slots = osb->max_slots; |
205 | 206 | ||
206 | o2info_set_request_filled(oim); | 207 | o2info_set_request_filled(&oim.im_req); |
207 | 208 | ||
208 | if (o2info_to_user(oim, req)) | 209 | if (o2info_to_user(oim, req)) |
209 | goto bail; | 210 | goto bail; |
@@ -211,7 +212,7 @@ int ocfs2_info_handle_maxslots(struct inode *inode, | |||
211 | status = 0; | 212 | status = 0; |
212 | bail: | 213 | bail: |
213 | if (status) | 214 | if (status) |
214 | o2info_set_request_error(oim, req); | 215 | o2info_set_request_error(&oim.im_req, req); |
215 | 216 | ||
216 | return status; | 217 | return status; |
217 | } | 218 | } |
@@ -228,7 +229,7 @@ int ocfs2_info_handle_label(struct inode *inode, | |||
228 | 229 | ||
229 | memcpy(oil.il_label, osb->vol_label, OCFS2_MAX_VOL_LABEL_LEN); | 230 | memcpy(oil.il_label, osb->vol_label, OCFS2_MAX_VOL_LABEL_LEN); |
230 | 231 | ||
231 | o2info_set_request_filled(oil); | 232 | o2info_set_request_filled(&oil.il_req); |
232 | 233 | ||
233 | if (o2info_to_user(oil, req)) | 234 | if (o2info_to_user(oil, req)) |
234 | goto bail; | 235 | goto bail; |
@@ -236,7 +237,7 @@ int ocfs2_info_handle_label(struct inode *inode, | |||
236 | status = 0; | 237 | status = 0; |
237 | bail: | 238 | bail: |
238 | if (status) | 239 | if (status) |
239 | o2info_set_request_error(oil, req); | 240 | o2info_set_request_error(&oil.il_req, req); |
240 | 241 | ||
241 | return status; | 242 | return status; |
242 | } | 243 | } |
@@ -253,7 +254,7 @@ int ocfs2_info_handle_uuid(struct inode *inode, | |||
253 | 254 | ||
254 | memcpy(oiu.iu_uuid_str, osb->uuid_str, OCFS2_TEXT_UUID_LEN + 1); | 255 | memcpy(oiu.iu_uuid_str, osb->uuid_str, OCFS2_TEXT_UUID_LEN + 1); |
255 | 256 | ||
256 | o2info_set_request_filled(oiu); | 257 | o2info_set_request_filled(&oiu.iu_req); |
257 | 258 | ||
258 | if (o2info_to_user(oiu, req)) | 259 | if (o2info_to_user(oiu, req)) |
259 | goto bail; | 260 | goto bail; |
@@ -261,7 +262,7 @@ int ocfs2_info_handle_uuid(struct inode *inode, | |||
261 | status = 0; | 262 | status = 0; |
262 | bail: | 263 | bail: |
263 | if (status) | 264 | if (status) |
264 | o2info_set_request_error(oiu, req); | 265 | o2info_set_request_error(&oiu.iu_req, req); |
265 | 266 | ||
266 | return status; | 267 | return status; |
267 | } | 268 | } |
@@ -280,7 +281,7 @@ int ocfs2_info_handle_fs_features(struct inode *inode, | |||
280 | oif.if_incompat_features = osb->s_feature_incompat; | 281 | oif.if_incompat_features = osb->s_feature_incompat; |
281 | oif.if_ro_compat_features = osb->s_feature_ro_compat; | 282 | oif.if_ro_compat_features = osb->s_feature_ro_compat; |
282 | 283 | ||
283 | o2info_set_request_filled(oif); | 284 | o2info_set_request_filled(&oif.if_req); |
284 | 285 | ||
285 | if (o2info_to_user(oif, req)) | 286 | if (o2info_to_user(oif, req)) |
286 | goto bail; | 287 | goto bail; |
@@ -288,7 +289,7 @@ int ocfs2_info_handle_fs_features(struct inode *inode, | |||
288 | status = 0; | 289 | status = 0; |
289 | bail: | 290 | bail: |
290 | if (status) | 291 | if (status) |
291 | o2info_set_request_error(oif, req); | 292 | o2info_set_request_error(&oif.if_req, req); |
292 | 293 | ||
293 | return status; | 294 | return status; |
294 | } | 295 | } |
@@ -305,7 +306,7 @@ int ocfs2_info_handle_journal_size(struct inode *inode, | |||
305 | 306 | ||
306 | oij.ij_journal_size = osb->journal->j_inode->i_size; | 307 | oij.ij_journal_size = osb->journal->j_inode->i_size; |
307 | 308 | ||
308 | o2info_set_request_filled(oij); | 309 | o2info_set_request_filled(&oij.ij_req); |
309 | 310 | ||
310 | if (o2info_to_user(oij, req)) | 311 | if (o2info_to_user(oij, req)) |
311 | goto bail; | 312 | goto bail; |
@@ -313,7 +314,408 @@ int ocfs2_info_handle_journal_size(struct inode *inode, | |||
313 | status = 0; | 314 | status = 0; |
314 | bail: | 315 | bail: |
315 | if (status) | 316 | if (status) |
316 | o2info_set_request_error(oij, req); | 317 | o2info_set_request_error(&oij.ij_req, req); |
318 | |||
319 | return status; | ||
320 | } | ||
321 | |||
322 | int ocfs2_info_scan_inode_alloc(struct ocfs2_super *osb, | ||
323 | struct inode *inode_alloc, u64 blkno, | ||
324 | struct ocfs2_info_freeinode *fi, u32 slot) | ||
325 | { | ||
326 | int status = 0, unlock = 0; | ||
327 | |||
328 | struct buffer_head *bh = NULL; | ||
329 | struct ocfs2_dinode *dinode_alloc = NULL; | ||
330 | |||
331 | if (inode_alloc) | ||
332 | mutex_lock(&inode_alloc->i_mutex); | ||
333 | |||
334 | if (o2info_coherent(&fi->ifi_req)) { | ||
335 | status = ocfs2_inode_lock(inode_alloc, &bh, 0); | ||
336 | if (status < 0) { | ||
337 | mlog_errno(status); | ||
338 | goto bail; | ||
339 | } | ||
340 | unlock = 1; | ||
341 | } else { | ||
342 | status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); | ||
343 | if (status < 0) { | ||
344 | mlog_errno(status); | ||
345 | goto bail; | ||
346 | } | ||
347 | } | ||
348 | |||
349 | dinode_alloc = (struct ocfs2_dinode *)bh->b_data; | ||
350 | |||
351 | fi->ifi_stat[slot].lfi_total = | ||
352 | le32_to_cpu(dinode_alloc->id1.bitmap1.i_total); | ||
353 | fi->ifi_stat[slot].lfi_free = | ||
354 | le32_to_cpu(dinode_alloc->id1.bitmap1.i_total) - | ||
355 | le32_to_cpu(dinode_alloc->id1.bitmap1.i_used); | ||
356 | |||
357 | bail: | ||
358 | if (unlock) | ||
359 | ocfs2_inode_unlock(inode_alloc, 0); | ||
360 | |||
361 | if (inode_alloc) | ||
362 | mutex_unlock(&inode_alloc->i_mutex); | ||
363 | |||
364 | brelse(bh); | ||
365 | |||
366 | return status; | ||
367 | } | ||
368 | |||
369 | int ocfs2_info_handle_freeinode(struct inode *inode, | ||
370 | struct ocfs2_info_request __user *req) | ||
371 | { | ||
372 | u32 i; | ||
373 | u64 blkno = -1; | ||
374 | char namebuf[40]; | ||
375 | int status = -EFAULT, type = INODE_ALLOC_SYSTEM_INODE; | ||
376 | struct ocfs2_info_freeinode *oifi = NULL; | ||
377 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
378 | struct inode *inode_alloc = NULL; | ||
379 | |||
380 | oifi = kzalloc(sizeof(struct ocfs2_info_freeinode), GFP_KERNEL); | ||
381 | if (!oifi) { | ||
382 | status = -ENOMEM; | ||
383 | mlog_errno(status); | ||
384 | goto bail; | ||
385 | } | ||
386 | |||
387 | if (o2info_from_user(*oifi, req)) | ||
388 | goto bail; | ||
389 | |||
390 | oifi->ifi_slotnum = osb->max_slots; | ||
391 | |||
392 | for (i = 0; i < oifi->ifi_slotnum; i++) { | ||
393 | if (o2info_coherent(&oifi->ifi_req)) { | ||
394 | inode_alloc = ocfs2_get_system_file_inode(osb, type, i); | ||
395 | if (!inode_alloc) { | ||
396 | mlog(ML_ERROR, "unable to get alloc inode in " | ||
397 | "slot %u\n", i); | ||
398 | status = -EIO; | ||
399 | goto bail; | ||
400 | } | ||
401 | } else { | ||
402 | ocfs2_sprintf_system_inode_name(namebuf, | ||
403 | sizeof(namebuf), | ||
404 | type, i); | ||
405 | status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, | ||
406 | namebuf, | ||
407 | strlen(namebuf), | ||
408 | &blkno); | ||
409 | if (status < 0) { | ||
410 | status = -ENOENT; | ||
411 | goto bail; | ||
412 | } | ||
413 | } | ||
414 | |||
415 | status = ocfs2_info_scan_inode_alloc(osb, inode_alloc, blkno, oifi, i); | ||
416 | if (status < 0) | ||
417 | goto bail; | ||
418 | |||
419 | iput(inode_alloc); | ||
420 | inode_alloc = NULL; | ||
421 | } | ||
422 | |||
423 | o2info_set_request_filled(&oifi->ifi_req); | ||
424 | |||
425 | if (o2info_to_user(*oifi, req)) | ||
426 | goto bail; | ||
427 | |||
428 | status = 0; | ||
429 | bail: | ||
430 | if (status) | ||
431 | o2info_set_request_error(&oifi->ifi_req, req); | ||
432 | |||
433 | kfree(oifi); | ||
434 | |||
435 | return status; | ||
436 | } | ||
437 | |||
438 | static void o2ffg_update_histogram(struct ocfs2_info_free_chunk_list *hist, | ||
439 | unsigned int chunksize) | ||
440 | { | ||
441 | int index; | ||
442 | |||
443 | index = __ilog2_u32(chunksize); | ||
444 | if (index >= OCFS2_INFO_MAX_HIST) | ||
445 | index = OCFS2_INFO_MAX_HIST - 1; | ||
446 | |||
447 | hist->fc_chunks[index]++; | ||
448 | hist->fc_clusters[index] += chunksize; | ||
449 | } | ||
450 | |||
451 | static void o2ffg_update_stats(struct ocfs2_info_freefrag_stats *stats, | ||
452 | unsigned int chunksize) | ||
453 | { | ||
454 | if (chunksize > stats->ffs_max) | ||
455 | stats->ffs_max = chunksize; | ||
456 | |||
457 | if (chunksize < stats->ffs_min) | ||
458 | stats->ffs_min = chunksize; | ||
459 | |||
460 | stats->ffs_avg += chunksize; | ||
461 | stats->ffs_free_chunks_real++; | ||
462 | } | ||
463 | |||
464 | void ocfs2_info_update_ffg(struct ocfs2_info_freefrag *ffg, | ||
465 | unsigned int chunksize) | ||
466 | { | ||
467 | o2ffg_update_histogram(&(ffg->iff_ffs.ffs_fc_hist), chunksize); | ||
468 | o2ffg_update_stats(&(ffg->iff_ffs), chunksize); | ||
469 | } | ||
470 | |||
471 | int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, | ||
472 | struct inode *gb_inode, | ||
473 | struct ocfs2_dinode *gb_dinode, | ||
474 | struct ocfs2_chain_rec *rec, | ||
475 | struct ocfs2_info_freefrag *ffg, | ||
476 | u32 chunks_in_group) | ||
477 | { | ||
478 | int status = 0, used; | ||
479 | u64 blkno; | ||
480 | |||
481 | struct buffer_head *bh = NULL; | ||
482 | struct ocfs2_group_desc *bg = NULL; | ||
483 | |||
484 | unsigned int max_bits, num_clusters; | ||
485 | unsigned int offset = 0, cluster, chunk; | ||
486 | unsigned int chunk_free, last_chunksize = 0; | ||
487 | |||
488 | if (!le32_to_cpu(rec->c_free)) | ||
489 | goto bail; | ||
490 | |||
491 | do { | ||
492 | if (!bg) | ||
493 | blkno = le64_to_cpu(rec->c_blkno); | ||
494 | else | ||
495 | blkno = le64_to_cpu(bg->bg_next_group); | ||
496 | |||
497 | if (bh) { | ||
498 | brelse(bh); | ||
499 | bh = NULL; | ||
500 | } | ||
501 | |||
502 | if (o2info_coherent(&ffg->iff_req)) | ||
503 | status = ocfs2_read_group_descriptor(gb_inode, | ||
504 | gb_dinode, | ||
505 | blkno, &bh); | ||
506 | else | ||
507 | status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); | ||
508 | |||
509 | if (status < 0) { | ||
510 | mlog(ML_ERROR, "Can't read the group descriptor # " | ||
511 | "%llu from device.", (unsigned long long)blkno); | ||
512 | status = -EIO; | ||
513 | goto bail; | ||
514 | } | ||
515 | |||
516 | bg = (struct ocfs2_group_desc *)bh->b_data; | ||
517 | |||
518 | if (!le16_to_cpu(bg->bg_free_bits_count)) | ||
519 | continue; | ||
520 | |||
521 | max_bits = le16_to_cpu(bg->bg_bits); | ||
522 | offset = 0; | ||
523 | |||
524 | for (chunk = 0; chunk < chunks_in_group; chunk++) { | ||
525 | /* | ||
526 | * last chunk may be not an entire one. | ||
527 | */ | ||
528 | if ((offset + ffg->iff_chunksize) > max_bits) | ||
529 | num_clusters = max_bits - offset; | ||
530 | else | ||
531 | num_clusters = ffg->iff_chunksize; | ||
532 | |||
533 | chunk_free = 0; | ||
534 | for (cluster = 0; cluster < num_clusters; cluster++) { | ||
535 | used = ocfs2_test_bit(offset, | ||
536 | (unsigned long *)bg->bg_bitmap); | ||
537 | /* | ||
538 | * - chunk_free counts free clusters in #N chunk. | ||
539 | * - last_chunksize records the size(in) clusters | ||
540 | * for the last real free chunk being counted. | ||
541 | */ | ||
542 | if (!used) { | ||
543 | last_chunksize++; | ||
544 | chunk_free++; | ||
545 | } | ||
546 | |||
547 | if (used && last_chunksize) { | ||
548 | ocfs2_info_update_ffg(ffg, | ||
549 | last_chunksize); | ||
550 | last_chunksize = 0; | ||
551 | } | ||
552 | |||
553 | offset++; | ||
554 | } | ||
555 | |||
556 | if (chunk_free == ffg->iff_chunksize) | ||
557 | ffg->iff_ffs.ffs_free_chunks++; | ||
558 | } | ||
559 | |||
560 | /* | ||
561 | * need to update the info for last free chunk. | ||
562 | */ | ||
563 | if (last_chunksize) | ||
564 | ocfs2_info_update_ffg(ffg, last_chunksize); | ||
565 | |||
566 | } while (le64_to_cpu(bg->bg_next_group)); | ||
567 | |||
568 | bail: | ||
569 | brelse(bh); | ||
570 | |||
571 | return status; | ||
572 | } | ||
573 | |||
574 | int ocfs2_info_freefrag_scan_bitmap(struct ocfs2_super *osb, | ||
575 | struct inode *gb_inode, u64 blkno, | ||
576 | struct ocfs2_info_freefrag *ffg) | ||
577 | { | ||
578 | u32 chunks_in_group; | ||
579 | int status = 0, unlock = 0, i; | ||
580 | |||
581 | struct buffer_head *bh = NULL; | ||
582 | struct ocfs2_chain_list *cl = NULL; | ||
583 | struct ocfs2_chain_rec *rec = NULL; | ||
584 | struct ocfs2_dinode *gb_dinode = NULL; | ||
585 | |||
586 | if (gb_inode) | ||
587 | mutex_lock(&gb_inode->i_mutex); | ||
588 | |||
589 | if (o2info_coherent(&ffg->iff_req)) { | ||
590 | status = ocfs2_inode_lock(gb_inode, &bh, 0); | ||
591 | if (status < 0) { | ||
592 | mlog_errno(status); | ||
593 | goto bail; | ||
594 | } | ||
595 | unlock = 1; | ||
596 | } else { | ||
597 | status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); | ||
598 | if (status < 0) { | ||
599 | mlog_errno(status); | ||
600 | goto bail; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | gb_dinode = (struct ocfs2_dinode *)bh->b_data; | ||
605 | cl = &(gb_dinode->id2.i_chain); | ||
606 | |||
607 | /* | ||
608 | * Chunksize(in) clusters from userspace should be | ||
609 | * less than clusters in a group. | ||
610 | */ | ||
611 | if (ffg->iff_chunksize > le16_to_cpu(cl->cl_cpg)) { | ||
612 | status = -EINVAL; | ||
613 | goto bail; | ||
614 | } | ||
615 | |||
616 | memset(&ffg->iff_ffs, 0, sizeof(struct ocfs2_info_freefrag_stats)); | ||
617 | |||
618 | ffg->iff_ffs.ffs_min = ~0U; | ||
619 | ffg->iff_ffs.ffs_clusters = | ||
620 | le32_to_cpu(gb_dinode->id1.bitmap1.i_total); | ||
621 | ffg->iff_ffs.ffs_free_clusters = ffg->iff_ffs.ffs_clusters - | ||
622 | le32_to_cpu(gb_dinode->id1.bitmap1.i_used); | ||
623 | |||
624 | chunks_in_group = le16_to_cpu(cl->cl_cpg) / ffg->iff_chunksize + 1; | ||
625 | |||
626 | for (i = 0; i < le16_to_cpu(cl->cl_next_free_rec); i++) { | ||
627 | rec = &(cl->cl_recs[i]); | ||
628 | status = ocfs2_info_freefrag_scan_chain(osb, gb_inode, | ||
629 | gb_dinode, | ||
630 | rec, ffg, | ||
631 | chunks_in_group); | ||
632 | if (status) | ||
633 | goto bail; | ||
634 | } | ||
635 | |||
636 | if (ffg->iff_ffs.ffs_free_chunks_real) | ||
637 | ffg->iff_ffs.ffs_avg = (ffg->iff_ffs.ffs_avg / | ||
638 | ffg->iff_ffs.ffs_free_chunks_real); | ||
639 | bail: | ||
640 | if (unlock) | ||
641 | ocfs2_inode_unlock(gb_inode, 0); | ||
642 | |||
643 | if (gb_inode) | ||
644 | mutex_unlock(&gb_inode->i_mutex); | ||
645 | |||
646 | if (gb_inode) | ||
647 | iput(gb_inode); | ||
648 | |||
649 | brelse(bh); | ||
650 | |||
651 | return status; | ||
652 | } | ||
653 | |||
654 | int ocfs2_info_handle_freefrag(struct inode *inode, | ||
655 | struct ocfs2_info_request __user *req) | ||
656 | { | ||
657 | u64 blkno = -1; | ||
658 | char namebuf[40]; | ||
659 | int status = -EFAULT, type = GLOBAL_BITMAP_SYSTEM_INODE; | ||
660 | |||
661 | struct ocfs2_info_freefrag *oiff; | ||
662 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
663 | struct inode *gb_inode = NULL; | ||
664 | |||
665 | oiff = kzalloc(sizeof(struct ocfs2_info_freefrag), GFP_KERNEL); | ||
666 | if (!oiff) { | ||
667 | status = -ENOMEM; | ||
668 | mlog_errno(status); | ||
669 | goto bail; | ||
670 | } | ||
671 | |||
672 | if (o2info_from_user(*oiff, req)) | ||
673 | goto bail; | ||
674 | /* | ||
675 | * chunksize from userspace should be power of 2. | ||
676 | */ | ||
677 | if ((oiff->iff_chunksize & (oiff->iff_chunksize - 1)) || | ||
678 | (!oiff->iff_chunksize)) { | ||
679 | status = -EINVAL; | ||
680 | goto bail; | ||
681 | } | ||
682 | |||
683 | if (o2info_coherent(&oiff->iff_req)) { | ||
684 | gb_inode = ocfs2_get_system_file_inode(osb, type, | ||
685 | OCFS2_INVALID_SLOT); | ||
686 | if (!gb_inode) { | ||
687 | mlog(ML_ERROR, "unable to get global_bitmap inode\n"); | ||
688 | status = -EIO; | ||
689 | goto bail; | ||
690 | } | ||
691 | } else { | ||
692 | ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type, | ||
693 | OCFS2_INVALID_SLOT); | ||
694 | status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, | ||
695 | namebuf, | ||
696 | strlen(namebuf), | ||
697 | &blkno); | ||
698 | if (status < 0) { | ||
699 | status = -ENOENT; | ||
700 | goto bail; | ||
701 | } | ||
702 | } | ||
703 | |||
704 | status = ocfs2_info_freefrag_scan_bitmap(osb, gb_inode, blkno, oiff); | ||
705 | if (status < 0) | ||
706 | goto bail; | ||
707 | |||
708 | o2info_set_request_filled(&oiff->iff_req); | ||
709 | |||
710 | if (o2info_to_user(*oiff, req)) | ||
711 | goto bail; | ||
712 | |||
713 | status = 0; | ||
714 | bail: | ||
715 | if (status) | ||
716 | o2info_set_request_error(&oiff->iff_req, req); | ||
717 | |||
718 | kfree(oiff); | ||
317 | 719 | ||
318 | return status; | 720 | return status; |
319 | } | 721 | } |
@@ -327,7 +729,7 @@ int ocfs2_info_handle_unknown(struct inode *inode, | |||
327 | if (o2info_from_user(oir, req)) | 729 | if (o2info_from_user(oir, req)) |
328 | goto bail; | 730 | goto bail; |
329 | 731 | ||
330 | o2info_clear_request_filled(oir); | 732 | o2info_clear_request_filled(&oir); |
331 | 733 | ||
332 | if (o2info_to_user(oir, req)) | 734 | if (o2info_to_user(oir, req)) |
333 | goto bail; | 735 | goto bail; |
@@ -335,7 +737,7 @@ int ocfs2_info_handle_unknown(struct inode *inode, | |||
335 | status = 0; | 737 | status = 0; |
336 | bail: | 738 | bail: |
337 | if (status) | 739 | if (status) |
338 | o2info_set_request_error(oir, req); | 740 | o2info_set_request_error(&oir, req); |
339 | 741 | ||
340 | return status; | 742 | return status; |
341 | } | 743 | } |
@@ -389,6 +791,14 @@ int ocfs2_info_handle_request(struct inode *inode, | |||
389 | if (oir.ir_size == sizeof(struct ocfs2_info_journal_size)) | 791 | if (oir.ir_size == sizeof(struct ocfs2_info_journal_size)) |
390 | status = ocfs2_info_handle_journal_size(inode, req); | 792 | status = ocfs2_info_handle_journal_size(inode, req); |
391 | break; | 793 | break; |
794 | case OCFS2_INFO_FREEINODE: | ||
795 | if (oir.ir_size == sizeof(struct ocfs2_info_freeinode)) | ||
796 | status = ocfs2_info_handle_freeinode(inode, req); | ||
797 | break; | ||
798 | case OCFS2_INFO_FREEFRAG: | ||
799 | if (oir.ir_size == sizeof(struct ocfs2_info_freefrag)) | ||
800 | status = ocfs2_info_handle_freefrag(inode, req); | ||
801 | break; | ||
392 | default: | 802 | default: |
393 | status = ocfs2_info_handle_unknown(inode, req); | 803 | status = ocfs2_info_handle_unknown(inode, req); |
394 | break; | 804 | break; |
@@ -565,6 +975,8 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
565 | 975 | ||
566 | return 0; | 976 | return 0; |
567 | } | 977 | } |
978 | case OCFS2_IOC_MOVE_EXT: | ||
979 | return ocfs2_ioctl_move_extents(filp, (void __user *)arg); | ||
568 | default: | 980 | default: |
569 | return -ENOTTY; | 981 | return -ENOTTY; |
570 | } | 982 | } |
@@ -608,6 +1020,8 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
608 | return -EFAULT; | 1020 | return -EFAULT; |
609 | 1021 | ||
610 | return ocfs2_info_handle(inode, &info, 1); | 1022 | return ocfs2_info_handle(inode, &info, 1); |
1023 | case OCFS2_IOC_MOVE_EXT: | ||
1024 | break; | ||
611 | default: | 1025 | default: |
612 | return -ENOIOCTLCMD; | 1026 | return -ENOIOCTLCMD; |
613 | } | 1027 | } |