1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2ca4d147eSHerbert Poetzl /* 3ca4d147eSHerbert Poetzl * linux/fs/ocfs2/ioctl.c 4ca4d147eSHerbert Poetzl * 5ca4d147eSHerbert Poetzl * Copyright (C) 2006 Herbert Poetzl 6ca4d147eSHerbert Poetzl * adapted from Remy Card's ext2/ioctl.c 7ca4d147eSHerbert Poetzl */ 8ca4d147eSHerbert Poetzl 9ca4d147eSHerbert Poetzl #include <linux/fs.h> 10ca4d147eSHerbert Poetzl #include <linux/mount.h> 1119e8ac27SJie Liu #include <linux/blkdev.h> 1234e6c59aSTao Ma #include <linux/compat.h> 13ca4d147eSHerbert Poetzl 14ca4d147eSHerbert Poetzl #include <cluster/masklog.h> 15ca4d147eSHerbert Poetzl 16ca4d147eSHerbert Poetzl #include "ocfs2.h" 17ca4d147eSHerbert Poetzl #include "alloc.h" 18ca4d147eSHerbert Poetzl #include "dlmglue.h" 19b2580103SMark Fasheh #include "file.h" 20ca4d147eSHerbert Poetzl #include "inode.h" 21ca4d147eSHerbert Poetzl #include "journal.h" 22ca4d147eSHerbert Poetzl 23ca4d147eSHerbert Poetzl #include "ocfs2_fs.h" 242d562518SAdrian Bunk #include "ioctl.h" 25d659072fSTao Ma #include "resize.h" 26bd50873dSTao Ma #include "refcounttree.h" 273e5db17dSTristan Ye #include "sysfile.h" 283e5db17dSTristan Ye #include "dir.h" 293e5db17dSTristan Ye #include "buffer_head_io.h" 30d24a10b9STristan Ye #include "suballoc.h" 3153069d4eSTristan Ye #include "move_extents.h" 322d562518SAdrian Bunk 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 /* 392b462638SBen Hutchings * This is just a best-effort to tell userspace that this request 402b462638SBen Hutchings * caused the error. 41ddee5cdbSTristan Ye */ 428aa1fa36STristan Ye static inline void o2info_set_request_error(struct ocfs2_info_request *kreq, 43ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 44ddee5cdbSTristan Ye { 45ddee5cdbSTristan Ye kreq->ir_flags |= OCFS2_INFO_FL_ERROR; 46ddee5cdbSTristan Ye (void)put_user(kreq->ir_flags, (__u32 __user *)&(req->ir_flags)); 47ddee5cdbSTristan Ye } 48ddee5cdbSTristan Ye 498aa1fa36STristan Ye static inline void o2info_set_request_filled(struct ocfs2_info_request *req) 501936a267STristan Ye { 511936a267STristan Ye req->ir_flags |= OCFS2_INFO_FL_FILLED; 521936a267STristan Ye } 531936a267STristan Ye 548aa1fa36STristan Ye static inline void o2info_clear_request_filled(struct ocfs2_info_request *req) 551936a267STristan Ye { 561936a267STristan Ye req->ir_flags &= ~OCFS2_INFO_FL_FILLED; 571936a267STristan Ye } 581936a267STristan Ye 593e5db17dSTristan Ye static inline int o2info_coherent(struct ocfs2_info_request *req) 603e5db17dSTristan Ye { 613e5db17dSTristan Ye return (!(req->ir_flags & OCFS2_INFO_FL_NON_COHERENT)); 623e5db17dSTristan Ye } 631936a267STristan Ye 64ca4d147eSHerbert Poetzl static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags) 65ca4d147eSHerbert Poetzl { 66ca4d147eSHerbert Poetzl int status; 67ca4d147eSHerbert Poetzl 68e63aecb6SMark Fasheh status = ocfs2_inode_lock(inode, NULL, 0); 69ca4d147eSHerbert Poetzl if (status < 0) { 70ca4d147eSHerbert Poetzl mlog_errno(status); 71ca4d147eSHerbert Poetzl return status; 72ca4d147eSHerbert Poetzl } 736e4b0d56SJan Kara ocfs2_get_inode_flags(OCFS2_I(inode)); 74ca4d147eSHerbert Poetzl *flags = OCFS2_I(inode)->ip_attr; 75e63aecb6SMark Fasheh ocfs2_inode_unlock(inode, 0); 76ca4d147eSHerbert Poetzl 77ca4d147eSHerbert Poetzl return status; 78ca4d147eSHerbert Poetzl } 79ca4d147eSHerbert Poetzl 80ca4d147eSHerbert Poetzl static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, 81ca4d147eSHerbert Poetzl unsigned mask) 82ca4d147eSHerbert Poetzl { 83ca4d147eSHerbert Poetzl struct ocfs2_inode_info *ocfs2_inode = OCFS2_I(inode); 84ca4d147eSHerbert Poetzl struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 851fabe148SMark Fasheh handle_t *handle = NULL; 86ca4d147eSHerbert Poetzl struct buffer_head *bh = NULL; 87ca4d147eSHerbert Poetzl unsigned oldflags; 88ca4d147eSHerbert Poetzl int status; 89ca4d147eSHerbert Poetzl 905955102cSAl Viro inode_lock(inode); 91ca4d147eSHerbert Poetzl 92e63aecb6SMark Fasheh status = ocfs2_inode_lock(inode, &bh, 1); 93ca4d147eSHerbert Poetzl if (status < 0) { 94ca4d147eSHerbert Poetzl mlog_errno(status); 95ca4d147eSHerbert Poetzl goto bail; 96ca4d147eSHerbert Poetzl } 97ca4d147eSHerbert Poetzl 98ca4d147eSHerbert Poetzl status = -EACCES; 992e149670SSerge E. Hallyn if (!inode_owner_or_capable(inode)) 100ca4d147eSHerbert Poetzl goto bail_unlock; 101ca4d147eSHerbert Poetzl 102ca4d147eSHerbert Poetzl if (!S_ISDIR(inode->i_mode)) 103ca4d147eSHerbert Poetzl flags &= ~OCFS2_DIRSYNC_FL; 104ca4d147eSHerbert Poetzl 105ca4d147eSHerbert Poetzl oldflags = ocfs2_inode->ip_attr; 106ca4d147eSHerbert Poetzl flags = flags & mask; 107ca4d147eSHerbert Poetzl flags |= oldflags & ~mask; 108ca4d147eSHerbert Poetzl 109ca4d147eSHerbert Poetzl /* 110ca4d147eSHerbert Poetzl * The IMMUTABLE and APPEND_ONLY flags can only be changed by 111ca4d147eSHerbert Poetzl * the relevant capability. 112ca4d147eSHerbert Poetzl */ 113ca4d147eSHerbert Poetzl status = -EPERM; 114ca4d147eSHerbert Poetzl if ((oldflags & OCFS2_IMMUTABLE_FL) || ((flags ^ oldflags) & 115ca4d147eSHerbert Poetzl (OCFS2_APPEND_FL | OCFS2_IMMUTABLE_FL))) { 116ca4d147eSHerbert Poetzl if (!capable(CAP_LINUX_IMMUTABLE)) 117b3e0767aSJeff Liu goto bail_unlock; 118b3e0767aSJeff Liu } 119b3e0767aSJeff Liu 120b3e0767aSJeff Liu handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); 121b3e0767aSJeff Liu if (IS_ERR(handle)) { 122b3e0767aSJeff Liu status = PTR_ERR(handle); 123b3e0767aSJeff Liu mlog_errno(status); 124b3e0767aSJeff Liu goto bail_unlock; 125ca4d147eSHerbert Poetzl } 126ca4d147eSHerbert Poetzl 127ca4d147eSHerbert Poetzl ocfs2_inode->ip_attr = flags; 128ca4d147eSHerbert Poetzl ocfs2_set_inode_flags(inode); 129ca4d147eSHerbert Poetzl 130ca4d147eSHerbert Poetzl status = ocfs2_mark_inode_dirty(handle, inode, bh); 131ca4d147eSHerbert Poetzl if (status < 0) 132ca4d147eSHerbert Poetzl mlog_errno(status); 133ca4d147eSHerbert Poetzl 13402dc1af4SMark Fasheh ocfs2_commit_trans(osb, handle); 135b3e0767aSJeff Liu 136ca4d147eSHerbert Poetzl bail_unlock: 137e63aecb6SMark Fasheh ocfs2_inode_unlock(inode, 1); 138ca4d147eSHerbert Poetzl bail: 1395955102cSAl Viro inode_unlock(inode); 140ca4d147eSHerbert Poetzl 141ca4d147eSHerbert Poetzl brelse(bh); 142ca4d147eSHerbert Poetzl 143ca4d147eSHerbert Poetzl return status; 144ca4d147eSHerbert Poetzl } 145ca4d147eSHerbert Poetzl 146c253ed1fSFabian Frederick static int ocfs2_info_handle_blocksize(struct inode *inode, 147ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 148ddee5cdbSTristan Ye { 149ddee5cdbSTristan Ye struct ocfs2_info_blocksize oib; 150ddee5cdbSTristan Ye 151ddee5cdbSTristan Ye if (o2info_from_user(oib, req)) 1522b462638SBen Hutchings return -EFAULT; 153ddee5cdbSTristan Ye 154ddee5cdbSTristan Ye oib.ib_blocksize = inode->i_sb->s_blocksize; 1551936a267STristan Ye 1568aa1fa36STristan Ye o2info_set_request_filled(&oib.ib_req); 157ddee5cdbSTristan Ye 158ddee5cdbSTristan Ye if (o2info_to_user(oib, req)) 1592b462638SBen Hutchings return -EFAULT; 160ddee5cdbSTristan Ye 1612b462638SBen Hutchings return 0; 162ddee5cdbSTristan Ye } 163ddee5cdbSTristan Ye 164c253ed1fSFabian Frederick static int ocfs2_info_handle_clustersize(struct inode *inode, 165ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 166ddee5cdbSTristan Ye { 167ddee5cdbSTristan Ye struct ocfs2_info_clustersize oic; 168ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 169ddee5cdbSTristan Ye 170ddee5cdbSTristan Ye if (o2info_from_user(oic, req)) 1712b462638SBen Hutchings return -EFAULT; 172ddee5cdbSTristan Ye 173ddee5cdbSTristan Ye oic.ic_clustersize = osb->s_clustersize; 1741936a267STristan Ye 1758aa1fa36STristan Ye o2info_set_request_filled(&oic.ic_req); 176ddee5cdbSTristan Ye 177ddee5cdbSTristan Ye if (o2info_to_user(oic, req)) 1782b462638SBen Hutchings return -EFAULT; 179ddee5cdbSTristan Ye 1802b462638SBen Hutchings return 0; 181ddee5cdbSTristan Ye } 182ddee5cdbSTristan Ye 183c253ed1fSFabian Frederick static int ocfs2_info_handle_maxslots(struct inode *inode, 184ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 185ddee5cdbSTristan Ye { 186ddee5cdbSTristan Ye struct ocfs2_info_maxslots oim; 187ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 188ddee5cdbSTristan Ye 189ddee5cdbSTristan Ye if (o2info_from_user(oim, req)) 1902b462638SBen Hutchings return -EFAULT; 191ddee5cdbSTristan Ye 192ddee5cdbSTristan Ye oim.im_max_slots = osb->max_slots; 1931936a267STristan Ye 1948aa1fa36STristan Ye o2info_set_request_filled(&oim.im_req); 195ddee5cdbSTristan Ye 196ddee5cdbSTristan Ye if (o2info_to_user(oim, req)) 1972b462638SBen Hutchings return -EFAULT; 198ddee5cdbSTristan Ye 1992b462638SBen Hutchings return 0; 200ddee5cdbSTristan Ye } 201ddee5cdbSTristan Ye 202c253ed1fSFabian Frederick static int ocfs2_info_handle_label(struct inode *inode, 203ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 204ddee5cdbSTristan Ye { 205ddee5cdbSTristan Ye struct ocfs2_info_label oil; 206ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 207ddee5cdbSTristan Ye 208ddee5cdbSTristan Ye if (o2info_from_user(oil, req)) 2092b462638SBen Hutchings return -EFAULT; 210ddee5cdbSTristan Ye 211ddee5cdbSTristan Ye memcpy(oil.il_label, osb->vol_label, OCFS2_MAX_VOL_LABEL_LEN); 2121936a267STristan Ye 2138aa1fa36STristan Ye o2info_set_request_filled(&oil.il_req); 214ddee5cdbSTristan Ye 215ddee5cdbSTristan Ye if (o2info_to_user(oil, req)) 2162b462638SBen Hutchings return -EFAULT; 217ddee5cdbSTristan Ye 2182b462638SBen Hutchings return 0; 219ddee5cdbSTristan Ye } 220ddee5cdbSTristan Ye 221c253ed1fSFabian Frederick static int ocfs2_info_handle_uuid(struct inode *inode, 222ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 223ddee5cdbSTristan Ye { 224ddee5cdbSTristan Ye struct ocfs2_info_uuid oiu; 225ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 226ddee5cdbSTristan Ye 227ddee5cdbSTristan Ye if (o2info_from_user(oiu, req)) 2282b462638SBen Hutchings return -EFAULT; 229ddee5cdbSTristan Ye 230ddee5cdbSTristan Ye memcpy(oiu.iu_uuid_str, osb->uuid_str, OCFS2_TEXT_UUID_LEN + 1); 2311936a267STristan Ye 2328aa1fa36STristan Ye o2info_set_request_filled(&oiu.iu_req); 233ddee5cdbSTristan Ye 234ddee5cdbSTristan Ye if (o2info_to_user(oiu, req)) 2352b462638SBen Hutchings return -EFAULT; 236ddee5cdbSTristan Ye 2372b462638SBen Hutchings return 0; 238ddee5cdbSTristan Ye } 239ddee5cdbSTristan Ye 240c253ed1fSFabian Frederick static int ocfs2_info_handle_fs_features(struct inode *inode, 241ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 242ddee5cdbSTristan Ye { 243ddee5cdbSTristan Ye struct ocfs2_info_fs_features oif; 244ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 245ddee5cdbSTristan Ye 246ddee5cdbSTristan Ye if (o2info_from_user(oif, req)) 2472b462638SBen Hutchings return -EFAULT; 248ddee5cdbSTristan Ye 249ddee5cdbSTristan Ye oif.if_compat_features = osb->s_feature_compat; 250ddee5cdbSTristan Ye oif.if_incompat_features = osb->s_feature_incompat; 251ddee5cdbSTristan Ye oif.if_ro_compat_features = osb->s_feature_ro_compat; 2521936a267STristan Ye 2538aa1fa36STristan Ye o2info_set_request_filled(&oif.if_req); 254ddee5cdbSTristan Ye 255ddee5cdbSTristan Ye if (o2info_to_user(oif, req)) 2562b462638SBen Hutchings return -EFAULT; 257ddee5cdbSTristan Ye 2582b462638SBen Hutchings return 0; 259ddee5cdbSTristan Ye } 260ddee5cdbSTristan Ye 261c253ed1fSFabian Frederick static int ocfs2_info_handle_journal_size(struct inode *inode, 262ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 263ddee5cdbSTristan Ye { 264ddee5cdbSTristan Ye struct ocfs2_info_journal_size oij; 265ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 266ddee5cdbSTristan Ye 267ddee5cdbSTristan Ye if (o2info_from_user(oij, req)) 2682b462638SBen Hutchings return -EFAULT; 269ddee5cdbSTristan Ye 270f17c20ddSJunxiao Bi oij.ij_journal_size = i_size_read(osb->journal->j_inode); 271ddee5cdbSTristan Ye 2728aa1fa36STristan Ye o2info_set_request_filled(&oij.ij_req); 273ddee5cdbSTristan Ye 274ddee5cdbSTristan Ye if (o2info_to_user(oij, req)) 2752b462638SBen Hutchings return -EFAULT; 276ddee5cdbSTristan Ye 2772b462638SBen Hutchings return 0; 278ddee5cdbSTristan Ye } 279ddee5cdbSTristan Ye 280c253ed1fSFabian Frederick static int ocfs2_info_scan_inode_alloc(struct ocfs2_super *osb, 2813e5db17dSTristan Ye struct inode *inode_alloc, u64 blkno, 282c253ed1fSFabian Frederick struct ocfs2_info_freeinode *fi, 283c253ed1fSFabian Frederick u32 slot) 2843e5db17dSTristan Ye { 2853e5db17dSTristan Ye int status = 0, unlock = 0; 2863e5db17dSTristan Ye 2873e5db17dSTristan Ye struct buffer_head *bh = NULL; 2883e5db17dSTristan Ye struct ocfs2_dinode *dinode_alloc = NULL; 2893e5db17dSTristan Ye 2903e5db17dSTristan Ye if (inode_alloc) 2915955102cSAl Viro inode_lock(inode_alloc); 2923e5db17dSTristan Ye 2933e5db17dSTristan Ye if (o2info_coherent(&fi->ifi_req)) { 2943e5db17dSTristan Ye status = ocfs2_inode_lock(inode_alloc, &bh, 0); 2953e5db17dSTristan Ye if (status < 0) { 2963e5db17dSTristan Ye mlog_errno(status); 2973e5db17dSTristan Ye goto bail; 2983e5db17dSTristan Ye } 2993e5db17dSTristan Ye unlock = 1; 3003e5db17dSTristan Ye } else { 3013e5db17dSTristan Ye status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); 3023e5db17dSTristan Ye if (status < 0) { 3033e5db17dSTristan Ye mlog_errno(status); 3043e5db17dSTristan Ye goto bail; 3053e5db17dSTristan Ye } 3063e5db17dSTristan Ye } 3073e5db17dSTristan Ye 3083e5db17dSTristan Ye dinode_alloc = (struct ocfs2_dinode *)bh->b_data; 3093e5db17dSTristan Ye 3103e5db17dSTristan Ye fi->ifi_stat[slot].lfi_total = 3113e5db17dSTristan Ye le32_to_cpu(dinode_alloc->id1.bitmap1.i_total); 3123e5db17dSTristan Ye fi->ifi_stat[slot].lfi_free = 3133e5db17dSTristan Ye le32_to_cpu(dinode_alloc->id1.bitmap1.i_total) - 3143e5db17dSTristan Ye le32_to_cpu(dinode_alloc->id1.bitmap1.i_used); 3153e5db17dSTristan Ye 3163e5db17dSTristan Ye bail: 3173e5db17dSTristan Ye if (unlock) 3183e5db17dSTristan Ye ocfs2_inode_unlock(inode_alloc, 0); 3193e5db17dSTristan Ye 3203e5db17dSTristan Ye if (inode_alloc) 3215955102cSAl Viro inode_unlock(inode_alloc); 3223e5db17dSTristan Ye 3233e5db17dSTristan Ye brelse(bh); 3243e5db17dSTristan Ye 3253e5db17dSTristan Ye return status; 3263e5db17dSTristan Ye } 3273e5db17dSTristan Ye 328c253ed1fSFabian Frederick static int ocfs2_info_handle_freeinode(struct inode *inode, 3293e5db17dSTristan Ye struct ocfs2_info_request __user *req) 3303e5db17dSTristan Ye { 3313e5db17dSTristan Ye u32 i; 3323e5db17dSTristan Ye u64 blkno = -1; 3333e5db17dSTristan Ye char namebuf[40]; 3342b462638SBen Hutchings int status, type = INODE_ALLOC_SYSTEM_INODE; 3353e5db17dSTristan Ye struct ocfs2_info_freeinode *oifi = NULL; 3363e5db17dSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 3373e5db17dSTristan Ye struct inode *inode_alloc = NULL; 3383e5db17dSTristan Ye 3393e5db17dSTristan Ye oifi = kzalloc(sizeof(struct ocfs2_info_freeinode), GFP_KERNEL); 3403e5db17dSTristan Ye if (!oifi) { 3413e5db17dSTristan Ye status = -ENOMEM; 3423e5db17dSTristan Ye mlog_errno(status); 34387f0d5c8SDan Carpenter goto out_err; 3443e5db17dSTristan Ye } 3453e5db17dSTristan Ye 3462b462638SBen Hutchings if (o2info_from_user(*oifi, req)) { 3472b462638SBen Hutchings status = -EFAULT; 3482b462638SBen Hutchings goto out_free; 3492b462638SBen Hutchings } 3503e5db17dSTristan Ye 3513e5db17dSTristan Ye oifi->ifi_slotnum = osb->max_slots; 3523e5db17dSTristan Ye 3533e5db17dSTristan Ye for (i = 0; i < oifi->ifi_slotnum; i++) { 3543e5db17dSTristan Ye if (o2info_coherent(&oifi->ifi_req)) { 3553e5db17dSTristan Ye inode_alloc = ocfs2_get_system_file_inode(osb, type, i); 3563e5db17dSTristan Ye if (!inode_alloc) { 3573e5db17dSTristan Ye mlog(ML_ERROR, "unable to get alloc inode in " 3583e5db17dSTristan Ye "slot %u\n", i); 3593e5db17dSTristan Ye status = -EIO; 3603e5db17dSTristan Ye goto bail; 3613e5db17dSTristan Ye } 3623e5db17dSTristan Ye } else { 3633e5db17dSTristan Ye ocfs2_sprintf_system_inode_name(namebuf, 3643e5db17dSTristan Ye sizeof(namebuf), 3653e5db17dSTristan Ye type, i); 3663e5db17dSTristan Ye status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, 3673e5db17dSTristan Ye namebuf, 3683e5db17dSTristan Ye strlen(namebuf), 3693e5db17dSTristan Ye &blkno); 3703e5db17dSTristan Ye if (status < 0) { 3713e5db17dSTristan Ye status = -ENOENT; 3723e5db17dSTristan Ye goto bail; 3733e5db17dSTristan Ye } 3743e5db17dSTristan Ye } 3753e5db17dSTristan Ye 3763e5db17dSTristan Ye status = ocfs2_info_scan_inode_alloc(osb, inode_alloc, blkno, oifi, i); 3773e5db17dSTristan Ye 3783e5db17dSTristan Ye iput(inode_alloc); 3793e5db17dSTristan Ye inode_alloc = NULL; 3807dc3e839Sjiangyiwen 3817dc3e839Sjiangyiwen if (status < 0) 3827dc3e839Sjiangyiwen goto bail; 3833e5db17dSTristan Ye } 3843e5db17dSTristan Ye 3853e5db17dSTristan Ye o2info_set_request_filled(&oifi->ifi_req); 3863e5db17dSTristan Ye 3872b462638SBen Hutchings if (o2info_to_user(*oifi, req)) { 3882b462638SBen Hutchings status = -EFAULT; 3892b462638SBen Hutchings goto out_free; 3902b462638SBen Hutchings } 3913e5db17dSTristan Ye 3923e5db17dSTristan Ye status = 0; 3933e5db17dSTristan Ye bail: 3943e5db17dSTristan Ye if (status) 3953e5db17dSTristan Ye o2info_set_request_error(&oifi->ifi_req, req); 3962b462638SBen Hutchings out_free: 3973e5db17dSTristan Ye kfree(oifi); 39887f0d5c8SDan Carpenter out_err: 3993e5db17dSTristan Ye return status; 4003e5db17dSTristan Ye } 4013e5db17dSTristan Ye 402d24a10b9STristan Ye static void o2ffg_update_histogram(struct ocfs2_info_free_chunk_list *hist, 403d24a10b9STristan Ye unsigned int chunksize) 404d24a10b9STristan Ye { 405d24a10b9STristan Ye int index; 406d24a10b9STristan Ye 407d24a10b9STristan Ye index = __ilog2_u32(chunksize); 408d24a10b9STristan Ye if (index >= OCFS2_INFO_MAX_HIST) 409d24a10b9STristan Ye index = OCFS2_INFO_MAX_HIST - 1; 410d24a10b9STristan Ye 411d24a10b9STristan Ye hist->fc_chunks[index]++; 412d24a10b9STristan Ye hist->fc_clusters[index] += chunksize; 413d24a10b9STristan Ye } 414d24a10b9STristan Ye 415d24a10b9STristan Ye static void o2ffg_update_stats(struct ocfs2_info_freefrag_stats *stats, 416d24a10b9STristan Ye unsigned int chunksize) 417d24a10b9STristan Ye { 418d24a10b9STristan Ye if (chunksize > stats->ffs_max) 419d24a10b9STristan Ye stats->ffs_max = chunksize; 420d24a10b9STristan Ye 421d24a10b9STristan Ye if (chunksize < stats->ffs_min) 422d24a10b9STristan Ye stats->ffs_min = chunksize; 423d24a10b9STristan Ye 424d24a10b9STristan Ye stats->ffs_avg += chunksize; 425d24a10b9STristan Ye stats->ffs_free_chunks_real++; 426d24a10b9STristan Ye } 427d24a10b9STristan Ye 428c253ed1fSFabian Frederick static void ocfs2_info_update_ffg(struct ocfs2_info_freefrag *ffg, 429d24a10b9STristan Ye unsigned int chunksize) 430d24a10b9STristan Ye { 431d24a10b9STristan Ye o2ffg_update_histogram(&(ffg->iff_ffs.ffs_fc_hist), chunksize); 432d24a10b9STristan Ye o2ffg_update_stats(&(ffg->iff_ffs), chunksize); 433d24a10b9STristan Ye } 434d24a10b9STristan Ye 435c253ed1fSFabian Frederick static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, 436d24a10b9STristan Ye struct inode *gb_inode, 437d24a10b9STristan Ye struct ocfs2_dinode *gb_dinode, 438d24a10b9STristan Ye struct ocfs2_chain_rec *rec, 439d24a10b9STristan Ye struct ocfs2_info_freefrag *ffg, 440d24a10b9STristan Ye u32 chunks_in_group) 441d24a10b9STristan Ye { 442d24a10b9STristan Ye int status = 0, used; 443d24a10b9STristan Ye u64 blkno; 444d24a10b9STristan Ye 445d24a10b9STristan Ye struct buffer_head *bh = NULL; 446d24a10b9STristan Ye struct ocfs2_group_desc *bg = NULL; 447d24a10b9STristan Ye 448d24a10b9STristan Ye unsigned int max_bits, num_clusters; 449d24a10b9STristan Ye unsigned int offset = 0, cluster, chunk; 450d24a10b9STristan Ye unsigned int chunk_free, last_chunksize = 0; 451d24a10b9STristan Ye 452d24a10b9STristan Ye if (!le32_to_cpu(rec->c_free)) 453d24a10b9STristan Ye goto bail; 454d24a10b9STristan Ye 455d24a10b9STristan Ye do { 456d24a10b9STristan Ye if (!bg) 457d24a10b9STristan Ye blkno = le64_to_cpu(rec->c_blkno); 458d24a10b9STristan Ye else 459d24a10b9STristan Ye blkno = le64_to_cpu(bg->bg_next_group); 460d24a10b9STristan Ye 461d24a10b9STristan Ye if (bh) { 462d24a10b9STristan Ye brelse(bh); 463d24a10b9STristan Ye bh = NULL; 464d24a10b9STristan Ye } 465d24a10b9STristan Ye 466d24a10b9STristan Ye if (o2info_coherent(&ffg->iff_req)) 467d24a10b9STristan Ye status = ocfs2_read_group_descriptor(gb_inode, 468d24a10b9STristan Ye gb_dinode, 469d24a10b9STristan Ye blkno, &bh); 470d24a10b9STristan Ye else 471d24a10b9STristan Ye status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); 472d24a10b9STristan Ye 473d24a10b9STristan Ye if (status < 0) { 474d24a10b9STristan Ye mlog(ML_ERROR, "Can't read the group descriptor # " 475d24a10b9STristan Ye "%llu from device.", (unsigned long long)blkno); 476d24a10b9STristan Ye status = -EIO; 477d24a10b9STristan Ye goto bail; 478d24a10b9STristan Ye } 479d24a10b9STristan Ye 480d24a10b9STristan Ye bg = (struct ocfs2_group_desc *)bh->b_data; 481d24a10b9STristan Ye 482d24a10b9STristan Ye if (!le16_to_cpu(bg->bg_free_bits_count)) 483d24a10b9STristan Ye continue; 484d24a10b9STristan Ye 485d24a10b9STristan Ye max_bits = le16_to_cpu(bg->bg_bits); 486d24a10b9STristan Ye offset = 0; 487d24a10b9STristan Ye 488d24a10b9STristan Ye for (chunk = 0; chunk < chunks_in_group; chunk++) { 489d24a10b9STristan Ye /* 490d24a10b9STristan Ye * last chunk may be not an entire one. 491d24a10b9STristan Ye */ 492d24a10b9STristan Ye if ((offset + ffg->iff_chunksize) > max_bits) 493d24a10b9STristan Ye num_clusters = max_bits - offset; 494d24a10b9STristan Ye else 495d24a10b9STristan Ye num_clusters = ffg->iff_chunksize; 496d24a10b9STristan Ye 497d24a10b9STristan Ye chunk_free = 0; 498d24a10b9STristan Ye for (cluster = 0; cluster < num_clusters; cluster++) { 499d24a10b9STristan Ye used = ocfs2_test_bit(offset, 500d24a10b9STristan Ye (unsigned long *)bg->bg_bitmap); 501d24a10b9STristan Ye /* 502d24a10b9STristan Ye * - chunk_free counts free clusters in #N chunk. 503d24a10b9STristan Ye * - last_chunksize records the size(in) clusters 504d24a10b9STristan Ye * for the last real free chunk being counted. 505d24a10b9STristan Ye */ 506d24a10b9STristan Ye if (!used) { 507d24a10b9STristan Ye last_chunksize++; 508d24a10b9STristan Ye chunk_free++; 509d24a10b9STristan Ye } 510d24a10b9STristan Ye 511d24a10b9STristan Ye if (used && last_chunksize) { 512d24a10b9STristan Ye ocfs2_info_update_ffg(ffg, 513d24a10b9STristan Ye last_chunksize); 514d24a10b9STristan Ye last_chunksize = 0; 515d24a10b9STristan Ye } 516d24a10b9STristan Ye 517d24a10b9STristan Ye offset++; 518d24a10b9STristan Ye } 519d24a10b9STristan Ye 520d24a10b9STristan Ye if (chunk_free == ffg->iff_chunksize) 521d24a10b9STristan Ye ffg->iff_ffs.ffs_free_chunks++; 522d24a10b9STristan Ye } 523d24a10b9STristan Ye 524d24a10b9STristan Ye /* 525d24a10b9STristan Ye * need to update the info for last free chunk. 526d24a10b9STristan Ye */ 527d24a10b9STristan Ye if (last_chunksize) 528d24a10b9STristan Ye ocfs2_info_update_ffg(ffg, last_chunksize); 529d24a10b9STristan Ye 530d24a10b9STristan Ye } while (le64_to_cpu(bg->bg_next_group)); 531d24a10b9STristan Ye 532d24a10b9STristan Ye bail: 533d24a10b9STristan Ye brelse(bh); 534d24a10b9STristan Ye 535d24a10b9STristan Ye return status; 536d24a10b9STristan Ye } 537d24a10b9STristan Ye 538c253ed1fSFabian Frederick static int ocfs2_info_freefrag_scan_bitmap(struct ocfs2_super *osb, 539d24a10b9STristan Ye struct inode *gb_inode, u64 blkno, 540d24a10b9STristan Ye struct ocfs2_info_freefrag *ffg) 541d24a10b9STristan Ye { 542d24a10b9STristan Ye u32 chunks_in_group; 543d24a10b9STristan Ye int status = 0, unlock = 0, i; 544d24a10b9STristan Ye 545d24a10b9STristan Ye struct buffer_head *bh = NULL; 546d24a10b9STristan Ye struct ocfs2_chain_list *cl = NULL; 547d24a10b9STristan Ye struct ocfs2_chain_rec *rec = NULL; 548d24a10b9STristan Ye struct ocfs2_dinode *gb_dinode = NULL; 549d24a10b9STristan Ye 550d24a10b9STristan Ye if (gb_inode) 5515955102cSAl Viro inode_lock(gb_inode); 552d24a10b9STristan Ye 553d24a10b9STristan Ye if (o2info_coherent(&ffg->iff_req)) { 554d24a10b9STristan Ye status = ocfs2_inode_lock(gb_inode, &bh, 0); 555d24a10b9STristan Ye if (status < 0) { 556d24a10b9STristan Ye mlog_errno(status); 557d24a10b9STristan Ye goto bail; 558d24a10b9STristan Ye } 559d24a10b9STristan Ye unlock = 1; 560d24a10b9STristan Ye } else { 561d24a10b9STristan Ye status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); 562d24a10b9STristan Ye if (status < 0) { 563d24a10b9STristan Ye mlog_errno(status); 564d24a10b9STristan Ye goto bail; 565d24a10b9STristan Ye } 566d24a10b9STristan Ye } 567d24a10b9STristan Ye 568d24a10b9STristan Ye gb_dinode = (struct ocfs2_dinode *)bh->b_data; 569d24a10b9STristan Ye cl = &(gb_dinode->id2.i_chain); 570d24a10b9STristan Ye 571d24a10b9STristan Ye /* 572d24a10b9STristan Ye * Chunksize(in) clusters from userspace should be 573d24a10b9STristan Ye * less than clusters in a group. 574d24a10b9STristan Ye */ 575d24a10b9STristan Ye if (ffg->iff_chunksize > le16_to_cpu(cl->cl_cpg)) { 576d24a10b9STristan Ye status = -EINVAL; 577d24a10b9STristan Ye goto bail; 578d24a10b9STristan Ye } 579d24a10b9STristan Ye 580d24a10b9STristan Ye memset(&ffg->iff_ffs, 0, sizeof(struct ocfs2_info_freefrag_stats)); 581d24a10b9STristan Ye 582d24a10b9STristan Ye ffg->iff_ffs.ffs_min = ~0U; 583d24a10b9STristan Ye ffg->iff_ffs.ffs_clusters = 584d24a10b9STristan Ye le32_to_cpu(gb_dinode->id1.bitmap1.i_total); 585d24a10b9STristan Ye ffg->iff_ffs.ffs_free_clusters = ffg->iff_ffs.ffs_clusters - 586d24a10b9STristan Ye le32_to_cpu(gb_dinode->id1.bitmap1.i_used); 587d24a10b9STristan Ye 588d24a10b9STristan Ye chunks_in_group = le16_to_cpu(cl->cl_cpg) / ffg->iff_chunksize + 1; 589d24a10b9STristan Ye 590d24a10b9STristan Ye for (i = 0; i < le16_to_cpu(cl->cl_next_free_rec); i++) { 591d24a10b9STristan Ye rec = &(cl->cl_recs[i]); 592d24a10b9STristan Ye status = ocfs2_info_freefrag_scan_chain(osb, gb_inode, 593d24a10b9STristan Ye gb_dinode, 594d24a10b9STristan Ye rec, ffg, 595d24a10b9STristan Ye chunks_in_group); 596d24a10b9STristan Ye if (status) 597d24a10b9STristan Ye goto bail; 598d24a10b9STristan Ye } 599d24a10b9STristan Ye 600d24a10b9STristan Ye if (ffg->iff_ffs.ffs_free_chunks_real) 601d24a10b9STristan Ye ffg->iff_ffs.ffs_avg = (ffg->iff_ffs.ffs_avg / 602d24a10b9STristan Ye ffg->iff_ffs.ffs_free_chunks_real); 603d24a10b9STristan Ye bail: 604d24a10b9STristan Ye if (unlock) 605d24a10b9STristan Ye ocfs2_inode_unlock(gb_inode, 0); 606d24a10b9STristan Ye 607d24a10b9STristan Ye if (gb_inode) 6085955102cSAl Viro inode_unlock(gb_inode); 609d24a10b9STristan Ye 610d24a10b9STristan Ye iput(gb_inode); 611d24a10b9STristan Ye brelse(bh); 612d24a10b9STristan Ye 613d24a10b9STristan Ye return status; 614d24a10b9STristan Ye } 615d24a10b9STristan Ye 616c253ed1fSFabian Frederick static int ocfs2_info_handle_freefrag(struct inode *inode, 617d24a10b9STristan Ye struct ocfs2_info_request __user *req) 618d24a10b9STristan Ye { 619d24a10b9STristan Ye u64 blkno = -1; 620d24a10b9STristan Ye char namebuf[40]; 6212b462638SBen Hutchings int status, type = GLOBAL_BITMAP_SYSTEM_INODE; 622d24a10b9STristan Ye 623d24a10b9STristan Ye struct ocfs2_info_freefrag *oiff; 624d24a10b9STristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 625d24a10b9STristan Ye struct inode *gb_inode = NULL; 626d24a10b9STristan Ye 627d24a10b9STristan Ye oiff = kzalloc(sizeof(struct ocfs2_info_freefrag), GFP_KERNEL); 628d24a10b9STristan Ye if (!oiff) { 629d24a10b9STristan Ye status = -ENOMEM; 630d24a10b9STristan Ye mlog_errno(status); 63187f0d5c8SDan Carpenter goto out_err; 632d24a10b9STristan Ye } 633d24a10b9STristan Ye 6342b462638SBen Hutchings if (o2info_from_user(*oiff, req)) { 6352b462638SBen Hutchings status = -EFAULT; 6362b462638SBen Hutchings goto out_free; 6372b462638SBen Hutchings } 638d24a10b9STristan Ye /* 639d24a10b9STristan Ye * chunksize from userspace should be power of 2. 640d24a10b9STristan Ye */ 641d24a10b9STristan Ye if ((oiff->iff_chunksize & (oiff->iff_chunksize - 1)) || 642d24a10b9STristan Ye (!oiff->iff_chunksize)) { 643d24a10b9STristan Ye status = -EINVAL; 644d24a10b9STristan Ye goto bail; 645d24a10b9STristan Ye } 646d24a10b9STristan Ye 647d24a10b9STristan Ye if (o2info_coherent(&oiff->iff_req)) { 648d24a10b9STristan Ye gb_inode = ocfs2_get_system_file_inode(osb, type, 649d24a10b9STristan Ye OCFS2_INVALID_SLOT); 650d24a10b9STristan Ye if (!gb_inode) { 651d24a10b9STristan Ye mlog(ML_ERROR, "unable to get global_bitmap inode\n"); 652d24a10b9STristan Ye status = -EIO; 653d24a10b9STristan Ye goto bail; 654d24a10b9STristan Ye } 655d24a10b9STristan Ye } else { 656d24a10b9STristan Ye ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type, 657d24a10b9STristan Ye OCFS2_INVALID_SLOT); 658d24a10b9STristan Ye status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, 659d24a10b9STristan Ye namebuf, 660d24a10b9STristan Ye strlen(namebuf), 661d24a10b9STristan Ye &blkno); 662d24a10b9STristan Ye if (status < 0) { 663d24a10b9STristan Ye status = -ENOENT; 664d24a10b9STristan Ye goto bail; 665d24a10b9STristan Ye } 666d24a10b9STristan Ye } 667d24a10b9STristan Ye 668d24a10b9STristan Ye status = ocfs2_info_freefrag_scan_bitmap(osb, gb_inode, blkno, oiff); 669d24a10b9STristan Ye if (status < 0) 670d24a10b9STristan Ye goto bail; 671d24a10b9STristan Ye 672d24a10b9STristan Ye o2info_set_request_filled(&oiff->iff_req); 673d24a10b9STristan Ye 6747ebab453SWei Yongjun if (o2info_to_user(*oiff, req)) { 6757ebab453SWei Yongjun status = -EFAULT; 6762b462638SBen Hutchings goto out_free; 6777ebab453SWei Yongjun } 678d24a10b9STristan Ye 679d24a10b9STristan Ye status = 0; 680d24a10b9STristan Ye bail: 681d24a10b9STristan Ye if (status) 682d24a10b9STristan Ye o2info_set_request_error(&oiff->iff_req, req); 6832b462638SBen Hutchings out_free: 684d24a10b9STristan Ye kfree(oiff); 68587f0d5c8SDan Carpenter out_err: 686ddee5cdbSTristan Ye return status; 687ddee5cdbSTristan Ye } 688ddee5cdbSTristan Ye 689c253ed1fSFabian Frederick static int ocfs2_info_handle_unknown(struct inode *inode, 690ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 691ddee5cdbSTristan Ye { 692ddee5cdbSTristan Ye struct ocfs2_info_request oir; 693ddee5cdbSTristan Ye 694ddee5cdbSTristan Ye if (o2info_from_user(oir, req)) 6952b462638SBen Hutchings return -EFAULT; 696ddee5cdbSTristan Ye 6978aa1fa36STristan Ye o2info_clear_request_filled(&oir); 698ddee5cdbSTristan Ye 699ddee5cdbSTristan Ye if (o2info_to_user(oir, req)) 7002b462638SBen Hutchings return -EFAULT; 701ddee5cdbSTristan Ye 7022b462638SBen Hutchings return 0; 703ddee5cdbSTristan Ye } 704ddee5cdbSTristan Ye 705ddee5cdbSTristan Ye /* 706ddee5cdbSTristan Ye * Validate and distinguish OCFS2_IOC_INFO requests. 707ddee5cdbSTristan Ye * 708ddee5cdbSTristan Ye * - validate the magic number. 709ddee5cdbSTristan Ye * - distinguish different requests. 710ddee5cdbSTristan Ye * - validate size of different requests. 711ddee5cdbSTristan Ye */ 712c253ed1fSFabian Frederick static int ocfs2_info_handle_request(struct inode *inode, 713ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 714ddee5cdbSTristan Ye { 715ddee5cdbSTristan Ye int status = -EFAULT; 716ddee5cdbSTristan Ye struct ocfs2_info_request oir; 717ddee5cdbSTristan Ye 718ddee5cdbSTristan Ye if (o2info_from_user(oir, req)) 719ddee5cdbSTristan Ye goto bail; 720ddee5cdbSTristan Ye 721ddee5cdbSTristan Ye status = -EINVAL; 722ddee5cdbSTristan Ye if (oir.ir_magic != OCFS2_INFO_MAGIC) 723ddee5cdbSTristan Ye goto bail; 724ddee5cdbSTristan Ye 725ddee5cdbSTristan Ye switch (oir.ir_code) { 726ddee5cdbSTristan Ye case OCFS2_INFO_BLOCKSIZE: 727ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_blocksize)) 728ddee5cdbSTristan Ye status = ocfs2_info_handle_blocksize(inode, req); 729ddee5cdbSTristan Ye break; 730ddee5cdbSTristan Ye case OCFS2_INFO_CLUSTERSIZE: 731ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_clustersize)) 732ddee5cdbSTristan Ye status = ocfs2_info_handle_clustersize(inode, req); 733ddee5cdbSTristan Ye break; 734ddee5cdbSTristan Ye case OCFS2_INFO_MAXSLOTS: 735ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_maxslots)) 736ddee5cdbSTristan Ye status = ocfs2_info_handle_maxslots(inode, req); 737ddee5cdbSTristan Ye break; 738ddee5cdbSTristan Ye case OCFS2_INFO_LABEL: 739ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_label)) 740ddee5cdbSTristan Ye status = ocfs2_info_handle_label(inode, req); 741ddee5cdbSTristan Ye break; 742ddee5cdbSTristan Ye case OCFS2_INFO_UUID: 743ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_uuid)) 744ddee5cdbSTristan Ye status = ocfs2_info_handle_uuid(inode, req); 745ddee5cdbSTristan Ye break; 746ddee5cdbSTristan Ye case OCFS2_INFO_FS_FEATURES: 747ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_fs_features)) 748ddee5cdbSTristan Ye status = ocfs2_info_handle_fs_features(inode, req); 749ddee5cdbSTristan Ye break; 750ddee5cdbSTristan Ye case OCFS2_INFO_JOURNAL_SIZE: 751ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_journal_size)) 752ddee5cdbSTristan Ye status = ocfs2_info_handle_journal_size(inode, req); 753ddee5cdbSTristan Ye break; 7543e5db17dSTristan Ye case OCFS2_INFO_FREEINODE: 7553e5db17dSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_freeinode)) 7563e5db17dSTristan Ye status = ocfs2_info_handle_freeinode(inode, req); 7573e5db17dSTristan Ye break; 758d24a10b9STristan Ye case OCFS2_INFO_FREEFRAG: 759d24a10b9STristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_freefrag)) 760d24a10b9STristan Ye status = ocfs2_info_handle_freefrag(inode, req); 761d24a10b9STristan Ye break; 762ddee5cdbSTristan Ye default: 763ddee5cdbSTristan Ye status = ocfs2_info_handle_unknown(inode, req); 764ddee5cdbSTristan Ye break; 765ddee5cdbSTristan Ye } 766ddee5cdbSTristan Ye 767ddee5cdbSTristan Ye bail: 768ddee5cdbSTristan Ye return status; 769ddee5cdbSTristan Ye } 770ddee5cdbSTristan Ye 771c253ed1fSFabian Frederick static int ocfs2_get_request_ptr(struct ocfs2_info *info, int idx, 772ddee5cdbSTristan Ye u64 *req_addr, int compat_flag) 773ddee5cdbSTristan Ye { 774ddee5cdbSTristan Ye int status = -EFAULT; 775ddee5cdbSTristan Ye u64 __user *bp = NULL; 776ddee5cdbSTristan Ye 777ddee5cdbSTristan Ye if (compat_flag) { 778ddee5cdbSTristan Ye #ifdef CONFIG_COMPAT 779ddee5cdbSTristan Ye /* 780ddee5cdbSTristan Ye * pointer bp stores the base address of a pointers array, 781ddee5cdbSTristan Ye * which collects all addresses of separate request. 782ddee5cdbSTristan Ye */ 783ddee5cdbSTristan Ye bp = (u64 __user *)(unsigned long)compat_ptr(info->oi_requests); 784ddee5cdbSTristan Ye #else 785ddee5cdbSTristan Ye BUG(); 786ddee5cdbSTristan Ye #endif 787ddee5cdbSTristan Ye } else 788ddee5cdbSTristan Ye bp = (u64 __user *)(unsigned long)(info->oi_requests); 789ddee5cdbSTristan Ye 790ddee5cdbSTristan Ye if (o2info_from_user(*req_addr, bp + idx)) 791ddee5cdbSTristan Ye goto bail; 792ddee5cdbSTristan Ye 793ddee5cdbSTristan Ye status = 0; 794ddee5cdbSTristan Ye bail: 795ddee5cdbSTristan Ye return status; 796ddee5cdbSTristan Ye } 797ddee5cdbSTristan Ye 798ddee5cdbSTristan Ye /* 799ddee5cdbSTristan Ye * OCFS2_IOC_INFO handles an array of requests passed from userspace. 800ddee5cdbSTristan Ye * 801ddee5cdbSTristan Ye * ocfs2_info_handle() recevies a large info aggregation, grab and 802ddee5cdbSTristan Ye * validate the request count from header, then break it into small 803ddee5cdbSTristan Ye * pieces, later specific handlers can handle them one by one. 804ddee5cdbSTristan Ye * 805ddee5cdbSTristan Ye * Idea here is to make each separate request small enough to ensure 806ddee5cdbSTristan Ye * a better backward&forward compatibility, since a small piece of 807ddee5cdbSTristan Ye * request will be less likely to be broken if disk layout get changed. 808ddee5cdbSTristan Ye */ 809c253ed1fSFabian Frederick static int ocfs2_info_handle(struct inode *inode, struct ocfs2_info *info, 810ddee5cdbSTristan Ye int compat_flag) 811ddee5cdbSTristan Ye { 812ddee5cdbSTristan Ye int i, status = 0; 813ddee5cdbSTristan Ye u64 req_addr; 814ddee5cdbSTristan Ye struct ocfs2_info_request __user *reqp; 815ddee5cdbSTristan Ye 816ddee5cdbSTristan Ye if ((info->oi_count > OCFS2_INFO_MAX_REQUEST) || 817ddee5cdbSTristan Ye (!info->oi_requests)) { 818ddee5cdbSTristan Ye status = -EINVAL; 819ddee5cdbSTristan Ye goto bail; 820ddee5cdbSTristan Ye } 821ddee5cdbSTristan Ye 822ddee5cdbSTristan Ye for (i = 0; i < info->oi_count; i++) { 823ddee5cdbSTristan Ye 824ddee5cdbSTristan Ye status = ocfs2_get_request_ptr(info, i, &req_addr, compat_flag); 825ddee5cdbSTristan Ye if (status) 826ddee5cdbSTristan Ye break; 827ddee5cdbSTristan Ye 828f6a56903SAl Viro reqp = (struct ocfs2_info_request __user *)(unsigned long)req_addr; 829ddee5cdbSTristan Ye if (!reqp) { 830ddee5cdbSTristan Ye status = -EINVAL; 831ddee5cdbSTristan Ye goto bail; 832ddee5cdbSTristan Ye } 833ddee5cdbSTristan Ye 834ddee5cdbSTristan Ye status = ocfs2_info_handle_request(inode, reqp); 835ddee5cdbSTristan Ye if (status) 836ddee5cdbSTristan Ye break; 837ddee5cdbSTristan Ye } 838ddee5cdbSTristan Ye 839ddee5cdbSTristan Ye bail: 840ddee5cdbSTristan Ye return status; 841ddee5cdbSTristan Ye } 842ddee5cdbSTristan Ye 843c9ec1488SAndi Kleen long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 844ca4d147eSHerbert Poetzl { 845496ad9aaSAl Viro struct inode *inode = file_inode(filp); 846ca4d147eSHerbert Poetzl unsigned int flags; 847d659072fSTao Ma int new_clusters; 848ca4d147eSHerbert Poetzl int status; 849b2580103SMark Fasheh struct ocfs2_space_resv sr; 8507909f2bfSTao Ma struct ocfs2_new_group_input input; 851bd50873dSTao Ma struct reflink_arguments args; 852f6a56903SAl Viro const char __user *old_path; 853f6a56903SAl Viro const char __user *new_path; 854bd50873dSTao Ma bool preserve; 855ddee5cdbSTristan Ye struct ocfs2_info info; 856f6a56903SAl Viro void __user *argp = (void __user *)arg; 857ca4d147eSHerbert Poetzl 858ca4d147eSHerbert Poetzl switch (cmd) { 859ca4d147eSHerbert Poetzl case OCFS2_IOC_GETFLAGS: 860ca4d147eSHerbert Poetzl status = ocfs2_get_inode_attr(inode, &flags); 861ca4d147eSHerbert Poetzl if (status < 0) 862ca4d147eSHerbert Poetzl return status; 863ca4d147eSHerbert Poetzl 864ca4d147eSHerbert Poetzl flags &= OCFS2_FL_VISIBLE; 865ca4d147eSHerbert Poetzl return put_user(flags, (int __user *) arg); 866ca4d147eSHerbert Poetzl case OCFS2_IOC_SETFLAGS: 867ca4d147eSHerbert Poetzl if (get_user(flags, (int __user *) arg)) 868ca4d147eSHerbert Poetzl return -EFAULT; 869ca4d147eSHerbert Poetzl 870a561be71SAl Viro status = mnt_want_write_file(filp); 87142a74f20SDave Hansen if (status) 87242a74f20SDave Hansen return status; 87342a74f20SDave Hansen status = ocfs2_set_inode_attr(inode, flags, 874ca4d147eSHerbert Poetzl OCFS2_FL_MODIFIABLE); 8752a79f17eSAl Viro mnt_drop_write_file(filp); 87642a74f20SDave Hansen return status; 877b2580103SMark Fasheh case OCFS2_IOC_RESVSP: 878b2580103SMark Fasheh case OCFS2_IOC_RESVSP64: 879b2580103SMark Fasheh case OCFS2_IOC_UNRESVSP: 880b2580103SMark Fasheh case OCFS2_IOC_UNRESVSP64: 881b2580103SMark Fasheh if (copy_from_user(&sr, (int __user *) arg, sizeof(sr))) 882b2580103SMark Fasheh return -EFAULT; 883b2580103SMark Fasheh 884b2580103SMark Fasheh return ocfs2_change_file_space(filp, cmd, &sr); 885d659072fSTao Ma case OCFS2_IOC_GROUP_EXTEND: 8860957f007SMark Fasheh if (!capable(CAP_SYS_RESOURCE)) 8870957f007SMark Fasheh return -EPERM; 8880957f007SMark Fasheh 889d659072fSTao Ma if (get_user(new_clusters, (int __user *)arg)) 890d659072fSTao Ma return -EFAULT; 891d659072fSTao Ma 892fef6925cSJan Kara status = mnt_want_write_file(filp); 893fef6925cSJan Kara if (status) 894fef6925cSJan Kara return status; 895fef6925cSJan Kara status = ocfs2_group_extend(inode, new_clusters); 896fef6925cSJan Kara mnt_drop_write_file(filp); 897fef6925cSJan Kara return status; 8987909f2bfSTao Ma case OCFS2_IOC_GROUP_ADD: 8997909f2bfSTao Ma case OCFS2_IOC_GROUP_ADD64: 9000957f007SMark Fasheh if (!capable(CAP_SYS_RESOURCE)) 9010957f007SMark Fasheh return -EPERM; 9020957f007SMark Fasheh 9037909f2bfSTao Ma if (copy_from_user(&input, (int __user *) arg, sizeof(input))) 9047909f2bfSTao Ma return -EFAULT; 9057909f2bfSTao Ma 906fef6925cSJan Kara status = mnt_want_write_file(filp); 907fef6925cSJan Kara if (status) 908fef6925cSJan Kara return status; 909fef6925cSJan Kara status = ocfs2_group_add(inode, &input); 910fef6925cSJan Kara mnt_drop_write_file(filp); 911fef6925cSJan Kara return status; 912bd50873dSTao Ma case OCFS2_IOC_REFLINK: 913f6a56903SAl Viro if (copy_from_user(&args, argp, sizeof(args))) 914bd50873dSTao Ma return -EFAULT; 915f6a56903SAl Viro old_path = (const char __user *)(unsigned long)args.old_path; 916f6a56903SAl Viro new_path = (const char __user *)(unsigned long)args.new_path; 917bd50873dSTao Ma preserve = (args.preserve != 0); 918bd50873dSTao Ma 919bd50873dSTao Ma return ocfs2_reflink_ioctl(inode, old_path, new_path, preserve); 920ddee5cdbSTristan Ye case OCFS2_IOC_INFO: 921f6a56903SAl Viro if (copy_from_user(&info, argp, sizeof(struct ocfs2_info))) 922ddee5cdbSTristan Ye return -EFAULT; 923ddee5cdbSTristan Ye 924ddee5cdbSTristan Ye return ocfs2_info_handle(inode, &info, 0); 92555e67872STao Ma case FITRIM: 92655e67872STao Ma { 92755e67872STao Ma struct super_block *sb = inode->i_sb; 92819e8ac27SJie Liu struct request_queue *q = bdev_get_queue(sb->s_bdev); 92955e67872STao Ma struct fstrim_range range; 93055e67872STao Ma int ret = 0; 93155e67872STao Ma 93255e67872STao Ma if (!capable(CAP_SYS_ADMIN)) 93355e67872STao Ma return -EPERM; 93455e67872STao Ma 93519e8ac27SJie Liu if (!blk_queue_discard(q)) 93619e8ac27SJie Liu return -EOPNOTSUPP; 93719e8ac27SJie Liu 938f6a56903SAl Viro if (copy_from_user(&range, argp, sizeof(range))) 93955e67872STao Ma return -EFAULT; 94055e67872STao Ma 9411ba2212bSJie Liu range.minlen = max_t(u64, q->limits.discard_granularity, 9421ba2212bSJie Liu range.minlen); 94355e67872STao Ma ret = ocfs2_trim_fs(sb, &range); 94455e67872STao Ma if (ret < 0) 94555e67872STao Ma return ret; 94655e67872STao Ma 947f6a56903SAl Viro if (copy_to_user(argp, &range, sizeof(range))) 94855e67872STao Ma return -EFAULT; 94955e67872STao Ma 95055e67872STao Ma return 0; 95155e67872STao Ma } 95253069d4eSTristan Ye case OCFS2_IOC_MOVE_EXT: 953f6a56903SAl Viro return ocfs2_ioctl_move_extents(filp, argp); 954ca4d147eSHerbert Poetzl default: 955ca4d147eSHerbert Poetzl return -ENOTTY; 956ca4d147eSHerbert Poetzl } 957ca4d147eSHerbert Poetzl } 958ca4d147eSHerbert Poetzl 959586d232bSMark Fasheh #ifdef CONFIG_COMPAT 960586d232bSMark Fasheh long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) 961586d232bSMark Fasheh { 96234e6c59aSTao Ma bool preserve; 96334e6c59aSTao Ma struct reflink_arguments args; 964496ad9aaSAl Viro struct inode *inode = file_inode(file); 965ddee5cdbSTristan Ye struct ocfs2_info info; 966f6a56903SAl Viro void __user *argp = (void __user *)arg; 96734e6c59aSTao Ma 968586d232bSMark Fasheh switch (cmd) { 969586d232bSMark Fasheh case OCFS2_IOC32_GETFLAGS: 970586d232bSMark Fasheh cmd = OCFS2_IOC_GETFLAGS; 971586d232bSMark Fasheh break; 972586d232bSMark Fasheh case OCFS2_IOC32_SETFLAGS: 973586d232bSMark Fasheh cmd = OCFS2_IOC_SETFLAGS; 974586d232bSMark Fasheh break; 975b2580103SMark Fasheh case OCFS2_IOC_RESVSP: 976b2580103SMark Fasheh case OCFS2_IOC_RESVSP64: 977b2580103SMark Fasheh case OCFS2_IOC_UNRESVSP: 978b2580103SMark Fasheh case OCFS2_IOC_UNRESVSP64: 979d659072fSTao Ma case OCFS2_IOC_GROUP_EXTEND: 9807909f2bfSTao Ma case OCFS2_IOC_GROUP_ADD: 9817909f2bfSTao Ma case OCFS2_IOC_GROUP_ADD64: 982b2580103SMark Fasheh break; 98334e6c59aSTao Ma case OCFS2_IOC_REFLINK: 984f6a56903SAl Viro if (copy_from_user(&args, argp, sizeof(args))) 98534e6c59aSTao Ma return -EFAULT; 98634e6c59aSTao Ma preserve = (args.preserve != 0); 98734e6c59aSTao Ma 98834e6c59aSTao Ma return ocfs2_reflink_ioctl(inode, compat_ptr(args.old_path), 98934e6c59aSTao Ma compat_ptr(args.new_path), preserve); 990ddee5cdbSTristan Ye case OCFS2_IOC_INFO: 991f6a56903SAl Viro if (copy_from_user(&info, argp, sizeof(struct ocfs2_info))) 992ddee5cdbSTristan Ye return -EFAULT; 993ddee5cdbSTristan Ye 994ddee5cdbSTristan Ye return ocfs2_info_handle(inode, &info, 1); 99553069d4eSTristan Ye case OCFS2_IOC_MOVE_EXT: 99653069d4eSTristan Ye break; 997586d232bSMark Fasheh default: 998586d232bSMark Fasheh return -ENOIOCTLCMD; 999586d232bSMark Fasheh } 1000586d232bSMark Fasheh 1001c9ec1488SAndi Kleen return ocfs2_ioctl(file, cmd, arg); 1002586d232bSMark Fasheh } 1003586d232bSMark Fasheh #endif 1004