1ca4d147eSHerbert Poetzl /* 2ca4d147eSHerbert Poetzl * linux/fs/ocfs2/ioctl.c 3ca4d147eSHerbert Poetzl * 4ca4d147eSHerbert Poetzl * Copyright (C) 2006 Herbert Poetzl 5ca4d147eSHerbert Poetzl * adapted from Remy Card's ext2/ioctl.c 6ca4d147eSHerbert Poetzl */ 7ca4d147eSHerbert Poetzl 8ca4d147eSHerbert Poetzl #include <linux/fs.h> 9ca4d147eSHerbert Poetzl #include <linux/mount.h> 1034e6c59aSTao Ma #include <linux/compat.h> 11ca4d147eSHerbert Poetzl 12ca4d147eSHerbert Poetzl #include <cluster/masklog.h> 13ca4d147eSHerbert Poetzl 14ca4d147eSHerbert Poetzl #include "ocfs2.h" 15ca4d147eSHerbert Poetzl #include "alloc.h" 16ca4d147eSHerbert Poetzl #include "dlmglue.h" 17b2580103SMark Fasheh #include "file.h" 18ca4d147eSHerbert Poetzl #include "inode.h" 19ca4d147eSHerbert Poetzl #include "journal.h" 20ca4d147eSHerbert Poetzl 21ca4d147eSHerbert Poetzl #include "ocfs2_fs.h" 222d562518SAdrian Bunk #include "ioctl.h" 23d659072fSTao Ma #include "resize.h" 24bd50873dSTao Ma #include "refcounttree.h" 253e5db17dSTristan Ye #include "sysfile.h" 263e5db17dSTristan Ye #include "dir.h" 273e5db17dSTristan Ye #include "buffer_head_io.h" 28d24a10b9STristan Ye #include "suballoc.h" 2953069d4eSTristan Ye #include "move_extents.h" 302d562518SAdrian Bunk 31ca4d147eSHerbert Poetzl #include <linux/ext2_fs.h> 32ca4d147eSHerbert Poetzl 33ddee5cdbSTristan Ye #define o2info_from_user(a, b) \ 34ddee5cdbSTristan Ye copy_from_user(&(a), (b), sizeof(a)) 35ddee5cdbSTristan Ye #define o2info_to_user(a, b) \ 36ddee5cdbSTristan Ye copy_to_user((typeof(a) __user *)b, &(a), sizeof(a)) 37ddee5cdbSTristan Ye 38ddee5cdbSTristan Ye /* 39ddee5cdbSTristan Ye * This call is void because we are already reporting an error that may 40ddee5cdbSTristan Ye * be -EFAULT. The error will be returned from the ioctl(2) call. It's 41ddee5cdbSTristan Ye * just a best-effort to tell userspace that this request caused the error. 42ddee5cdbSTristan Ye */ 438aa1fa36STristan Ye static inline void o2info_set_request_error(struct ocfs2_info_request *kreq, 44ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 45ddee5cdbSTristan Ye { 46ddee5cdbSTristan Ye kreq->ir_flags |= OCFS2_INFO_FL_ERROR; 47ddee5cdbSTristan Ye (void)put_user(kreq->ir_flags, (__u32 __user *)&(req->ir_flags)); 48ddee5cdbSTristan Ye } 49ddee5cdbSTristan Ye 508aa1fa36STristan Ye static inline void o2info_set_request_filled(struct ocfs2_info_request *req) 511936a267STristan Ye { 521936a267STristan Ye req->ir_flags |= OCFS2_INFO_FL_FILLED; 531936a267STristan Ye } 541936a267STristan Ye 558aa1fa36STristan Ye static inline void o2info_clear_request_filled(struct ocfs2_info_request *req) 561936a267STristan Ye { 571936a267STristan Ye req->ir_flags &= ~OCFS2_INFO_FL_FILLED; 581936a267STristan Ye } 591936a267STristan Ye 603e5db17dSTristan Ye static inline int o2info_coherent(struct ocfs2_info_request *req) 613e5db17dSTristan Ye { 623e5db17dSTristan Ye return (!(req->ir_flags & OCFS2_INFO_FL_NON_COHERENT)); 633e5db17dSTristan Ye } 641936a267STristan Ye 65ca4d147eSHerbert Poetzl static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags) 66ca4d147eSHerbert Poetzl { 67ca4d147eSHerbert Poetzl int status; 68ca4d147eSHerbert Poetzl 69e63aecb6SMark Fasheh status = ocfs2_inode_lock(inode, NULL, 0); 70ca4d147eSHerbert Poetzl if (status < 0) { 71ca4d147eSHerbert Poetzl mlog_errno(status); 72ca4d147eSHerbert Poetzl return status; 73ca4d147eSHerbert Poetzl } 746e4b0d56SJan Kara ocfs2_get_inode_flags(OCFS2_I(inode)); 75ca4d147eSHerbert Poetzl *flags = OCFS2_I(inode)->ip_attr; 76e63aecb6SMark Fasheh ocfs2_inode_unlock(inode, 0); 77ca4d147eSHerbert Poetzl 78ca4d147eSHerbert Poetzl return status; 79ca4d147eSHerbert Poetzl } 80ca4d147eSHerbert Poetzl 81ca4d147eSHerbert Poetzl static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, 82ca4d147eSHerbert Poetzl unsigned mask) 83ca4d147eSHerbert Poetzl { 84ca4d147eSHerbert Poetzl struct ocfs2_inode_info *ocfs2_inode = OCFS2_I(inode); 85ca4d147eSHerbert Poetzl struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 861fabe148SMark Fasheh handle_t *handle = NULL; 87ca4d147eSHerbert Poetzl struct buffer_head *bh = NULL; 88ca4d147eSHerbert Poetzl unsigned oldflags; 89ca4d147eSHerbert Poetzl int status; 90ca4d147eSHerbert Poetzl 91ca4d147eSHerbert Poetzl mutex_lock(&inode->i_mutex); 92ca4d147eSHerbert Poetzl 93e63aecb6SMark Fasheh status = ocfs2_inode_lock(inode, &bh, 1); 94ca4d147eSHerbert Poetzl if (status < 0) { 95ca4d147eSHerbert Poetzl mlog_errno(status); 96ca4d147eSHerbert Poetzl goto bail; 97ca4d147eSHerbert Poetzl } 98ca4d147eSHerbert Poetzl 99ca4d147eSHerbert Poetzl status = -EACCES; 1002e149670SSerge E. Hallyn if (!inode_owner_or_capable(inode)) 101ca4d147eSHerbert Poetzl goto bail_unlock; 102ca4d147eSHerbert Poetzl 103ca4d147eSHerbert Poetzl if (!S_ISDIR(inode->i_mode)) 104ca4d147eSHerbert Poetzl flags &= ~OCFS2_DIRSYNC_FL; 105ca4d147eSHerbert Poetzl 10665eff9ccSMark Fasheh handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); 107ca4d147eSHerbert Poetzl if (IS_ERR(handle)) { 108ca4d147eSHerbert Poetzl status = PTR_ERR(handle); 109ca4d147eSHerbert Poetzl mlog_errno(status); 110ca4d147eSHerbert Poetzl goto bail_unlock; 111ca4d147eSHerbert Poetzl } 112ca4d147eSHerbert Poetzl 113ca4d147eSHerbert Poetzl oldflags = ocfs2_inode->ip_attr; 114ca4d147eSHerbert Poetzl flags = flags & mask; 115ca4d147eSHerbert Poetzl flags |= oldflags & ~mask; 116ca4d147eSHerbert Poetzl 117ca4d147eSHerbert Poetzl /* 118ca4d147eSHerbert Poetzl * The IMMUTABLE and APPEND_ONLY flags can only be changed by 119ca4d147eSHerbert Poetzl * the relevant capability. 120ca4d147eSHerbert Poetzl */ 121ca4d147eSHerbert Poetzl status = -EPERM; 122ca4d147eSHerbert Poetzl if ((oldflags & OCFS2_IMMUTABLE_FL) || ((flags ^ oldflags) & 123ca4d147eSHerbert Poetzl (OCFS2_APPEND_FL | OCFS2_IMMUTABLE_FL))) { 124ca4d147eSHerbert Poetzl if (!capable(CAP_LINUX_IMMUTABLE)) 125b8a0ae57SWengang Wang goto bail_commit; 126ca4d147eSHerbert Poetzl } 127ca4d147eSHerbert Poetzl 128ca4d147eSHerbert Poetzl ocfs2_inode->ip_attr = flags; 129ca4d147eSHerbert Poetzl ocfs2_set_inode_flags(inode); 130ca4d147eSHerbert Poetzl 131ca4d147eSHerbert Poetzl status = ocfs2_mark_inode_dirty(handle, inode, bh); 132ca4d147eSHerbert Poetzl if (status < 0) 133ca4d147eSHerbert Poetzl mlog_errno(status); 134ca4d147eSHerbert Poetzl 135b8a0ae57SWengang Wang bail_commit: 13602dc1af4SMark Fasheh ocfs2_commit_trans(osb, handle); 137ca4d147eSHerbert Poetzl bail_unlock: 138e63aecb6SMark Fasheh ocfs2_inode_unlock(inode, 1); 139ca4d147eSHerbert Poetzl bail: 140ca4d147eSHerbert Poetzl mutex_unlock(&inode->i_mutex); 141ca4d147eSHerbert Poetzl 142ca4d147eSHerbert Poetzl brelse(bh); 143ca4d147eSHerbert Poetzl 144ca4d147eSHerbert Poetzl return status; 145ca4d147eSHerbert Poetzl } 146ca4d147eSHerbert Poetzl 147ddee5cdbSTristan Ye int ocfs2_info_handle_blocksize(struct inode *inode, 148ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 149ddee5cdbSTristan Ye { 150ddee5cdbSTristan Ye int status = -EFAULT; 151ddee5cdbSTristan Ye struct ocfs2_info_blocksize oib; 152ddee5cdbSTristan Ye 153ddee5cdbSTristan Ye if (o2info_from_user(oib, req)) 154ddee5cdbSTristan Ye goto bail; 155ddee5cdbSTristan Ye 156ddee5cdbSTristan Ye oib.ib_blocksize = inode->i_sb->s_blocksize; 1571936a267STristan Ye 1588aa1fa36STristan Ye o2info_set_request_filled(&oib.ib_req); 159ddee5cdbSTristan Ye 160ddee5cdbSTristan Ye if (o2info_to_user(oib, req)) 161ddee5cdbSTristan Ye goto bail; 162ddee5cdbSTristan Ye 163ddee5cdbSTristan Ye status = 0; 164ddee5cdbSTristan Ye bail: 165ddee5cdbSTristan Ye if (status) 1668aa1fa36STristan Ye o2info_set_request_error(&oib.ib_req, req); 167ddee5cdbSTristan Ye 168ddee5cdbSTristan Ye return status; 169ddee5cdbSTristan Ye } 170ddee5cdbSTristan Ye 171ddee5cdbSTristan Ye int ocfs2_info_handle_clustersize(struct inode *inode, 172ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 173ddee5cdbSTristan Ye { 174ddee5cdbSTristan Ye int status = -EFAULT; 175ddee5cdbSTristan Ye struct ocfs2_info_clustersize oic; 176ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 177ddee5cdbSTristan Ye 178ddee5cdbSTristan Ye if (o2info_from_user(oic, req)) 179ddee5cdbSTristan Ye goto bail; 180ddee5cdbSTristan Ye 181ddee5cdbSTristan Ye oic.ic_clustersize = osb->s_clustersize; 1821936a267STristan Ye 1838aa1fa36STristan Ye o2info_set_request_filled(&oic.ic_req); 184ddee5cdbSTristan Ye 185ddee5cdbSTristan Ye if (o2info_to_user(oic, req)) 186ddee5cdbSTristan Ye goto bail; 187ddee5cdbSTristan Ye 188ddee5cdbSTristan Ye status = 0; 189ddee5cdbSTristan Ye bail: 190ddee5cdbSTristan Ye if (status) 1918aa1fa36STristan Ye o2info_set_request_error(&oic.ic_req, req); 192ddee5cdbSTristan Ye 193ddee5cdbSTristan Ye return status; 194ddee5cdbSTristan Ye } 195ddee5cdbSTristan Ye 196ddee5cdbSTristan Ye int ocfs2_info_handle_maxslots(struct inode *inode, 197ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 198ddee5cdbSTristan Ye { 199ddee5cdbSTristan Ye int status = -EFAULT; 200ddee5cdbSTristan Ye struct ocfs2_info_maxslots oim; 201ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 202ddee5cdbSTristan Ye 203ddee5cdbSTristan Ye if (o2info_from_user(oim, req)) 204ddee5cdbSTristan Ye goto bail; 205ddee5cdbSTristan Ye 206ddee5cdbSTristan Ye oim.im_max_slots = osb->max_slots; 2071936a267STristan Ye 2088aa1fa36STristan Ye o2info_set_request_filled(&oim.im_req); 209ddee5cdbSTristan Ye 210ddee5cdbSTristan Ye if (o2info_to_user(oim, req)) 211ddee5cdbSTristan Ye goto bail; 212ddee5cdbSTristan Ye 213ddee5cdbSTristan Ye status = 0; 214ddee5cdbSTristan Ye bail: 215ddee5cdbSTristan Ye if (status) 2168aa1fa36STristan Ye o2info_set_request_error(&oim.im_req, req); 217ddee5cdbSTristan Ye 218ddee5cdbSTristan Ye return status; 219ddee5cdbSTristan Ye } 220ddee5cdbSTristan Ye 221ddee5cdbSTristan Ye int ocfs2_info_handle_label(struct inode *inode, 222ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 223ddee5cdbSTristan Ye { 224ddee5cdbSTristan Ye int status = -EFAULT; 225ddee5cdbSTristan Ye struct ocfs2_info_label oil; 226ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 227ddee5cdbSTristan Ye 228ddee5cdbSTristan Ye if (o2info_from_user(oil, req)) 229ddee5cdbSTristan Ye goto bail; 230ddee5cdbSTristan Ye 231ddee5cdbSTristan Ye memcpy(oil.il_label, osb->vol_label, OCFS2_MAX_VOL_LABEL_LEN); 2321936a267STristan Ye 2338aa1fa36STristan Ye o2info_set_request_filled(&oil.il_req); 234ddee5cdbSTristan Ye 235ddee5cdbSTristan Ye if (o2info_to_user(oil, req)) 236ddee5cdbSTristan Ye goto bail; 237ddee5cdbSTristan Ye 238ddee5cdbSTristan Ye status = 0; 239ddee5cdbSTristan Ye bail: 240ddee5cdbSTristan Ye if (status) 2418aa1fa36STristan Ye o2info_set_request_error(&oil.il_req, req); 242ddee5cdbSTristan Ye 243ddee5cdbSTristan Ye return status; 244ddee5cdbSTristan Ye } 245ddee5cdbSTristan Ye 246ddee5cdbSTristan Ye int ocfs2_info_handle_uuid(struct inode *inode, 247ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 248ddee5cdbSTristan Ye { 249ddee5cdbSTristan Ye int status = -EFAULT; 250ddee5cdbSTristan Ye struct ocfs2_info_uuid oiu; 251ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 252ddee5cdbSTristan Ye 253ddee5cdbSTristan Ye if (o2info_from_user(oiu, req)) 254ddee5cdbSTristan Ye goto bail; 255ddee5cdbSTristan Ye 256ddee5cdbSTristan Ye memcpy(oiu.iu_uuid_str, osb->uuid_str, OCFS2_TEXT_UUID_LEN + 1); 2571936a267STristan Ye 2588aa1fa36STristan Ye o2info_set_request_filled(&oiu.iu_req); 259ddee5cdbSTristan Ye 260ddee5cdbSTristan Ye if (o2info_to_user(oiu, req)) 261ddee5cdbSTristan Ye goto bail; 262ddee5cdbSTristan Ye 263ddee5cdbSTristan Ye status = 0; 264ddee5cdbSTristan Ye bail: 265ddee5cdbSTristan Ye if (status) 2668aa1fa36STristan Ye o2info_set_request_error(&oiu.iu_req, req); 267ddee5cdbSTristan Ye 268ddee5cdbSTristan Ye return status; 269ddee5cdbSTristan Ye } 270ddee5cdbSTristan Ye 271ddee5cdbSTristan Ye int ocfs2_info_handle_fs_features(struct inode *inode, 272ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 273ddee5cdbSTristan Ye { 274ddee5cdbSTristan Ye int status = -EFAULT; 275ddee5cdbSTristan Ye struct ocfs2_info_fs_features oif; 276ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 277ddee5cdbSTristan Ye 278ddee5cdbSTristan Ye if (o2info_from_user(oif, req)) 279ddee5cdbSTristan Ye goto bail; 280ddee5cdbSTristan Ye 281ddee5cdbSTristan Ye oif.if_compat_features = osb->s_feature_compat; 282ddee5cdbSTristan Ye oif.if_incompat_features = osb->s_feature_incompat; 283ddee5cdbSTristan Ye oif.if_ro_compat_features = osb->s_feature_ro_compat; 2841936a267STristan Ye 2858aa1fa36STristan Ye o2info_set_request_filled(&oif.if_req); 286ddee5cdbSTristan Ye 287ddee5cdbSTristan Ye if (o2info_to_user(oif, req)) 288ddee5cdbSTristan Ye goto bail; 289ddee5cdbSTristan Ye 290ddee5cdbSTristan Ye status = 0; 291ddee5cdbSTristan Ye bail: 292ddee5cdbSTristan Ye if (status) 2938aa1fa36STristan Ye o2info_set_request_error(&oif.if_req, req); 294ddee5cdbSTristan Ye 295ddee5cdbSTristan Ye return status; 296ddee5cdbSTristan Ye } 297ddee5cdbSTristan Ye 298ddee5cdbSTristan Ye int ocfs2_info_handle_journal_size(struct inode *inode, 299ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 300ddee5cdbSTristan Ye { 301ddee5cdbSTristan Ye int status = -EFAULT; 302ddee5cdbSTristan Ye struct ocfs2_info_journal_size oij; 303ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 304ddee5cdbSTristan Ye 305ddee5cdbSTristan Ye if (o2info_from_user(oij, req)) 306ddee5cdbSTristan Ye goto bail; 307ddee5cdbSTristan Ye 308ddee5cdbSTristan Ye oij.ij_journal_size = osb->journal->j_inode->i_size; 309ddee5cdbSTristan Ye 3108aa1fa36STristan Ye o2info_set_request_filled(&oij.ij_req); 311ddee5cdbSTristan Ye 312ddee5cdbSTristan Ye if (o2info_to_user(oij, req)) 313ddee5cdbSTristan Ye goto bail; 314ddee5cdbSTristan Ye 315ddee5cdbSTristan Ye status = 0; 316ddee5cdbSTristan Ye bail: 317ddee5cdbSTristan Ye if (status) 3188aa1fa36STristan Ye o2info_set_request_error(&oij.ij_req, req); 319ddee5cdbSTristan Ye 320ddee5cdbSTristan Ye return status; 321ddee5cdbSTristan Ye } 322ddee5cdbSTristan Ye 3233e5db17dSTristan Ye int ocfs2_info_scan_inode_alloc(struct ocfs2_super *osb, 3243e5db17dSTristan Ye struct inode *inode_alloc, u64 blkno, 3253e5db17dSTristan Ye struct ocfs2_info_freeinode *fi, u32 slot) 3263e5db17dSTristan Ye { 3273e5db17dSTristan Ye int status = 0, unlock = 0; 3283e5db17dSTristan Ye 3293e5db17dSTristan Ye struct buffer_head *bh = NULL; 3303e5db17dSTristan Ye struct ocfs2_dinode *dinode_alloc = NULL; 3313e5db17dSTristan Ye 3323e5db17dSTristan Ye if (inode_alloc) 3333e5db17dSTristan Ye mutex_lock(&inode_alloc->i_mutex); 3343e5db17dSTristan Ye 3353e5db17dSTristan Ye if (o2info_coherent(&fi->ifi_req)) { 3363e5db17dSTristan Ye status = ocfs2_inode_lock(inode_alloc, &bh, 0); 3373e5db17dSTristan Ye if (status < 0) { 3383e5db17dSTristan Ye mlog_errno(status); 3393e5db17dSTristan Ye goto bail; 3403e5db17dSTristan Ye } 3413e5db17dSTristan Ye unlock = 1; 3423e5db17dSTristan Ye } else { 3433e5db17dSTristan Ye status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); 3443e5db17dSTristan Ye if (status < 0) { 3453e5db17dSTristan Ye mlog_errno(status); 3463e5db17dSTristan Ye goto bail; 3473e5db17dSTristan Ye } 3483e5db17dSTristan Ye } 3493e5db17dSTristan Ye 3503e5db17dSTristan Ye dinode_alloc = (struct ocfs2_dinode *)bh->b_data; 3513e5db17dSTristan Ye 3523e5db17dSTristan Ye fi->ifi_stat[slot].lfi_total = 3533e5db17dSTristan Ye le32_to_cpu(dinode_alloc->id1.bitmap1.i_total); 3543e5db17dSTristan Ye fi->ifi_stat[slot].lfi_free = 3553e5db17dSTristan Ye le32_to_cpu(dinode_alloc->id1.bitmap1.i_total) - 3563e5db17dSTristan Ye le32_to_cpu(dinode_alloc->id1.bitmap1.i_used); 3573e5db17dSTristan Ye 3583e5db17dSTristan Ye bail: 3593e5db17dSTristan Ye if (unlock) 3603e5db17dSTristan Ye ocfs2_inode_unlock(inode_alloc, 0); 3613e5db17dSTristan Ye 3623e5db17dSTristan Ye if (inode_alloc) 3633e5db17dSTristan Ye mutex_unlock(&inode_alloc->i_mutex); 3643e5db17dSTristan Ye 3653e5db17dSTristan Ye brelse(bh); 3663e5db17dSTristan Ye 3673e5db17dSTristan Ye return status; 3683e5db17dSTristan Ye } 3693e5db17dSTristan Ye 3703e5db17dSTristan Ye int ocfs2_info_handle_freeinode(struct inode *inode, 3713e5db17dSTristan Ye struct ocfs2_info_request __user *req) 3723e5db17dSTristan Ye { 3733e5db17dSTristan Ye u32 i; 3743e5db17dSTristan Ye u64 blkno = -1; 3753e5db17dSTristan Ye char namebuf[40]; 3763e5db17dSTristan Ye int status = -EFAULT, type = INODE_ALLOC_SYSTEM_INODE; 3773e5db17dSTristan Ye struct ocfs2_info_freeinode *oifi = NULL; 3783e5db17dSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 3793e5db17dSTristan Ye struct inode *inode_alloc = NULL; 3803e5db17dSTristan Ye 3813e5db17dSTristan Ye oifi = kzalloc(sizeof(struct ocfs2_info_freeinode), GFP_KERNEL); 3823e5db17dSTristan Ye if (!oifi) { 3833e5db17dSTristan Ye status = -ENOMEM; 3843e5db17dSTristan Ye mlog_errno(status); 38587f0d5c8SDan Carpenter goto out_err; 3863e5db17dSTristan Ye } 3873e5db17dSTristan Ye 3883e5db17dSTristan Ye if (o2info_from_user(*oifi, req)) 3893e5db17dSTristan Ye goto bail; 3903e5db17dSTristan Ye 3913e5db17dSTristan Ye oifi->ifi_slotnum = osb->max_slots; 3923e5db17dSTristan Ye 3933e5db17dSTristan Ye for (i = 0; i < oifi->ifi_slotnum; i++) { 3943e5db17dSTristan Ye if (o2info_coherent(&oifi->ifi_req)) { 3953e5db17dSTristan Ye inode_alloc = ocfs2_get_system_file_inode(osb, type, i); 3963e5db17dSTristan Ye if (!inode_alloc) { 3973e5db17dSTristan Ye mlog(ML_ERROR, "unable to get alloc inode in " 3983e5db17dSTristan Ye "slot %u\n", i); 3993e5db17dSTristan Ye status = -EIO; 4003e5db17dSTristan Ye goto bail; 4013e5db17dSTristan Ye } 4023e5db17dSTristan Ye } else { 4033e5db17dSTristan Ye ocfs2_sprintf_system_inode_name(namebuf, 4043e5db17dSTristan Ye sizeof(namebuf), 4053e5db17dSTristan Ye type, i); 4063e5db17dSTristan Ye status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, 4073e5db17dSTristan Ye namebuf, 4083e5db17dSTristan Ye strlen(namebuf), 4093e5db17dSTristan Ye &blkno); 4103e5db17dSTristan Ye if (status < 0) { 4113e5db17dSTristan Ye status = -ENOENT; 4123e5db17dSTristan Ye goto bail; 4133e5db17dSTristan Ye } 4143e5db17dSTristan Ye } 4153e5db17dSTristan Ye 4163e5db17dSTristan Ye status = ocfs2_info_scan_inode_alloc(osb, inode_alloc, blkno, oifi, i); 4173e5db17dSTristan Ye if (status < 0) 4183e5db17dSTristan Ye goto bail; 4193e5db17dSTristan Ye 4203e5db17dSTristan Ye iput(inode_alloc); 4213e5db17dSTristan Ye inode_alloc = NULL; 4223e5db17dSTristan Ye } 4233e5db17dSTristan Ye 4243e5db17dSTristan Ye o2info_set_request_filled(&oifi->ifi_req); 4253e5db17dSTristan Ye 4263e5db17dSTristan Ye if (o2info_to_user(*oifi, req)) 4273e5db17dSTristan Ye goto bail; 4283e5db17dSTristan Ye 4293e5db17dSTristan Ye status = 0; 4303e5db17dSTristan Ye bail: 4313e5db17dSTristan Ye if (status) 4323e5db17dSTristan Ye o2info_set_request_error(&oifi->ifi_req, req); 4333e5db17dSTristan Ye 4343e5db17dSTristan Ye kfree(oifi); 43587f0d5c8SDan Carpenter out_err: 4363e5db17dSTristan Ye return status; 4373e5db17dSTristan Ye } 4383e5db17dSTristan Ye 439d24a10b9STristan Ye static void o2ffg_update_histogram(struct ocfs2_info_free_chunk_list *hist, 440d24a10b9STristan Ye unsigned int chunksize) 441d24a10b9STristan Ye { 442d24a10b9STristan Ye int index; 443d24a10b9STristan Ye 444d24a10b9STristan Ye index = __ilog2_u32(chunksize); 445d24a10b9STristan Ye if (index >= OCFS2_INFO_MAX_HIST) 446d24a10b9STristan Ye index = OCFS2_INFO_MAX_HIST - 1; 447d24a10b9STristan Ye 448d24a10b9STristan Ye hist->fc_chunks[index]++; 449d24a10b9STristan Ye hist->fc_clusters[index] += chunksize; 450d24a10b9STristan Ye } 451d24a10b9STristan Ye 452d24a10b9STristan Ye static void o2ffg_update_stats(struct ocfs2_info_freefrag_stats *stats, 453d24a10b9STristan Ye unsigned int chunksize) 454d24a10b9STristan Ye { 455d24a10b9STristan Ye if (chunksize > stats->ffs_max) 456d24a10b9STristan Ye stats->ffs_max = chunksize; 457d24a10b9STristan Ye 458d24a10b9STristan Ye if (chunksize < stats->ffs_min) 459d24a10b9STristan Ye stats->ffs_min = chunksize; 460d24a10b9STristan Ye 461d24a10b9STristan Ye stats->ffs_avg += chunksize; 462d24a10b9STristan Ye stats->ffs_free_chunks_real++; 463d24a10b9STristan Ye } 464d24a10b9STristan Ye 465d24a10b9STristan Ye void ocfs2_info_update_ffg(struct ocfs2_info_freefrag *ffg, 466d24a10b9STristan Ye unsigned int chunksize) 467d24a10b9STristan Ye { 468d24a10b9STristan Ye o2ffg_update_histogram(&(ffg->iff_ffs.ffs_fc_hist), chunksize); 469d24a10b9STristan Ye o2ffg_update_stats(&(ffg->iff_ffs), chunksize); 470d24a10b9STristan Ye } 471d24a10b9STristan Ye 472d24a10b9STristan Ye int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, 473d24a10b9STristan Ye struct inode *gb_inode, 474d24a10b9STristan Ye struct ocfs2_dinode *gb_dinode, 475d24a10b9STristan Ye struct ocfs2_chain_rec *rec, 476d24a10b9STristan Ye struct ocfs2_info_freefrag *ffg, 477d24a10b9STristan Ye u32 chunks_in_group) 478d24a10b9STristan Ye { 479d24a10b9STristan Ye int status = 0, used; 480d24a10b9STristan Ye u64 blkno; 481d24a10b9STristan Ye 482d24a10b9STristan Ye struct buffer_head *bh = NULL; 483d24a10b9STristan Ye struct ocfs2_group_desc *bg = NULL; 484d24a10b9STristan Ye 485d24a10b9STristan Ye unsigned int max_bits, num_clusters; 486d24a10b9STristan Ye unsigned int offset = 0, cluster, chunk; 487d24a10b9STristan Ye unsigned int chunk_free, last_chunksize = 0; 488d24a10b9STristan Ye 489d24a10b9STristan Ye if (!le32_to_cpu(rec->c_free)) 490d24a10b9STristan Ye goto bail; 491d24a10b9STristan Ye 492d24a10b9STristan Ye do { 493d24a10b9STristan Ye if (!bg) 494d24a10b9STristan Ye blkno = le64_to_cpu(rec->c_blkno); 495d24a10b9STristan Ye else 496d24a10b9STristan Ye blkno = le64_to_cpu(bg->bg_next_group); 497d24a10b9STristan Ye 498d24a10b9STristan Ye if (bh) { 499d24a10b9STristan Ye brelse(bh); 500d24a10b9STristan Ye bh = NULL; 501d24a10b9STristan Ye } 502d24a10b9STristan Ye 503d24a10b9STristan Ye if (o2info_coherent(&ffg->iff_req)) 504d24a10b9STristan Ye status = ocfs2_read_group_descriptor(gb_inode, 505d24a10b9STristan Ye gb_dinode, 506d24a10b9STristan Ye blkno, &bh); 507d24a10b9STristan Ye else 508d24a10b9STristan Ye status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); 509d24a10b9STristan Ye 510d24a10b9STristan Ye if (status < 0) { 511d24a10b9STristan Ye mlog(ML_ERROR, "Can't read the group descriptor # " 512d24a10b9STristan Ye "%llu from device.", (unsigned long long)blkno); 513d24a10b9STristan Ye status = -EIO; 514d24a10b9STristan Ye goto bail; 515d24a10b9STristan Ye } 516d24a10b9STristan Ye 517d24a10b9STristan Ye bg = (struct ocfs2_group_desc *)bh->b_data; 518d24a10b9STristan Ye 519d24a10b9STristan Ye if (!le16_to_cpu(bg->bg_free_bits_count)) 520d24a10b9STristan Ye continue; 521d24a10b9STristan Ye 522d24a10b9STristan Ye max_bits = le16_to_cpu(bg->bg_bits); 523d24a10b9STristan Ye offset = 0; 524d24a10b9STristan Ye 525d24a10b9STristan Ye for (chunk = 0; chunk < chunks_in_group; chunk++) { 526d24a10b9STristan Ye /* 527d24a10b9STristan Ye * last chunk may be not an entire one. 528d24a10b9STristan Ye */ 529d24a10b9STristan Ye if ((offset + ffg->iff_chunksize) > max_bits) 530d24a10b9STristan Ye num_clusters = max_bits - offset; 531d24a10b9STristan Ye else 532d24a10b9STristan Ye num_clusters = ffg->iff_chunksize; 533d24a10b9STristan Ye 534d24a10b9STristan Ye chunk_free = 0; 535d24a10b9STristan Ye for (cluster = 0; cluster < num_clusters; cluster++) { 536d24a10b9STristan Ye used = ocfs2_test_bit(offset, 537d24a10b9STristan Ye (unsigned long *)bg->bg_bitmap); 538d24a10b9STristan Ye /* 539d24a10b9STristan Ye * - chunk_free counts free clusters in #N chunk. 540d24a10b9STristan Ye * - last_chunksize records the size(in) clusters 541d24a10b9STristan Ye * for the last real free chunk being counted. 542d24a10b9STristan Ye */ 543d24a10b9STristan Ye if (!used) { 544d24a10b9STristan Ye last_chunksize++; 545d24a10b9STristan Ye chunk_free++; 546d24a10b9STristan Ye } 547d24a10b9STristan Ye 548d24a10b9STristan Ye if (used && last_chunksize) { 549d24a10b9STristan Ye ocfs2_info_update_ffg(ffg, 550d24a10b9STristan Ye last_chunksize); 551d24a10b9STristan Ye last_chunksize = 0; 552d24a10b9STristan Ye } 553d24a10b9STristan Ye 554d24a10b9STristan Ye offset++; 555d24a10b9STristan Ye } 556d24a10b9STristan Ye 557d24a10b9STristan Ye if (chunk_free == ffg->iff_chunksize) 558d24a10b9STristan Ye ffg->iff_ffs.ffs_free_chunks++; 559d24a10b9STristan Ye } 560d24a10b9STristan Ye 561d24a10b9STristan Ye /* 562d24a10b9STristan Ye * need to update the info for last free chunk. 563d24a10b9STristan Ye */ 564d24a10b9STristan Ye if (last_chunksize) 565d24a10b9STristan Ye ocfs2_info_update_ffg(ffg, last_chunksize); 566d24a10b9STristan Ye 567d24a10b9STristan Ye } while (le64_to_cpu(bg->bg_next_group)); 568d24a10b9STristan Ye 569d24a10b9STristan Ye bail: 570d24a10b9STristan Ye brelse(bh); 571d24a10b9STristan Ye 572d24a10b9STristan Ye return status; 573d24a10b9STristan Ye } 574d24a10b9STristan Ye 575d24a10b9STristan Ye int ocfs2_info_freefrag_scan_bitmap(struct ocfs2_super *osb, 576d24a10b9STristan Ye struct inode *gb_inode, u64 blkno, 577d24a10b9STristan Ye struct ocfs2_info_freefrag *ffg) 578d24a10b9STristan Ye { 579d24a10b9STristan Ye u32 chunks_in_group; 580d24a10b9STristan Ye int status = 0, unlock = 0, i; 581d24a10b9STristan Ye 582d24a10b9STristan Ye struct buffer_head *bh = NULL; 583d24a10b9STristan Ye struct ocfs2_chain_list *cl = NULL; 584d24a10b9STristan Ye struct ocfs2_chain_rec *rec = NULL; 585d24a10b9STristan Ye struct ocfs2_dinode *gb_dinode = NULL; 586d24a10b9STristan Ye 587d24a10b9STristan Ye if (gb_inode) 588d24a10b9STristan Ye mutex_lock(&gb_inode->i_mutex); 589d24a10b9STristan Ye 590d24a10b9STristan Ye if (o2info_coherent(&ffg->iff_req)) { 591d24a10b9STristan Ye status = ocfs2_inode_lock(gb_inode, &bh, 0); 592d24a10b9STristan Ye if (status < 0) { 593d24a10b9STristan Ye mlog_errno(status); 594d24a10b9STristan Ye goto bail; 595d24a10b9STristan Ye } 596d24a10b9STristan Ye unlock = 1; 597d24a10b9STristan Ye } else { 598d24a10b9STristan Ye status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); 599d24a10b9STristan Ye if (status < 0) { 600d24a10b9STristan Ye mlog_errno(status); 601d24a10b9STristan Ye goto bail; 602d24a10b9STristan Ye } 603d24a10b9STristan Ye } 604d24a10b9STristan Ye 605d24a10b9STristan Ye gb_dinode = (struct ocfs2_dinode *)bh->b_data; 606d24a10b9STristan Ye cl = &(gb_dinode->id2.i_chain); 607d24a10b9STristan Ye 608d24a10b9STristan Ye /* 609d24a10b9STristan Ye * Chunksize(in) clusters from userspace should be 610d24a10b9STristan Ye * less than clusters in a group. 611d24a10b9STristan Ye */ 612d24a10b9STristan Ye if (ffg->iff_chunksize > le16_to_cpu(cl->cl_cpg)) { 613d24a10b9STristan Ye status = -EINVAL; 614d24a10b9STristan Ye goto bail; 615d24a10b9STristan Ye } 616d24a10b9STristan Ye 617d24a10b9STristan Ye memset(&ffg->iff_ffs, 0, sizeof(struct ocfs2_info_freefrag_stats)); 618d24a10b9STristan Ye 619d24a10b9STristan Ye ffg->iff_ffs.ffs_min = ~0U; 620d24a10b9STristan Ye ffg->iff_ffs.ffs_clusters = 621d24a10b9STristan Ye le32_to_cpu(gb_dinode->id1.bitmap1.i_total); 622d24a10b9STristan Ye ffg->iff_ffs.ffs_free_clusters = ffg->iff_ffs.ffs_clusters - 623d24a10b9STristan Ye le32_to_cpu(gb_dinode->id1.bitmap1.i_used); 624d24a10b9STristan Ye 625d24a10b9STristan Ye chunks_in_group = le16_to_cpu(cl->cl_cpg) / ffg->iff_chunksize + 1; 626d24a10b9STristan Ye 627d24a10b9STristan Ye for (i = 0; i < le16_to_cpu(cl->cl_next_free_rec); i++) { 628d24a10b9STristan Ye rec = &(cl->cl_recs[i]); 629d24a10b9STristan Ye status = ocfs2_info_freefrag_scan_chain(osb, gb_inode, 630d24a10b9STristan Ye gb_dinode, 631d24a10b9STristan Ye rec, ffg, 632d24a10b9STristan Ye chunks_in_group); 633d24a10b9STristan Ye if (status) 634d24a10b9STristan Ye goto bail; 635d24a10b9STristan Ye } 636d24a10b9STristan Ye 637d24a10b9STristan Ye if (ffg->iff_ffs.ffs_free_chunks_real) 638d24a10b9STristan Ye ffg->iff_ffs.ffs_avg = (ffg->iff_ffs.ffs_avg / 639d24a10b9STristan Ye ffg->iff_ffs.ffs_free_chunks_real); 640d24a10b9STristan Ye bail: 641d24a10b9STristan Ye if (unlock) 642d24a10b9STristan Ye ocfs2_inode_unlock(gb_inode, 0); 643d24a10b9STristan Ye 644d24a10b9STristan Ye if (gb_inode) 645d24a10b9STristan Ye mutex_unlock(&gb_inode->i_mutex); 646d24a10b9STristan Ye 647d24a10b9STristan Ye if (gb_inode) 648d24a10b9STristan Ye iput(gb_inode); 649d24a10b9STristan Ye 650d24a10b9STristan Ye brelse(bh); 651d24a10b9STristan Ye 652d24a10b9STristan Ye return status; 653d24a10b9STristan Ye } 654d24a10b9STristan Ye 655d24a10b9STristan Ye int ocfs2_info_handle_freefrag(struct inode *inode, 656d24a10b9STristan Ye struct ocfs2_info_request __user *req) 657d24a10b9STristan Ye { 658d24a10b9STristan Ye u64 blkno = -1; 659d24a10b9STristan Ye char namebuf[40]; 660d24a10b9STristan Ye int status = -EFAULT, type = GLOBAL_BITMAP_SYSTEM_INODE; 661d24a10b9STristan Ye 662d24a10b9STristan Ye struct ocfs2_info_freefrag *oiff; 663d24a10b9STristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 664d24a10b9STristan Ye struct inode *gb_inode = NULL; 665d24a10b9STristan Ye 666d24a10b9STristan Ye oiff = kzalloc(sizeof(struct ocfs2_info_freefrag), GFP_KERNEL); 667d24a10b9STristan Ye if (!oiff) { 668d24a10b9STristan Ye status = -ENOMEM; 669d24a10b9STristan Ye mlog_errno(status); 67087f0d5c8SDan Carpenter goto out_err; 671d24a10b9STristan Ye } 672d24a10b9STristan Ye 673d24a10b9STristan Ye if (o2info_from_user(*oiff, req)) 674d24a10b9STristan Ye goto bail; 675d24a10b9STristan Ye /* 676d24a10b9STristan Ye * chunksize from userspace should be power of 2. 677d24a10b9STristan Ye */ 678d24a10b9STristan Ye if ((oiff->iff_chunksize & (oiff->iff_chunksize - 1)) || 679d24a10b9STristan Ye (!oiff->iff_chunksize)) { 680d24a10b9STristan Ye status = -EINVAL; 681d24a10b9STristan Ye goto bail; 682d24a10b9STristan Ye } 683d24a10b9STristan Ye 684d24a10b9STristan Ye if (o2info_coherent(&oiff->iff_req)) { 685d24a10b9STristan Ye gb_inode = ocfs2_get_system_file_inode(osb, type, 686d24a10b9STristan Ye OCFS2_INVALID_SLOT); 687d24a10b9STristan Ye if (!gb_inode) { 688d24a10b9STristan Ye mlog(ML_ERROR, "unable to get global_bitmap inode\n"); 689d24a10b9STristan Ye status = -EIO; 690d24a10b9STristan Ye goto bail; 691d24a10b9STristan Ye } 692d24a10b9STristan Ye } else { 693d24a10b9STristan Ye ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type, 694d24a10b9STristan Ye OCFS2_INVALID_SLOT); 695d24a10b9STristan Ye status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, 696d24a10b9STristan Ye namebuf, 697d24a10b9STristan Ye strlen(namebuf), 698d24a10b9STristan Ye &blkno); 699d24a10b9STristan Ye if (status < 0) { 700d24a10b9STristan Ye status = -ENOENT; 701d24a10b9STristan Ye goto bail; 702d24a10b9STristan Ye } 703d24a10b9STristan Ye } 704d24a10b9STristan Ye 705d24a10b9STristan Ye status = ocfs2_info_freefrag_scan_bitmap(osb, gb_inode, blkno, oiff); 706d24a10b9STristan Ye if (status < 0) 707d24a10b9STristan Ye goto bail; 708d24a10b9STristan Ye 709d24a10b9STristan Ye o2info_set_request_filled(&oiff->iff_req); 710d24a10b9STristan Ye 711d24a10b9STristan Ye if (o2info_to_user(*oiff, req)) 712d24a10b9STristan Ye goto bail; 713d24a10b9STristan Ye 714d24a10b9STristan Ye status = 0; 715d24a10b9STristan Ye bail: 716d24a10b9STristan Ye if (status) 717d24a10b9STristan Ye o2info_set_request_error(&oiff->iff_req, req); 718d24a10b9STristan Ye 719d24a10b9STristan Ye kfree(oiff); 72087f0d5c8SDan Carpenter out_err: 721ddee5cdbSTristan Ye return status; 722ddee5cdbSTristan Ye } 723ddee5cdbSTristan Ye 724ddee5cdbSTristan Ye int ocfs2_info_handle_unknown(struct inode *inode, 725ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 726ddee5cdbSTristan Ye { 727ddee5cdbSTristan Ye int status = -EFAULT; 728ddee5cdbSTristan Ye struct ocfs2_info_request oir; 729ddee5cdbSTristan Ye 730ddee5cdbSTristan Ye if (o2info_from_user(oir, req)) 731ddee5cdbSTristan Ye goto bail; 732ddee5cdbSTristan Ye 7338aa1fa36STristan Ye o2info_clear_request_filled(&oir); 734ddee5cdbSTristan Ye 735ddee5cdbSTristan Ye if (o2info_to_user(oir, req)) 736ddee5cdbSTristan Ye goto bail; 737ddee5cdbSTristan Ye 738ddee5cdbSTristan Ye status = 0; 739ddee5cdbSTristan Ye bail: 740ddee5cdbSTristan Ye if (status) 7418aa1fa36STristan Ye o2info_set_request_error(&oir, req); 742ddee5cdbSTristan Ye 743ddee5cdbSTristan Ye return status; 744ddee5cdbSTristan Ye } 745ddee5cdbSTristan Ye 746ddee5cdbSTristan Ye /* 747ddee5cdbSTristan Ye * Validate and distinguish OCFS2_IOC_INFO requests. 748ddee5cdbSTristan Ye * 749ddee5cdbSTristan Ye * - validate the magic number. 750ddee5cdbSTristan Ye * - distinguish different requests. 751ddee5cdbSTristan Ye * - validate size of different requests. 752ddee5cdbSTristan Ye */ 753ddee5cdbSTristan Ye int ocfs2_info_handle_request(struct inode *inode, 754ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 755ddee5cdbSTristan Ye { 756ddee5cdbSTristan Ye int status = -EFAULT; 757ddee5cdbSTristan Ye struct ocfs2_info_request oir; 758ddee5cdbSTristan Ye 759ddee5cdbSTristan Ye if (o2info_from_user(oir, req)) 760ddee5cdbSTristan Ye goto bail; 761ddee5cdbSTristan Ye 762ddee5cdbSTristan Ye status = -EINVAL; 763ddee5cdbSTristan Ye if (oir.ir_magic != OCFS2_INFO_MAGIC) 764ddee5cdbSTristan Ye goto bail; 765ddee5cdbSTristan Ye 766ddee5cdbSTristan Ye switch (oir.ir_code) { 767ddee5cdbSTristan Ye case OCFS2_INFO_BLOCKSIZE: 768ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_blocksize)) 769ddee5cdbSTristan Ye status = ocfs2_info_handle_blocksize(inode, req); 770ddee5cdbSTristan Ye break; 771ddee5cdbSTristan Ye case OCFS2_INFO_CLUSTERSIZE: 772ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_clustersize)) 773ddee5cdbSTristan Ye status = ocfs2_info_handle_clustersize(inode, req); 774ddee5cdbSTristan Ye break; 775ddee5cdbSTristan Ye case OCFS2_INFO_MAXSLOTS: 776ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_maxslots)) 777ddee5cdbSTristan Ye status = ocfs2_info_handle_maxslots(inode, req); 778ddee5cdbSTristan Ye break; 779ddee5cdbSTristan Ye case OCFS2_INFO_LABEL: 780ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_label)) 781ddee5cdbSTristan Ye status = ocfs2_info_handle_label(inode, req); 782ddee5cdbSTristan Ye break; 783ddee5cdbSTristan Ye case OCFS2_INFO_UUID: 784ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_uuid)) 785ddee5cdbSTristan Ye status = ocfs2_info_handle_uuid(inode, req); 786ddee5cdbSTristan Ye break; 787ddee5cdbSTristan Ye case OCFS2_INFO_FS_FEATURES: 788ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_fs_features)) 789ddee5cdbSTristan Ye status = ocfs2_info_handle_fs_features(inode, req); 790ddee5cdbSTristan Ye break; 791ddee5cdbSTristan Ye case OCFS2_INFO_JOURNAL_SIZE: 792ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_journal_size)) 793ddee5cdbSTristan Ye status = ocfs2_info_handle_journal_size(inode, req); 794ddee5cdbSTristan Ye break; 7953e5db17dSTristan Ye case OCFS2_INFO_FREEINODE: 7963e5db17dSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_freeinode)) 7973e5db17dSTristan Ye status = ocfs2_info_handle_freeinode(inode, req); 7983e5db17dSTristan Ye break; 799d24a10b9STristan Ye case OCFS2_INFO_FREEFRAG: 800d24a10b9STristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_freefrag)) 801d24a10b9STristan Ye status = ocfs2_info_handle_freefrag(inode, req); 802d24a10b9STristan Ye break; 803ddee5cdbSTristan Ye default: 804ddee5cdbSTristan Ye status = ocfs2_info_handle_unknown(inode, req); 805ddee5cdbSTristan Ye break; 806ddee5cdbSTristan Ye } 807ddee5cdbSTristan Ye 808ddee5cdbSTristan Ye bail: 809ddee5cdbSTristan Ye return status; 810ddee5cdbSTristan Ye } 811ddee5cdbSTristan Ye 812ddee5cdbSTristan Ye int ocfs2_get_request_ptr(struct ocfs2_info *info, int idx, 813ddee5cdbSTristan Ye u64 *req_addr, int compat_flag) 814ddee5cdbSTristan Ye { 815ddee5cdbSTristan Ye int status = -EFAULT; 816ddee5cdbSTristan Ye u64 __user *bp = NULL; 817ddee5cdbSTristan Ye 818ddee5cdbSTristan Ye if (compat_flag) { 819ddee5cdbSTristan Ye #ifdef CONFIG_COMPAT 820ddee5cdbSTristan Ye /* 821ddee5cdbSTristan Ye * pointer bp stores the base address of a pointers array, 822ddee5cdbSTristan Ye * which collects all addresses of separate request. 823ddee5cdbSTristan Ye */ 824ddee5cdbSTristan Ye bp = (u64 __user *)(unsigned long)compat_ptr(info->oi_requests); 825ddee5cdbSTristan Ye #else 826ddee5cdbSTristan Ye BUG(); 827ddee5cdbSTristan Ye #endif 828ddee5cdbSTristan Ye } else 829ddee5cdbSTristan Ye bp = (u64 __user *)(unsigned long)(info->oi_requests); 830ddee5cdbSTristan Ye 831ddee5cdbSTristan Ye if (o2info_from_user(*req_addr, bp + idx)) 832ddee5cdbSTristan Ye goto bail; 833ddee5cdbSTristan Ye 834ddee5cdbSTristan Ye status = 0; 835ddee5cdbSTristan Ye bail: 836ddee5cdbSTristan Ye return status; 837ddee5cdbSTristan Ye } 838ddee5cdbSTristan Ye 839ddee5cdbSTristan Ye /* 840ddee5cdbSTristan Ye * OCFS2_IOC_INFO handles an array of requests passed from userspace. 841ddee5cdbSTristan Ye * 842ddee5cdbSTristan Ye * ocfs2_info_handle() recevies a large info aggregation, grab and 843ddee5cdbSTristan Ye * validate the request count from header, then break it into small 844ddee5cdbSTristan Ye * pieces, later specific handlers can handle them one by one. 845ddee5cdbSTristan Ye * 846ddee5cdbSTristan Ye * Idea here is to make each separate request small enough to ensure 847ddee5cdbSTristan Ye * a better backward&forward compatibility, since a small piece of 848ddee5cdbSTristan Ye * request will be less likely to be broken if disk layout get changed. 849ddee5cdbSTristan Ye */ 850ddee5cdbSTristan Ye int ocfs2_info_handle(struct inode *inode, struct ocfs2_info *info, 851ddee5cdbSTristan Ye int compat_flag) 852ddee5cdbSTristan Ye { 853ddee5cdbSTristan Ye int i, status = 0; 854ddee5cdbSTristan Ye u64 req_addr; 855ddee5cdbSTristan Ye struct ocfs2_info_request __user *reqp; 856ddee5cdbSTristan Ye 857ddee5cdbSTristan Ye if ((info->oi_count > OCFS2_INFO_MAX_REQUEST) || 858ddee5cdbSTristan Ye (!info->oi_requests)) { 859ddee5cdbSTristan Ye status = -EINVAL; 860ddee5cdbSTristan Ye goto bail; 861ddee5cdbSTristan Ye } 862ddee5cdbSTristan Ye 863ddee5cdbSTristan Ye for (i = 0; i < info->oi_count; i++) { 864ddee5cdbSTristan Ye 865ddee5cdbSTristan Ye status = ocfs2_get_request_ptr(info, i, &req_addr, compat_flag); 866ddee5cdbSTristan Ye if (status) 867ddee5cdbSTristan Ye break; 868ddee5cdbSTristan Ye 869ddee5cdbSTristan Ye reqp = (struct ocfs2_info_request *)(unsigned long)req_addr; 870ddee5cdbSTristan Ye if (!reqp) { 871ddee5cdbSTristan Ye status = -EINVAL; 872ddee5cdbSTristan Ye goto bail; 873ddee5cdbSTristan Ye } 874ddee5cdbSTristan Ye 875ddee5cdbSTristan Ye status = ocfs2_info_handle_request(inode, reqp); 876ddee5cdbSTristan Ye if (status) 877ddee5cdbSTristan Ye break; 878ddee5cdbSTristan Ye } 879ddee5cdbSTristan Ye 880ddee5cdbSTristan Ye bail: 881ddee5cdbSTristan Ye return status; 882ddee5cdbSTristan Ye } 883ddee5cdbSTristan Ye 884c9ec1488SAndi Kleen long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 885ca4d147eSHerbert Poetzl { 886c9ec1488SAndi Kleen struct inode *inode = filp->f_path.dentry->d_inode; 887ca4d147eSHerbert Poetzl unsigned int flags; 888d659072fSTao Ma int new_clusters; 889ca4d147eSHerbert Poetzl int status; 890b2580103SMark Fasheh struct ocfs2_space_resv sr; 8917909f2bfSTao Ma struct ocfs2_new_group_input input; 892bd50873dSTao Ma struct reflink_arguments args; 893bd50873dSTao Ma const char *old_path, *new_path; 894bd50873dSTao Ma bool preserve; 895ddee5cdbSTristan Ye struct ocfs2_info info; 896ca4d147eSHerbert Poetzl 897ca4d147eSHerbert Poetzl switch (cmd) { 898ca4d147eSHerbert Poetzl case OCFS2_IOC_GETFLAGS: 899ca4d147eSHerbert Poetzl status = ocfs2_get_inode_attr(inode, &flags); 900ca4d147eSHerbert Poetzl if (status < 0) 901ca4d147eSHerbert Poetzl return status; 902ca4d147eSHerbert Poetzl 903ca4d147eSHerbert Poetzl flags &= OCFS2_FL_VISIBLE; 904ca4d147eSHerbert Poetzl return put_user(flags, (int __user *) arg); 905ca4d147eSHerbert Poetzl case OCFS2_IOC_SETFLAGS: 906ca4d147eSHerbert Poetzl if (get_user(flags, (int __user *) arg)) 907ca4d147eSHerbert Poetzl return -EFAULT; 908ca4d147eSHerbert Poetzl 909*a561be71SAl Viro status = mnt_want_write_file(filp); 91042a74f20SDave Hansen if (status) 91142a74f20SDave Hansen return status; 91242a74f20SDave Hansen status = ocfs2_set_inode_attr(inode, flags, 913ca4d147eSHerbert Poetzl OCFS2_FL_MODIFIABLE); 91442a74f20SDave Hansen mnt_drop_write(filp->f_path.mnt); 91542a74f20SDave Hansen return status; 916b2580103SMark Fasheh case OCFS2_IOC_RESVSP: 917b2580103SMark Fasheh case OCFS2_IOC_RESVSP64: 918b2580103SMark Fasheh case OCFS2_IOC_UNRESVSP: 919b2580103SMark Fasheh case OCFS2_IOC_UNRESVSP64: 920b2580103SMark Fasheh if (copy_from_user(&sr, (int __user *) arg, sizeof(sr))) 921b2580103SMark Fasheh return -EFAULT; 922b2580103SMark Fasheh 923b2580103SMark Fasheh return ocfs2_change_file_space(filp, cmd, &sr); 924d659072fSTao Ma case OCFS2_IOC_GROUP_EXTEND: 9250957f007SMark Fasheh if (!capable(CAP_SYS_RESOURCE)) 9260957f007SMark Fasheh return -EPERM; 9270957f007SMark Fasheh 928d659072fSTao Ma if (get_user(new_clusters, (int __user *)arg)) 929d659072fSTao Ma return -EFAULT; 930d659072fSTao Ma 931d659072fSTao Ma return ocfs2_group_extend(inode, new_clusters); 9327909f2bfSTao Ma case OCFS2_IOC_GROUP_ADD: 9337909f2bfSTao Ma case OCFS2_IOC_GROUP_ADD64: 9340957f007SMark Fasheh if (!capable(CAP_SYS_RESOURCE)) 9350957f007SMark Fasheh return -EPERM; 9360957f007SMark Fasheh 9377909f2bfSTao Ma if (copy_from_user(&input, (int __user *) arg, sizeof(input))) 9387909f2bfSTao Ma return -EFAULT; 9397909f2bfSTao Ma 9407909f2bfSTao Ma return ocfs2_group_add(inode, &input); 941bd50873dSTao Ma case OCFS2_IOC_REFLINK: 942bd50873dSTao Ma if (copy_from_user(&args, (struct reflink_arguments *)arg, 943bd50873dSTao Ma sizeof(args))) 944bd50873dSTao Ma return -EFAULT; 945bd50873dSTao Ma old_path = (const char *)(unsigned long)args.old_path; 946bd50873dSTao Ma new_path = (const char *)(unsigned long)args.new_path; 947bd50873dSTao Ma preserve = (args.preserve != 0); 948bd50873dSTao Ma 949bd50873dSTao Ma return ocfs2_reflink_ioctl(inode, old_path, new_path, preserve); 950ddee5cdbSTristan Ye case OCFS2_IOC_INFO: 951ddee5cdbSTristan Ye if (copy_from_user(&info, (struct ocfs2_info __user *)arg, 952ddee5cdbSTristan Ye sizeof(struct ocfs2_info))) 953ddee5cdbSTristan Ye return -EFAULT; 954ddee5cdbSTristan Ye 955ddee5cdbSTristan Ye return ocfs2_info_handle(inode, &info, 0); 95655e67872STao Ma case FITRIM: 95755e67872STao Ma { 95855e67872STao Ma struct super_block *sb = inode->i_sb; 95955e67872STao Ma struct fstrim_range range; 96055e67872STao Ma int ret = 0; 96155e67872STao Ma 96255e67872STao Ma if (!capable(CAP_SYS_ADMIN)) 96355e67872STao Ma return -EPERM; 96455e67872STao Ma 96555e67872STao Ma if (copy_from_user(&range, (struct fstrim_range *)arg, 96655e67872STao Ma sizeof(range))) 96755e67872STao Ma return -EFAULT; 96855e67872STao Ma 96955e67872STao Ma ret = ocfs2_trim_fs(sb, &range); 97055e67872STao Ma if (ret < 0) 97155e67872STao Ma return ret; 97255e67872STao Ma 97355e67872STao Ma if (copy_to_user((struct fstrim_range *)arg, &range, 97455e67872STao Ma sizeof(range))) 97555e67872STao Ma return -EFAULT; 97655e67872STao Ma 97755e67872STao Ma return 0; 97855e67872STao Ma } 97953069d4eSTristan Ye case OCFS2_IOC_MOVE_EXT: 98053069d4eSTristan Ye return ocfs2_ioctl_move_extents(filp, (void __user *)arg); 981ca4d147eSHerbert Poetzl default: 982ca4d147eSHerbert Poetzl return -ENOTTY; 983ca4d147eSHerbert Poetzl } 984ca4d147eSHerbert Poetzl } 985ca4d147eSHerbert Poetzl 986586d232bSMark Fasheh #ifdef CONFIG_COMPAT 987586d232bSMark Fasheh long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) 988586d232bSMark Fasheh { 98934e6c59aSTao Ma bool preserve; 99034e6c59aSTao Ma struct reflink_arguments args; 99134e6c59aSTao Ma struct inode *inode = file->f_path.dentry->d_inode; 992ddee5cdbSTristan Ye struct ocfs2_info info; 99334e6c59aSTao Ma 994586d232bSMark Fasheh switch (cmd) { 995586d232bSMark Fasheh case OCFS2_IOC32_GETFLAGS: 996586d232bSMark Fasheh cmd = OCFS2_IOC_GETFLAGS; 997586d232bSMark Fasheh break; 998586d232bSMark Fasheh case OCFS2_IOC32_SETFLAGS: 999586d232bSMark Fasheh cmd = OCFS2_IOC_SETFLAGS; 1000586d232bSMark Fasheh break; 1001b2580103SMark Fasheh case OCFS2_IOC_RESVSP: 1002b2580103SMark Fasheh case OCFS2_IOC_RESVSP64: 1003b2580103SMark Fasheh case OCFS2_IOC_UNRESVSP: 1004b2580103SMark Fasheh case OCFS2_IOC_UNRESVSP64: 1005d659072fSTao Ma case OCFS2_IOC_GROUP_EXTEND: 10067909f2bfSTao Ma case OCFS2_IOC_GROUP_ADD: 10077909f2bfSTao Ma case OCFS2_IOC_GROUP_ADD64: 100855e67872STao Ma case FITRIM: 1009b2580103SMark Fasheh break; 101034e6c59aSTao Ma case OCFS2_IOC_REFLINK: 101134e6c59aSTao Ma if (copy_from_user(&args, (struct reflink_arguments *)arg, 101234e6c59aSTao Ma sizeof(args))) 101334e6c59aSTao Ma return -EFAULT; 101434e6c59aSTao Ma preserve = (args.preserve != 0); 101534e6c59aSTao Ma 101634e6c59aSTao Ma return ocfs2_reflink_ioctl(inode, compat_ptr(args.old_path), 101734e6c59aSTao Ma compat_ptr(args.new_path), preserve); 1018ddee5cdbSTristan Ye case OCFS2_IOC_INFO: 1019ddee5cdbSTristan Ye if (copy_from_user(&info, (struct ocfs2_info __user *)arg, 1020ddee5cdbSTristan Ye sizeof(struct ocfs2_info))) 1021ddee5cdbSTristan Ye return -EFAULT; 1022ddee5cdbSTristan Ye 1023ddee5cdbSTristan Ye return ocfs2_info_handle(inode, &info, 1); 102453069d4eSTristan Ye case OCFS2_IOC_MOVE_EXT: 102553069d4eSTristan Ye break; 1026586d232bSMark Fasheh default: 1027586d232bSMark Fasheh return -ENOIOCTLCMD; 1028586d232bSMark Fasheh } 1029586d232bSMark Fasheh 1030c9ec1488SAndi Kleen return ocfs2_ioctl(file, cmd, arg); 1031586d232bSMark Fasheh } 1032586d232bSMark Fasheh #endif 1033