diff options
| -rw-r--r-- | fs/ocfs2/ioctl.c | 128 | ||||
| -rw-r--r-- | fs/ocfs2/ocfs2_ioctl.h | 11 |
2 files changed, 139 insertions, 0 deletions
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c index 373c1d153a9..4216739e163 100644 --- a/fs/ocfs2/ioctl.c +++ b/fs/ocfs2/ioctl.c | |||
| @@ -22,6 +22,9 @@ | |||
| 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" | ||
| 25 | 28 | ||
| 26 | #include <linux/ext2_fs.h> | 29 | #include <linux/ext2_fs.h> |
| 27 | 30 | ||
| @@ -52,6 +55,11 @@ static inline void o2info_clear_request_filled(struct ocfs2_info_request *req) | |||
| 52 | req->ir_flags &= ~OCFS2_INFO_FL_FILLED; | 55 | req->ir_flags &= ~OCFS2_INFO_FL_FILLED; |
| 53 | } | 56 | } |
| 54 | 57 | ||
| 58 | static inline int o2info_coherent(struct ocfs2_info_request *req) | ||
| 59 | { | ||
| 60 | return (!(req->ir_flags & OCFS2_INFO_FL_NON_COHERENT)); | ||
| 61 | } | ||
| 62 | |||
| 55 | static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags) | 63 | static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags) |
| 56 | { | 64 | { |
| 57 | int status; | 65 | int status; |
| @@ -309,6 +317,122 @@ bail: | |||
| 309 | return status; | 317 | return status; |
| 310 | } | 318 | } |
| 311 | 319 | ||
| 320 | int ocfs2_info_scan_inode_alloc(struct ocfs2_super *osb, | ||
| 321 | struct inode *inode_alloc, u64 blkno, | ||
| 322 | struct ocfs2_info_freeinode *fi, u32 slot) | ||
| 323 | { | ||
| 324 | int status = 0, unlock = 0; | ||
| 325 | |||
| 326 | struct buffer_head *bh = NULL; | ||
| 327 | struct ocfs2_dinode *dinode_alloc = NULL; | ||
| 328 | |||
| 329 | if (inode_alloc) | ||
| 330 | mutex_lock(&inode_alloc->i_mutex); | ||
| 331 | |||
| 332 | if (o2info_coherent(&fi->ifi_req)) { | ||
| 333 | status = ocfs2_inode_lock(inode_alloc, &bh, 0); | ||
| 334 | if (status < 0) { | ||
| 335 | mlog_errno(status); | ||
| 336 | goto bail; | ||
| 337 | } | ||
| 338 | unlock = 1; | ||
| 339 | } else { | ||
| 340 | status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); | ||
| 341 | if (status < 0) { | ||
| 342 | mlog_errno(status); | ||
| 343 | goto bail; | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | dinode_alloc = (struct ocfs2_dinode *)bh->b_data; | ||
| 348 | |||
| 349 | fi->ifi_stat[slot].lfi_total = | ||
| 350 | le32_to_cpu(dinode_alloc->id1.bitmap1.i_total); | ||
| 351 | fi->ifi_stat[slot].lfi_free = | ||
| 352 | le32_to_cpu(dinode_alloc->id1.bitmap1.i_total) - | ||
| 353 | le32_to_cpu(dinode_alloc->id1.bitmap1.i_used); | ||
| 354 | |||
| 355 | bail: | ||
| 356 | if (unlock) | ||
| 357 | ocfs2_inode_unlock(inode_alloc, 0); | ||
| 358 | |||
| 359 | if (inode_alloc) | ||
| 360 | mutex_unlock(&inode_alloc->i_mutex); | ||
| 361 | |||
| 362 | brelse(bh); | ||
| 363 | |||
| 364 | return status; | ||
| 365 | } | ||
| 366 | |||
| 367 | int ocfs2_info_handle_freeinode(struct inode *inode, | ||
| 368 | struct ocfs2_info_request __user *req) | ||
| 369 | { | ||
| 370 | u32 i; | ||
| 371 | u64 blkno = -1; | ||
| 372 | char namebuf[40]; | ||
| 373 | int status = -EFAULT, type = INODE_ALLOC_SYSTEM_INODE; | ||
| 374 | struct ocfs2_info_freeinode *oifi = NULL; | ||
| 375 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
| 376 | struct inode *inode_alloc = NULL; | ||
| 377 | |||
| 378 | oifi = kzalloc(sizeof(struct ocfs2_info_freeinode), GFP_KERNEL); | ||
| 379 | if (!oifi) { | ||
| 380 | status = -ENOMEM; | ||
| 381 | mlog_errno(status); | ||
| 382 | goto bail; | ||
| 383 | } | ||
| 384 | |||
| 385 | if (o2info_from_user(*oifi, req)) | ||
| 386 | goto bail; | ||
| 387 | |||
| 388 | oifi->ifi_slotnum = osb->max_slots; | ||
| 389 | |||
| 390 | for (i = 0; i < oifi->ifi_slotnum; i++) { | ||
| 391 | if (o2info_coherent(&oifi->ifi_req)) { | ||
| 392 | inode_alloc = ocfs2_get_system_file_inode(osb, type, i); | ||
| 393 | if (!inode_alloc) { | ||
| 394 | mlog(ML_ERROR, "unable to get alloc inode in " | ||
| 395 | "slot %u\n", i); | ||
| 396 | status = -EIO; | ||
| 397 | goto bail; | ||
| 398 | } | ||
| 399 | } else { | ||
| 400 | ocfs2_sprintf_system_inode_name(namebuf, | ||
| 401 | sizeof(namebuf), | ||
| 402 | type, i); | ||
| 403 | status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, | ||
| 404 | namebuf, | ||
| 405 | strlen(namebuf), | ||
| 406 | &blkno); | ||
| 407 | if (status < 0) { | ||
| 408 | status = -ENOENT; | ||
| 409 | goto bail; | ||
| 410 | } | ||
| 411 | } | ||
| 412 | |||
| 413 | status = ocfs2_info_scan_inode_alloc(osb, inode_alloc, blkno, oifi, i); | ||
| 414 | if (status < 0) | ||
| 415 | goto bail; | ||
| 416 | |||
| 417 | iput(inode_alloc); | ||
| 418 | inode_alloc = NULL; | ||
| 419 | } | ||
| 420 | |||
| 421 | o2info_set_request_filled(&oifi->ifi_req); | ||
| 422 | |||
| 423 | if (o2info_to_user(*oifi, req)) | ||
| 424 | goto bail; | ||
| 425 | |||
| 426 | status = 0; | ||
| 427 | bail: | ||
| 428 | if (status) | ||
| 429 | o2info_set_request_error(&oifi->ifi_req, req); | ||
| 430 | |||
| 431 | kfree(oifi); | ||
| 432 | |||
| 433 | return status; | ||
| 434 | } | ||
| 435 | |||
| 312 | int ocfs2_info_handle_unknown(struct inode *inode, | 436 | int ocfs2_info_handle_unknown(struct inode *inode, |
| 313 | struct ocfs2_info_request __user *req) | 437 | struct ocfs2_info_request __user *req) |
| 314 | { | 438 | { |
| @@ -380,6 +504,10 @@ int ocfs2_info_handle_request(struct inode *inode, | |||
| 380 | if (oir.ir_size == sizeof(struct ocfs2_info_journal_size)) | 504 | if (oir.ir_size == sizeof(struct ocfs2_info_journal_size)) |
| 381 | status = ocfs2_info_handle_journal_size(inode, req); | 505 | status = ocfs2_info_handle_journal_size(inode, req); |
| 382 | break; | 506 | break; |
| 507 | case OCFS2_INFO_FREEINODE: | ||
| 508 | if (oir.ir_size == sizeof(struct ocfs2_info_freeinode)) | ||
| 509 | status = ocfs2_info_handle_freeinode(inode, req); | ||
| 510 | break; | ||
| 383 | default: | 511 | default: |
| 384 | status = ocfs2_info_handle_unknown(inode, req); | 512 | status = ocfs2_info_handle_unknown(inode, req); |
| 385 | break; | 513 | break; |
diff --git a/fs/ocfs2/ocfs2_ioctl.h b/fs/ocfs2/ocfs2_ioctl.h index b46f39bf743..6b4b39a8366 100644 --- a/fs/ocfs2/ocfs2_ioctl.h +++ b/fs/ocfs2/ocfs2_ioctl.h | |||
| @@ -142,6 +142,16 @@ struct ocfs2_info_journal_size { | |||
| 142 | __u64 ij_journal_size; | 142 | __u64 ij_journal_size; |
| 143 | }; | 143 | }; |
| 144 | 144 | ||
| 145 | struct ocfs2_info_freeinode { | ||
| 146 | struct ocfs2_info_request ifi_req; | ||
| 147 | struct ocfs2_info_local_freeinode { | ||
| 148 | __u64 lfi_total; | ||
| 149 | __u64 lfi_free; | ||
| 150 | } ifi_stat[OCFS2_MAX_SLOTS]; | ||
| 151 | __u32 ifi_slotnum; /* out */ | ||
| 152 | __u32 ifi_pad; | ||
| 153 | }; | ||
| 154 | |||
| 145 | /* Codes for ocfs2_info_request */ | 155 | /* Codes for ocfs2_info_request */ |
| 146 | enum ocfs2_info_type { | 156 | enum ocfs2_info_type { |
| 147 | OCFS2_INFO_CLUSTERSIZE = 1, | 157 | OCFS2_INFO_CLUSTERSIZE = 1, |
| @@ -151,6 +161,7 @@ enum ocfs2_info_type { | |||
| 151 | OCFS2_INFO_UUID, | 161 | OCFS2_INFO_UUID, |
| 152 | OCFS2_INFO_FS_FEATURES, | 162 | OCFS2_INFO_FS_FEATURES, |
| 153 | OCFS2_INFO_JOURNAL_SIZE, | 163 | OCFS2_INFO_JOURNAL_SIZE, |
| 164 | OCFS2_INFO_FREEINODE, | ||
| 154 | OCFS2_INFO_NUM_TYPES | 165 | OCFS2_INFO_NUM_TYPES |
| 155 | }; | 166 | }; |
| 156 | 167 | ||
