1b2441318SGreg 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 1095aca2842SDarrick J. Wong status = vfs_ioc_setflags_prepare(inode, oldflags, flags); 1105aca2842SDarrick J. Wong if (status) 111b3e0767aSJeff Liu goto bail_unlock; 112b3e0767aSJeff Liu 113b3e0767aSJeff Liu handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); 114b3e0767aSJeff Liu if (IS_ERR(handle)) { 115b3e0767aSJeff Liu status = PTR_ERR(handle); 116b3e0767aSJeff Liu mlog_errno(status); 117b3e0767aSJeff Liu goto bail_unlock; 118ca4d147eSHerbert Poetzl } 119ca4d147eSHerbert Poetzl 120ca4d147eSHerbert Poetzl ocfs2_inode->ip_attr = flags; 121ca4d147eSHerbert Poetzl ocfs2_set_inode_flags(inode); 122ca4d147eSHerbert Poetzl 123ca4d147eSHerbert Poetzl status = ocfs2_mark_inode_dirty(handle, inode, bh); 124ca4d147eSHerbert Poetzl if (status < 0) 125ca4d147eSHerbert Poetzl mlog_errno(status); 126ca4d147eSHerbert Poetzl 12702dc1af4SMark Fasheh ocfs2_commit_trans(osb, handle); 128b3e0767aSJeff Liu 129ca4d147eSHerbert Poetzl bail_unlock: 130e63aecb6SMark Fasheh ocfs2_inode_unlock(inode, 1); 131ca4d147eSHerbert Poetzl bail: 1325955102cSAl Viro inode_unlock(inode); 133ca4d147eSHerbert Poetzl 134ca4d147eSHerbert Poetzl brelse(bh); 135ca4d147eSHerbert Poetzl 136ca4d147eSHerbert Poetzl return status; 137ca4d147eSHerbert Poetzl } 138ca4d147eSHerbert Poetzl 139c253ed1fSFabian Frederick static int ocfs2_info_handle_blocksize(struct inode *inode, 140ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 141ddee5cdbSTristan Ye { 142ddee5cdbSTristan Ye struct ocfs2_info_blocksize oib; 143ddee5cdbSTristan Ye 144ddee5cdbSTristan Ye if (o2info_from_user(oib, req)) 1452b462638SBen Hutchings return -EFAULT; 146ddee5cdbSTristan Ye 147ddee5cdbSTristan Ye oib.ib_blocksize = inode->i_sb->s_blocksize; 1481936a267STristan Ye 1498aa1fa36STristan Ye o2info_set_request_filled(&oib.ib_req); 150ddee5cdbSTristan Ye 151ddee5cdbSTristan Ye if (o2info_to_user(oib, req)) 1522b462638SBen Hutchings return -EFAULT; 153ddee5cdbSTristan Ye 1542b462638SBen Hutchings return 0; 155ddee5cdbSTristan Ye } 156ddee5cdbSTristan Ye 157c253ed1fSFabian Frederick static int ocfs2_info_handle_clustersize(struct inode *inode, 158ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 159ddee5cdbSTristan Ye { 160ddee5cdbSTristan Ye struct ocfs2_info_clustersize oic; 161ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 162ddee5cdbSTristan Ye 163ddee5cdbSTristan Ye if (o2info_from_user(oic, req)) 1642b462638SBen Hutchings return -EFAULT; 165ddee5cdbSTristan Ye 166ddee5cdbSTristan Ye oic.ic_clustersize = osb->s_clustersize; 1671936a267STristan Ye 1688aa1fa36STristan Ye o2info_set_request_filled(&oic.ic_req); 169ddee5cdbSTristan Ye 170ddee5cdbSTristan Ye if (o2info_to_user(oic, req)) 1712b462638SBen Hutchings return -EFAULT; 172ddee5cdbSTristan Ye 1732b462638SBen Hutchings return 0; 174ddee5cdbSTristan Ye } 175ddee5cdbSTristan Ye 176c253ed1fSFabian Frederick static int ocfs2_info_handle_maxslots(struct inode *inode, 177ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 178ddee5cdbSTristan Ye { 179ddee5cdbSTristan Ye struct ocfs2_info_maxslots oim; 180ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 181ddee5cdbSTristan Ye 182ddee5cdbSTristan Ye if (o2info_from_user(oim, req)) 1832b462638SBen Hutchings return -EFAULT; 184ddee5cdbSTristan Ye 185ddee5cdbSTristan Ye oim.im_max_slots = osb->max_slots; 1861936a267STristan Ye 1878aa1fa36STristan Ye o2info_set_request_filled(&oim.im_req); 188ddee5cdbSTristan Ye 189ddee5cdbSTristan Ye if (o2info_to_user(oim, req)) 1902b462638SBen Hutchings return -EFAULT; 191ddee5cdbSTristan Ye 1922b462638SBen Hutchings return 0; 193ddee5cdbSTristan Ye } 194ddee5cdbSTristan Ye 195c253ed1fSFabian Frederick static int ocfs2_info_handle_label(struct inode *inode, 196ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 197ddee5cdbSTristan Ye { 198ddee5cdbSTristan Ye struct ocfs2_info_label oil; 199ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 200ddee5cdbSTristan Ye 201ddee5cdbSTristan Ye if (o2info_from_user(oil, req)) 2022b462638SBen Hutchings return -EFAULT; 203ddee5cdbSTristan Ye 204ddee5cdbSTristan Ye memcpy(oil.il_label, osb->vol_label, OCFS2_MAX_VOL_LABEL_LEN); 2051936a267STristan Ye 2068aa1fa36STristan Ye o2info_set_request_filled(&oil.il_req); 207ddee5cdbSTristan Ye 208ddee5cdbSTristan Ye if (o2info_to_user(oil, req)) 2092b462638SBen Hutchings return -EFAULT; 210ddee5cdbSTristan Ye 2112b462638SBen Hutchings return 0; 212ddee5cdbSTristan Ye } 213ddee5cdbSTristan Ye 214c253ed1fSFabian Frederick static int ocfs2_info_handle_uuid(struct inode *inode, 215ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 216ddee5cdbSTristan Ye { 217ddee5cdbSTristan Ye struct ocfs2_info_uuid oiu; 218ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 219ddee5cdbSTristan Ye 220ddee5cdbSTristan Ye if (o2info_from_user(oiu, req)) 2212b462638SBen Hutchings return -EFAULT; 222ddee5cdbSTristan Ye 223ddee5cdbSTristan Ye memcpy(oiu.iu_uuid_str, osb->uuid_str, OCFS2_TEXT_UUID_LEN + 1); 2241936a267STristan Ye 2258aa1fa36STristan Ye o2info_set_request_filled(&oiu.iu_req); 226ddee5cdbSTristan Ye 227ddee5cdbSTristan Ye if (o2info_to_user(oiu, req)) 2282b462638SBen Hutchings return -EFAULT; 229ddee5cdbSTristan Ye 2302b462638SBen Hutchings return 0; 231ddee5cdbSTristan Ye } 232ddee5cdbSTristan Ye 233c253ed1fSFabian Frederick static int ocfs2_info_handle_fs_features(struct inode *inode, 234ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 235ddee5cdbSTristan Ye { 236ddee5cdbSTristan Ye struct ocfs2_info_fs_features oif; 237ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 238ddee5cdbSTristan Ye 239ddee5cdbSTristan Ye if (o2info_from_user(oif, req)) 2402b462638SBen Hutchings return -EFAULT; 241ddee5cdbSTristan Ye 242ddee5cdbSTristan Ye oif.if_compat_features = osb->s_feature_compat; 243ddee5cdbSTristan Ye oif.if_incompat_features = osb->s_feature_incompat; 244ddee5cdbSTristan Ye oif.if_ro_compat_features = osb->s_feature_ro_compat; 2451936a267STristan Ye 2468aa1fa36STristan Ye o2info_set_request_filled(&oif.if_req); 247ddee5cdbSTristan Ye 248ddee5cdbSTristan Ye if (o2info_to_user(oif, req)) 2492b462638SBen Hutchings return -EFAULT; 250ddee5cdbSTristan Ye 2512b462638SBen Hutchings return 0; 252ddee5cdbSTristan Ye } 253ddee5cdbSTristan Ye 254c253ed1fSFabian Frederick static int ocfs2_info_handle_journal_size(struct inode *inode, 255ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 256ddee5cdbSTristan Ye { 257ddee5cdbSTristan Ye struct ocfs2_info_journal_size oij; 258ddee5cdbSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 259ddee5cdbSTristan Ye 260ddee5cdbSTristan Ye if (o2info_from_user(oij, req)) 2612b462638SBen Hutchings return -EFAULT; 262ddee5cdbSTristan Ye 263f17c20ddSJunxiao Bi oij.ij_journal_size = i_size_read(osb->journal->j_inode); 264ddee5cdbSTristan Ye 2658aa1fa36STristan Ye o2info_set_request_filled(&oij.ij_req); 266ddee5cdbSTristan Ye 267ddee5cdbSTristan Ye if (o2info_to_user(oij, req)) 2682b462638SBen Hutchings return -EFAULT; 269ddee5cdbSTristan Ye 2702b462638SBen Hutchings return 0; 271ddee5cdbSTristan Ye } 272ddee5cdbSTristan Ye 273c253ed1fSFabian Frederick static int ocfs2_info_scan_inode_alloc(struct ocfs2_super *osb, 2743e5db17dSTristan Ye struct inode *inode_alloc, u64 blkno, 275c253ed1fSFabian Frederick struct ocfs2_info_freeinode *fi, 276c253ed1fSFabian Frederick u32 slot) 2773e5db17dSTristan Ye { 2783e5db17dSTristan Ye int status = 0, unlock = 0; 2793e5db17dSTristan Ye 2803e5db17dSTristan Ye struct buffer_head *bh = NULL; 2813e5db17dSTristan Ye struct ocfs2_dinode *dinode_alloc = NULL; 2823e5db17dSTristan Ye 2833e5db17dSTristan Ye if (inode_alloc) 2845955102cSAl Viro inode_lock(inode_alloc); 2853e5db17dSTristan Ye 2863e5db17dSTristan Ye if (o2info_coherent(&fi->ifi_req)) { 2873e5db17dSTristan Ye status = ocfs2_inode_lock(inode_alloc, &bh, 0); 2883e5db17dSTristan Ye if (status < 0) { 2893e5db17dSTristan Ye mlog_errno(status); 2903e5db17dSTristan Ye goto bail; 2913e5db17dSTristan Ye } 2923e5db17dSTristan Ye unlock = 1; 2933e5db17dSTristan Ye } else { 2943e5db17dSTristan Ye status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); 2953e5db17dSTristan Ye if (status < 0) { 2963e5db17dSTristan Ye mlog_errno(status); 2973e5db17dSTristan Ye goto bail; 2983e5db17dSTristan Ye } 2993e5db17dSTristan Ye } 3003e5db17dSTristan Ye 3013e5db17dSTristan Ye dinode_alloc = (struct ocfs2_dinode *)bh->b_data; 3023e5db17dSTristan Ye 3033e5db17dSTristan Ye fi->ifi_stat[slot].lfi_total = 3043e5db17dSTristan Ye le32_to_cpu(dinode_alloc->id1.bitmap1.i_total); 3053e5db17dSTristan Ye fi->ifi_stat[slot].lfi_free = 3063e5db17dSTristan Ye le32_to_cpu(dinode_alloc->id1.bitmap1.i_total) - 3073e5db17dSTristan Ye le32_to_cpu(dinode_alloc->id1.bitmap1.i_used); 3083e5db17dSTristan Ye 3093e5db17dSTristan Ye bail: 3103e5db17dSTristan Ye if (unlock) 3113e5db17dSTristan Ye ocfs2_inode_unlock(inode_alloc, 0); 3123e5db17dSTristan Ye 3133e5db17dSTristan Ye if (inode_alloc) 3145955102cSAl Viro inode_unlock(inode_alloc); 3153e5db17dSTristan Ye 3163e5db17dSTristan Ye brelse(bh); 3173e5db17dSTristan Ye 3183e5db17dSTristan Ye return status; 3193e5db17dSTristan Ye } 3203e5db17dSTristan Ye 321c253ed1fSFabian Frederick static int ocfs2_info_handle_freeinode(struct inode *inode, 3223e5db17dSTristan Ye struct ocfs2_info_request __user *req) 3233e5db17dSTristan Ye { 3243e5db17dSTristan Ye u32 i; 3253e5db17dSTristan Ye u64 blkno = -1; 3263e5db17dSTristan Ye char namebuf[40]; 3272b462638SBen Hutchings int status, type = INODE_ALLOC_SYSTEM_INODE; 3283e5db17dSTristan Ye struct ocfs2_info_freeinode *oifi = NULL; 3293e5db17dSTristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 3303e5db17dSTristan Ye struct inode *inode_alloc = NULL; 3313e5db17dSTristan Ye 3323e5db17dSTristan Ye oifi = kzalloc(sizeof(struct ocfs2_info_freeinode), GFP_KERNEL); 3333e5db17dSTristan Ye if (!oifi) { 3343e5db17dSTristan Ye status = -ENOMEM; 3353e5db17dSTristan Ye mlog_errno(status); 33687f0d5c8SDan Carpenter goto out_err; 3373e5db17dSTristan Ye } 3383e5db17dSTristan Ye 3392b462638SBen Hutchings if (o2info_from_user(*oifi, req)) { 3402b462638SBen Hutchings status = -EFAULT; 3412b462638SBen Hutchings goto out_free; 3422b462638SBen Hutchings } 3433e5db17dSTristan Ye 3443e5db17dSTristan Ye oifi->ifi_slotnum = osb->max_slots; 3453e5db17dSTristan Ye 3463e5db17dSTristan Ye for (i = 0; i < oifi->ifi_slotnum; i++) { 3473e5db17dSTristan Ye if (o2info_coherent(&oifi->ifi_req)) { 3483e5db17dSTristan Ye inode_alloc = ocfs2_get_system_file_inode(osb, type, i); 3493e5db17dSTristan Ye if (!inode_alloc) { 3503e5db17dSTristan Ye mlog(ML_ERROR, "unable to get alloc inode in " 3513e5db17dSTristan Ye "slot %u\n", i); 3523e5db17dSTristan Ye status = -EIO; 3533e5db17dSTristan Ye goto bail; 3543e5db17dSTristan Ye } 3553e5db17dSTristan Ye } else { 3563e5db17dSTristan Ye ocfs2_sprintf_system_inode_name(namebuf, 3573e5db17dSTristan Ye sizeof(namebuf), 3583e5db17dSTristan Ye type, i); 3593e5db17dSTristan Ye status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, 3603e5db17dSTristan Ye namebuf, 3613e5db17dSTristan Ye strlen(namebuf), 3623e5db17dSTristan Ye &blkno); 3633e5db17dSTristan Ye if (status < 0) { 3643e5db17dSTristan Ye status = -ENOENT; 3653e5db17dSTristan Ye goto bail; 3663e5db17dSTristan Ye } 3673e5db17dSTristan Ye } 3683e5db17dSTristan Ye 3693e5db17dSTristan Ye status = ocfs2_info_scan_inode_alloc(osb, inode_alloc, blkno, oifi, i); 3703e5db17dSTristan Ye 3713e5db17dSTristan Ye iput(inode_alloc); 3723e5db17dSTristan Ye inode_alloc = NULL; 3737dc3e839Sjiangyiwen 3747dc3e839Sjiangyiwen if (status < 0) 3757dc3e839Sjiangyiwen goto bail; 3763e5db17dSTristan Ye } 3773e5db17dSTristan Ye 3783e5db17dSTristan Ye o2info_set_request_filled(&oifi->ifi_req); 3793e5db17dSTristan Ye 3802b462638SBen Hutchings if (o2info_to_user(*oifi, req)) { 3812b462638SBen Hutchings status = -EFAULT; 3822b462638SBen Hutchings goto out_free; 3832b462638SBen Hutchings } 3843e5db17dSTristan Ye 3853e5db17dSTristan Ye status = 0; 3863e5db17dSTristan Ye bail: 3873e5db17dSTristan Ye if (status) 3883e5db17dSTristan Ye o2info_set_request_error(&oifi->ifi_req, req); 3892b462638SBen Hutchings out_free: 3903e5db17dSTristan Ye kfree(oifi); 39187f0d5c8SDan Carpenter out_err: 3923e5db17dSTristan Ye return status; 3933e5db17dSTristan Ye } 3943e5db17dSTristan Ye 395d24a10b9STristan Ye static void o2ffg_update_histogram(struct ocfs2_info_free_chunk_list *hist, 396d24a10b9STristan Ye unsigned int chunksize) 397d24a10b9STristan Ye { 398731a40faSZhen Lei u32 index; 399d24a10b9STristan Ye 400d24a10b9STristan Ye index = __ilog2_u32(chunksize); 401d24a10b9STristan Ye if (index >= OCFS2_INFO_MAX_HIST) 402d24a10b9STristan Ye index = OCFS2_INFO_MAX_HIST - 1; 403d24a10b9STristan Ye 404d24a10b9STristan Ye hist->fc_chunks[index]++; 405d24a10b9STristan Ye hist->fc_clusters[index] += chunksize; 406d24a10b9STristan Ye } 407d24a10b9STristan Ye 408d24a10b9STristan Ye static void o2ffg_update_stats(struct ocfs2_info_freefrag_stats *stats, 409d24a10b9STristan Ye unsigned int chunksize) 410d24a10b9STristan Ye { 411d24a10b9STristan Ye if (chunksize > stats->ffs_max) 412d24a10b9STristan Ye stats->ffs_max = chunksize; 413d24a10b9STristan Ye 414d24a10b9STristan Ye if (chunksize < stats->ffs_min) 415d24a10b9STristan Ye stats->ffs_min = chunksize; 416d24a10b9STristan Ye 417d24a10b9STristan Ye stats->ffs_avg += chunksize; 418d24a10b9STristan Ye stats->ffs_free_chunks_real++; 419d24a10b9STristan Ye } 420d24a10b9STristan Ye 421c253ed1fSFabian Frederick static void ocfs2_info_update_ffg(struct ocfs2_info_freefrag *ffg, 422d24a10b9STristan Ye unsigned int chunksize) 423d24a10b9STristan Ye { 424d24a10b9STristan Ye o2ffg_update_histogram(&(ffg->iff_ffs.ffs_fc_hist), chunksize); 425d24a10b9STristan Ye o2ffg_update_stats(&(ffg->iff_ffs), chunksize); 426d24a10b9STristan Ye } 427d24a10b9STristan Ye 428c253ed1fSFabian Frederick static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, 429d24a10b9STristan Ye struct inode *gb_inode, 430d24a10b9STristan Ye struct ocfs2_dinode *gb_dinode, 431d24a10b9STristan Ye struct ocfs2_chain_rec *rec, 432d24a10b9STristan Ye struct ocfs2_info_freefrag *ffg, 433d24a10b9STristan Ye u32 chunks_in_group) 434d24a10b9STristan Ye { 435d24a10b9STristan Ye int status = 0, used; 436d24a10b9STristan Ye u64 blkno; 437d24a10b9STristan Ye 438d24a10b9STristan Ye struct buffer_head *bh = NULL; 439d24a10b9STristan Ye struct ocfs2_group_desc *bg = NULL; 440d24a10b9STristan Ye 441d24a10b9STristan Ye unsigned int max_bits, num_clusters; 442d24a10b9STristan Ye unsigned int offset = 0, cluster, chunk; 443d24a10b9STristan Ye unsigned int chunk_free, last_chunksize = 0; 444d24a10b9STristan Ye 445d24a10b9STristan Ye if (!le32_to_cpu(rec->c_free)) 446d24a10b9STristan Ye goto bail; 447d24a10b9STristan Ye 448d24a10b9STristan Ye do { 449d24a10b9STristan Ye if (!bg) 450d24a10b9STristan Ye blkno = le64_to_cpu(rec->c_blkno); 451d24a10b9STristan Ye else 452d24a10b9STristan Ye blkno = le64_to_cpu(bg->bg_next_group); 453d24a10b9STristan Ye 454d24a10b9STristan Ye if (bh) { 455d24a10b9STristan Ye brelse(bh); 456d24a10b9STristan Ye bh = NULL; 457d24a10b9STristan Ye } 458d24a10b9STristan Ye 459d24a10b9STristan Ye if (o2info_coherent(&ffg->iff_req)) 460d24a10b9STristan Ye status = ocfs2_read_group_descriptor(gb_inode, 461d24a10b9STristan Ye gb_dinode, 462d24a10b9STristan Ye blkno, &bh); 463d24a10b9STristan Ye else 464d24a10b9STristan Ye status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); 465d24a10b9STristan Ye 466d24a10b9STristan Ye if (status < 0) { 467d24a10b9STristan Ye mlog(ML_ERROR, "Can't read the group descriptor # " 468d24a10b9STristan Ye "%llu from device.", (unsigned long long)blkno); 469d24a10b9STristan Ye status = -EIO; 470d24a10b9STristan Ye goto bail; 471d24a10b9STristan Ye } 472d24a10b9STristan Ye 473d24a10b9STristan Ye bg = (struct ocfs2_group_desc *)bh->b_data; 474d24a10b9STristan Ye 475d24a10b9STristan Ye if (!le16_to_cpu(bg->bg_free_bits_count)) 476d24a10b9STristan Ye continue; 477d24a10b9STristan Ye 478d24a10b9STristan Ye max_bits = le16_to_cpu(bg->bg_bits); 479d24a10b9STristan Ye offset = 0; 480d24a10b9STristan Ye 481d24a10b9STristan Ye for (chunk = 0; chunk < chunks_in_group; chunk++) { 482d24a10b9STristan Ye /* 483d24a10b9STristan Ye * last chunk may be not an entire one. 484d24a10b9STristan Ye */ 485d24a10b9STristan Ye if ((offset + ffg->iff_chunksize) > max_bits) 486d24a10b9STristan Ye num_clusters = max_bits - offset; 487d24a10b9STristan Ye else 488d24a10b9STristan Ye num_clusters = ffg->iff_chunksize; 489d24a10b9STristan Ye 490d24a10b9STristan Ye chunk_free = 0; 491d24a10b9STristan Ye for (cluster = 0; cluster < num_clusters; cluster++) { 492d24a10b9STristan Ye used = ocfs2_test_bit(offset, 493d24a10b9STristan Ye (unsigned long *)bg->bg_bitmap); 494d24a10b9STristan Ye /* 495d24a10b9STristan Ye * - chunk_free counts free clusters in #N chunk. 496d24a10b9STristan Ye * - last_chunksize records the size(in) clusters 497d24a10b9STristan Ye * for the last real free chunk being counted. 498d24a10b9STristan Ye */ 499d24a10b9STristan Ye if (!used) { 500d24a10b9STristan Ye last_chunksize++; 501d24a10b9STristan Ye chunk_free++; 502d24a10b9STristan Ye } 503d24a10b9STristan Ye 504d24a10b9STristan Ye if (used && last_chunksize) { 505d24a10b9STristan Ye ocfs2_info_update_ffg(ffg, 506d24a10b9STristan Ye last_chunksize); 507d24a10b9STristan Ye last_chunksize = 0; 508d24a10b9STristan Ye } 509d24a10b9STristan Ye 510d24a10b9STristan Ye offset++; 511d24a10b9STristan Ye } 512d24a10b9STristan Ye 513d24a10b9STristan Ye if (chunk_free == ffg->iff_chunksize) 514d24a10b9STristan Ye ffg->iff_ffs.ffs_free_chunks++; 515d24a10b9STristan Ye } 516d24a10b9STristan Ye 517d24a10b9STristan Ye /* 518d24a10b9STristan Ye * need to update the info for last free chunk. 519d24a10b9STristan Ye */ 520d24a10b9STristan Ye if (last_chunksize) 521d24a10b9STristan Ye ocfs2_info_update_ffg(ffg, last_chunksize); 522d24a10b9STristan Ye 523d24a10b9STristan Ye } while (le64_to_cpu(bg->bg_next_group)); 524d24a10b9STristan Ye 525d24a10b9STristan Ye bail: 526d24a10b9STristan Ye brelse(bh); 527d24a10b9STristan Ye 528d24a10b9STristan Ye return status; 529d24a10b9STristan Ye } 530d24a10b9STristan Ye 531c253ed1fSFabian Frederick static int ocfs2_info_freefrag_scan_bitmap(struct ocfs2_super *osb, 532d24a10b9STristan Ye struct inode *gb_inode, u64 blkno, 533d24a10b9STristan Ye struct ocfs2_info_freefrag *ffg) 534d24a10b9STristan Ye { 535d24a10b9STristan Ye u32 chunks_in_group; 536d24a10b9STristan Ye int status = 0, unlock = 0, i; 537d24a10b9STristan Ye 538d24a10b9STristan Ye struct buffer_head *bh = NULL; 539d24a10b9STristan Ye struct ocfs2_chain_list *cl = NULL; 540d24a10b9STristan Ye struct ocfs2_chain_rec *rec = NULL; 541d24a10b9STristan Ye struct ocfs2_dinode *gb_dinode = NULL; 542d24a10b9STristan Ye 543d24a10b9STristan Ye if (gb_inode) 5445955102cSAl Viro inode_lock(gb_inode); 545d24a10b9STristan Ye 546d24a10b9STristan Ye if (o2info_coherent(&ffg->iff_req)) { 547d24a10b9STristan Ye status = ocfs2_inode_lock(gb_inode, &bh, 0); 548d24a10b9STristan Ye if (status < 0) { 549d24a10b9STristan Ye mlog_errno(status); 550d24a10b9STristan Ye goto bail; 551d24a10b9STristan Ye } 552d24a10b9STristan Ye unlock = 1; 553d24a10b9STristan Ye } else { 554d24a10b9STristan Ye status = ocfs2_read_blocks_sync(osb, blkno, 1, &bh); 555d24a10b9STristan Ye if (status < 0) { 556d24a10b9STristan Ye mlog_errno(status); 557d24a10b9STristan Ye goto bail; 558d24a10b9STristan Ye } 559d24a10b9STristan Ye } 560d24a10b9STristan Ye 561d24a10b9STristan Ye gb_dinode = (struct ocfs2_dinode *)bh->b_data; 562d24a10b9STristan Ye cl = &(gb_dinode->id2.i_chain); 563d24a10b9STristan Ye 564d24a10b9STristan Ye /* 565d24a10b9STristan Ye * Chunksize(in) clusters from userspace should be 566d24a10b9STristan Ye * less than clusters in a group. 567d24a10b9STristan Ye */ 568d24a10b9STristan Ye if (ffg->iff_chunksize > le16_to_cpu(cl->cl_cpg)) { 569d24a10b9STristan Ye status = -EINVAL; 570d24a10b9STristan Ye goto bail; 571d24a10b9STristan Ye } 572d24a10b9STristan Ye 573d24a10b9STristan Ye memset(&ffg->iff_ffs, 0, sizeof(struct ocfs2_info_freefrag_stats)); 574d24a10b9STristan Ye 575d24a10b9STristan Ye ffg->iff_ffs.ffs_min = ~0U; 576d24a10b9STristan Ye ffg->iff_ffs.ffs_clusters = 577d24a10b9STristan Ye le32_to_cpu(gb_dinode->id1.bitmap1.i_total); 578d24a10b9STristan Ye ffg->iff_ffs.ffs_free_clusters = ffg->iff_ffs.ffs_clusters - 579d24a10b9STristan Ye le32_to_cpu(gb_dinode->id1.bitmap1.i_used); 580d24a10b9STristan Ye 581d24a10b9STristan Ye chunks_in_group = le16_to_cpu(cl->cl_cpg) / ffg->iff_chunksize + 1; 582d24a10b9STristan Ye 583d24a10b9STristan Ye for (i = 0; i < le16_to_cpu(cl->cl_next_free_rec); i++) { 584d24a10b9STristan Ye rec = &(cl->cl_recs[i]); 585d24a10b9STristan Ye status = ocfs2_info_freefrag_scan_chain(osb, gb_inode, 586d24a10b9STristan Ye gb_dinode, 587d24a10b9STristan Ye rec, ffg, 588d24a10b9STristan Ye chunks_in_group); 589d24a10b9STristan Ye if (status) 590d24a10b9STristan Ye goto bail; 591d24a10b9STristan Ye } 592d24a10b9STristan Ye 593d24a10b9STristan Ye if (ffg->iff_ffs.ffs_free_chunks_real) 594d24a10b9STristan Ye ffg->iff_ffs.ffs_avg = (ffg->iff_ffs.ffs_avg / 595d24a10b9STristan Ye ffg->iff_ffs.ffs_free_chunks_real); 596d24a10b9STristan Ye bail: 597d24a10b9STristan Ye if (unlock) 598d24a10b9STristan Ye ocfs2_inode_unlock(gb_inode, 0); 599d24a10b9STristan Ye 600d24a10b9STristan Ye if (gb_inode) 6015955102cSAl Viro inode_unlock(gb_inode); 602d24a10b9STristan Ye 603d24a10b9STristan Ye iput(gb_inode); 604d24a10b9STristan Ye brelse(bh); 605d24a10b9STristan Ye 606d24a10b9STristan Ye return status; 607d24a10b9STristan Ye } 608d24a10b9STristan Ye 609c253ed1fSFabian Frederick static int ocfs2_info_handle_freefrag(struct inode *inode, 610d24a10b9STristan Ye struct ocfs2_info_request __user *req) 611d24a10b9STristan Ye { 612d24a10b9STristan Ye u64 blkno = -1; 613d24a10b9STristan Ye char namebuf[40]; 6142b462638SBen Hutchings int status, type = GLOBAL_BITMAP_SYSTEM_INODE; 615d24a10b9STristan Ye 616d24a10b9STristan Ye struct ocfs2_info_freefrag *oiff; 617d24a10b9STristan Ye struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 618d24a10b9STristan Ye struct inode *gb_inode = NULL; 619d24a10b9STristan Ye 620d24a10b9STristan Ye oiff = kzalloc(sizeof(struct ocfs2_info_freefrag), GFP_KERNEL); 621d24a10b9STristan Ye if (!oiff) { 622d24a10b9STristan Ye status = -ENOMEM; 623d24a10b9STristan Ye mlog_errno(status); 62487f0d5c8SDan Carpenter goto out_err; 625d24a10b9STristan Ye } 626d24a10b9STristan Ye 6272b462638SBen Hutchings if (o2info_from_user(*oiff, req)) { 6282b462638SBen Hutchings status = -EFAULT; 6292b462638SBen Hutchings goto out_free; 6302b462638SBen Hutchings } 631d24a10b9STristan Ye /* 632d24a10b9STristan Ye * chunksize from userspace should be power of 2. 633d24a10b9STristan Ye */ 634d24a10b9STristan Ye if ((oiff->iff_chunksize & (oiff->iff_chunksize - 1)) || 635d24a10b9STristan Ye (!oiff->iff_chunksize)) { 636d24a10b9STristan Ye status = -EINVAL; 637d24a10b9STristan Ye goto bail; 638d24a10b9STristan Ye } 639d24a10b9STristan Ye 640d24a10b9STristan Ye if (o2info_coherent(&oiff->iff_req)) { 641d24a10b9STristan Ye gb_inode = ocfs2_get_system_file_inode(osb, type, 642d24a10b9STristan Ye OCFS2_INVALID_SLOT); 643d24a10b9STristan Ye if (!gb_inode) { 644d24a10b9STristan Ye mlog(ML_ERROR, "unable to get global_bitmap inode\n"); 645d24a10b9STristan Ye status = -EIO; 646d24a10b9STristan Ye goto bail; 647d24a10b9STristan Ye } 648d24a10b9STristan Ye } else { 649d24a10b9STristan Ye ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type, 650d24a10b9STristan Ye OCFS2_INVALID_SLOT); 651d24a10b9STristan Ye status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, 652d24a10b9STristan Ye namebuf, 653d24a10b9STristan Ye strlen(namebuf), 654d24a10b9STristan Ye &blkno); 655d24a10b9STristan Ye if (status < 0) { 656d24a10b9STristan Ye status = -ENOENT; 657d24a10b9STristan Ye goto bail; 658d24a10b9STristan Ye } 659d24a10b9STristan Ye } 660d24a10b9STristan Ye 661d24a10b9STristan Ye status = ocfs2_info_freefrag_scan_bitmap(osb, gb_inode, blkno, oiff); 662d24a10b9STristan Ye if (status < 0) 663d24a10b9STristan Ye goto bail; 664d24a10b9STristan Ye 665d24a10b9STristan Ye o2info_set_request_filled(&oiff->iff_req); 666d24a10b9STristan Ye 6677ebab453SWei Yongjun if (o2info_to_user(*oiff, req)) { 6687ebab453SWei Yongjun status = -EFAULT; 6692b462638SBen Hutchings goto out_free; 6707ebab453SWei Yongjun } 671d24a10b9STristan Ye 672d24a10b9STristan Ye status = 0; 673d24a10b9STristan Ye bail: 674d24a10b9STristan Ye if (status) 675d24a10b9STristan Ye o2info_set_request_error(&oiff->iff_req, req); 6762b462638SBen Hutchings out_free: 677d24a10b9STristan Ye kfree(oiff); 67887f0d5c8SDan Carpenter out_err: 679ddee5cdbSTristan Ye return status; 680ddee5cdbSTristan Ye } 681ddee5cdbSTristan Ye 682c253ed1fSFabian Frederick static int ocfs2_info_handle_unknown(struct inode *inode, 683ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 684ddee5cdbSTristan Ye { 685ddee5cdbSTristan Ye struct ocfs2_info_request oir; 686ddee5cdbSTristan Ye 687ddee5cdbSTristan Ye if (o2info_from_user(oir, req)) 6882b462638SBen Hutchings return -EFAULT; 689ddee5cdbSTristan Ye 6908aa1fa36STristan Ye o2info_clear_request_filled(&oir); 691ddee5cdbSTristan Ye 692ddee5cdbSTristan Ye if (o2info_to_user(oir, req)) 6932b462638SBen Hutchings return -EFAULT; 694ddee5cdbSTristan Ye 6952b462638SBen Hutchings return 0; 696ddee5cdbSTristan Ye } 697ddee5cdbSTristan Ye 698ddee5cdbSTristan Ye /* 699ddee5cdbSTristan Ye * Validate and distinguish OCFS2_IOC_INFO requests. 700ddee5cdbSTristan Ye * 701ddee5cdbSTristan Ye * - validate the magic number. 702ddee5cdbSTristan Ye * - distinguish different requests. 703ddee5cdbSTristan Ye * - validate size of different requests. 704ddee5cdbSTristan Ye */ 705c253ed1fSFabian Frederick static int ocfs2_info_handle_request(struct inode *inode, 706ddee5cdbSTristan Ye struct ocfs2_info_request __user *req) 707ddee5cdbSTristan Ye { 708ddee5cdbSTristan Ye int status = -EFAULT; 709ddee5cdbSTristan Ye struct ocfs2_info_request oir; 710ddee5cdbSTristan Ye 711ddee5cdbSTristan Ye if (o2info_from_user(oir, req)) 712ddee5cdbSTristan Ye goto bail; 713ddee5cdbSTristan Ye 714ddee5cdbSTristan Ye status = -EINVAL; 715ddee5cdbSTristan Ye if (oir.ir_magic != OCFS2_INFO_MAGIC) 716ddee5cdbSTristan Ye goto bail; 717ddee5cdbSTristan Ye 718ddee5cdbSTristan Ye switch (oir.ir_code) { 719ddee5cdbSTristan Ye case OCFS2_INFO_BLOCKSIZE: 720ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_blocksize)) 721ddee5cdbSTristan Ye status = ocfs2_info_handle_blocksize(inode, req); 722ddee5cdbSTristan Ye break; 723ddee5cdbSTristan Ye case OCFS2_INFO_CLUSTERSIZE: 724ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_clustersize)) 725ddee5cdbSTristan Ye status = ocfs2_info_handle_clustersize(inode, req); 726ddee5cdbSTristan Ye break; 727ddee5cdbSTristan Ye case OCFS2_INFO_MAXSLOTS: 728ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_maxslots)) 729ddee5cdbSTristan Ye status = ocfs2_info_handle_maxslots(inode, req); 730ddee5cdbSTristan Ye break; 731ddee5cdbSTristan Ye case OCFS2_INFO_LABEL: 732ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_label)) 733ddee5cdbSTristan Ye status = ocfs2_info_handle_label(inode, req); 734ddee5cdbSTristan Ye break; 735ddee5cdbSTristan Ye case OCFS2_INFO_UUID: 736ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_uuid)) 737ddee5cdbSTristan Ye status = ocfs2_info_handle_uuid(inode, req); 738ddee5cdbSTristan Ye break; 739ddee5cdbSTristan Ye case OCFS2_INFO_FS_FEATURES: 740ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_fs_features)) 741ddee5cdbSTristan Ye status = ocfs2_info_handle_fs_features(inode, req); 742ddee5cdbSTristan Ye break; 743ddee5cdbSTristan Ye case OCFS2_INFO_JOURNAL_SIZE: 744ddee5cdbSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_journal_size)) 745ddee5cdbSTristan Ye status = ocfs2_info_handle_journal_size(inode, req); 746ddee5cdbSTristan Ye break; 7473e5db17dSTristan Ye case OCFS2_INFO_FREEINODE: 7483e5db17dSTristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_freeinode)) 7493e5db17dSTristan Ye status = ocfs2_info_handle_freeinode(inode, req); 7503e5db17dSTristan Ye break; 751d24a10b9STristan Ye case OCFS2_INFO_FREEFRAG: 752d24a10b9STristan Ye if (oir.ir_size == sizeof(struct ocfs2_info_freefrag)) 753d24a10b9STristan Ye status = ocfs2_info_handle_freefrag(inode, req); 754d24a10b9STristan Ye break; 755ddee5cdbSTristan Ye default: 756ddee5cdbSTristan Ye status = ocfs2_info_handle_unknown(inode, req); 757ddee5cdbSTristan Ye break; 758ddee5cdbSTristan Ye } 759ddee5cdbSTristan Ye 760ddee5cdbSTristan Ye bail: 761ddee5cdbSTristan Ye return status; 762ddee5cdbSTristan Ye } 763ddee5cdbSTristan Ye 764c253ed1fSFabian Frederick static int ocfs2_get_request_ptr(struct ocfs2_info *info, int idx, 765ddee5cdbSTristan Ye u64 *req_addr, int compat_flag) 766ddee5cdbSTristan Ye { 767ddee5cdbSTristan Ye int status = -EFAULT; 768ddee5cdbSTristan Ye u64 __user *bp = NULL; 769ddee5cdbSTristan Ye 770ddee5cdbSTristan Ye if (compat_flag) { 771ddee5cdbSTristan Ye #ifdef CONFIG_COMPAT 772ddee5cdbSTristan Ye /* 773ddee5cdbSTristan Ye * pointer bp stores the base address of a pointers array, 774ddee5cdbSTristan Ye * which collects all addresses of separate request. 775ddee5cdbSTristan Ye */ 776ddee5cdbSTristan Ye bp = (u64 __user *)(unsigned long)compat_ptr(info->oi_requests); 777ddee5cdbSTristan Ye #else 778ddee5cdbSTristan Ye BUG(); 779ddee5cdbSTristan Ye #endif 780ddee5cdbSTristan Ye } else 781ddee5cdbSTristan Ye bp = (u64 __user *)(unsigned long)(info->oi_requests); 782ddee5cdbSTristan Ye 783ddee5cdbSTristan Ye if (o2info_from_user(*req_addr, bp + idx)) 784ddee5cdbSTristan Ye goto bail; 785ddee5cdbSTristan Ye 786ddee5cdbSTristan Ye status = 0; 787ddee5cdbSTristan Ye bail: 788ddee5cdbSTristan Ye return status; 789ddee5cdbSTristan Ye } 790ddee5cdbSTristan Ye 791ddee5cdbSTristan Ye /* 792ddee5cdbSTristan Ye * OCFS2_IOC_INFO handles an array of requests passed from userspace. 793ddee5cdbSTristan Ye * 794ddee5cdbSTristan Ye * ocfs2_info_handle() recevies a large info aggregation, grab and 795ddee5cdbSTristan Ye * validate the request count from header, then break it into small 796ddee5cdbSTristan Ye * pieces, later specific handlers can handle them one by one. 797ddee5cdbSTristan Ye * 798ddee5cdbSTristan Ye * Idea here is to make each separate request small enough to ensure 799ddee5cdbSTristan Ye * a better backward&forward compatibility, since a small piece of 800ddee5cdbSTristan Ye * request will be less likely to be broken if disk layout get changed. 801ddee5cdbSTristan Ye */ 802c253ed1fSFabian Frederick static int ocfs2_info_handle(struct inode *inode, struct ocfs2_info *info, 803ddee5cdbSTristan Ye int compat_flag) 804ddee5cdbSTristan Ye { 805ddee5cdbSTristan Ye int i, status = 0; 806ddee5cdbSTristan Ye u64 req_addr; 807ddee5cdbSTristan Ye struct ocfs2_info_request __user *reqp; 808ddee5cdbSTristan Ye 809ddee5cdbSTristan Ye if ((info->oi_count > OCFS2_INFO_MAX_REQUEST) || 810ddee5cdbSTristan Ye (!info->oi_requests)) { 811ddee5cdbSTristan Ye status = -EINVAL; 812ddee5cdbSTristan Ye goto bail; 813ddee5cdbSTristan Ye } 814ddee5cdbSTristan Ye 815ddee5cdbSTristan Ye for (i = 0; i < info->oi_count; i++) { 816ddee5cdbSTristan Ye 817ddee5cdbSTristan Ye status = ocfs2_get_request_ptr(info, i, &req_addr, compat_flag); 818ddee5cdbSTristan Ye if (status) 819ddee5cdbSTristan Ye break; 820ddee5cdbSTristan Ye 821f6a56903SAl Viro reqp = (struct ocfs2_info_request __user *)(unsigned long)req_addr; 822ddee5cdbSTristan Ye if (!reqp) { 823ddee5cdbSTristan Ye status = -EINVAL; 824ddee5cdbSTristan Ye goto bail; 825ddee5cdbSTristan Ye } 826ddee5cdbSTristan Ye 827ddee5cdbSTristan Ye status = ocfs2_info_handle_request(inode, reqp); 828ddee5cdbSTristan Ye if (status) 829ddee5cdbSTristan Ye break; 830ddee5cdbSTristan Ye } 831ddee5cdbSTristan Ye 832ddee5cdbSTristan Ye bail: 833ddee5cdbSTristan Ye return status; 834ddee5cdbSTristan Ye } 835ddee5cdbSTristan Ye 836c9ec1488SAndi Kleen long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 837ca4d147eSHerbert Poetzl { 838496ad9aaSAl Viro struct inode *inode = file_inode(filp); 839ca4d147eSHerbert Poetzl unsigned int flags; 840d659072fSTao Ma int new_clusters; 841ca4d147eSHerbert Poetzl int status; 842b2580103SMark Fasheh struct ocfs2_space_resv sr; 8437909f2bfSTao Ma struct ocfs2_new_group_input input; 844bd50873dSTao Ma struct reflink_arguments args; 845f6a56903SAl Viro const char __user *old_path; 846f6a56903SAl Viro const char __user *new_path; 847bd50873dSTao Ma bool preserve; 848ddee5cdbSTristan Ye struct ocfs2_info info; 849f6a56903SAl Viro void __user *argp = (void __user *)arg; 850ca4d147eSHerbert Poetzl 851ca4d147eSHerbert Poetzl switch (cmd) { 852ca4d147eSHerbert Poetzl case OCFS2_IOC_GETFLAGS: 853ca4d147eSHerbert Poetzl status = ocfs2_get_inode_attr(inode, &flags); 854ca4d147eSHerbert Poetzl if (status < 0) 855ca4d147eSHerbert Poetzl return status; 856ca4d147eSHerbert Poetzl 857ca4d147eSHerbert Poetzl flags &= OCFS2_FL_VISIBLE; 858ca4d147eSHerbert Poetzl return put_user(flags, (int __user *) arg); 859ca4d147eSHerbert Poetzl case OCFS2_IOC_SETFLAGS: 860ca4d147eSHerbert Poetzl if (get_user(flags, (int __user *) arg)) 861ca4d147eSHerbert Poetzl return -EFAULT; 862ca4d147eSHerbert Poetzl 863a561be71SAl Viro status = mnt_want_write_file(filp); 86442a74f20SDave Hansen if (status) 86542a74f20SDave Hansen return status; 86642a74f20SDave Hansen status = ocfs2_set_inode_attr(inode, flags, 867ca4d147eSHerbert Poetzl OCFS2_FL_MODIFIABLE); 8682a79f17eSAl Viro mnt_drop_write_file(filp); 86942a74f20SDave Hansen return status; 870b2580103SMark Fasheh case OCFS2_IOC_RESVSP: 871b2580103SMark Fasheh case OCFS2_IOC_RESVSP64: 872b2580103SMark Fasheh case OCFS2_IOC_UNRESVSP: 873b2580103SMark Fasheh case OCFS2_IOC_UNRESVSP64: 874b2580103SMark Fasheh if (copy_from_user(&sr, (int __user *) arg, sizeof(sr))) 875b2580103SMark Fasheh return -EFAULT; 876b2580103SMark Fasheh 877b2580103SMark Fasheh return ocfs2_change_file_space(filp, cmd, &sr); 878d659072fSTao Ma case OCFS2_IOC_GROUP_EXTEND: 8790957f007SMark Fasheh if (!capable(CAP_SYS_RESOURCE)) 8800957f007SMark Fasheh return -EPERM; 8810957f007SMark Fasheh 882d659072fSTao Ma if (get_user(new_clusters, (int __user *)arg)) 883d659072fSTao Ma return -EFAULT; 884d659072fSTao Ma 885fef6925cSJan Kara status = mnt_want_write_file(filp); 886fef6925cSJan Kara if (status) 887fef6925cSJan Kara return status; 888fef6925cSJan Kara status = ocfs2_group_extend(inode, new_clusters); 889fef6925cSJan Kara mnt_drop_write_file(filp); 890fef6925cSJan Kara return status; 8917909f2bfSTao Ma case OCFS2_IOC_GROUP_ADD: 8927909f2bfSTao Ma case OCFS2_IOC_GROUP_ADD64: 8930957f007SMark Fasheh if (!capable(CAP_SYS_RESOURCE)) 8940957f007SMark Fasheh return -EPERM; 8950957f007SMark Fasheh 8967909f2bfSTao Ma if (copy_from_user(&input, (int __user *) arg, sizeof(input))) 8977909f2bfSTao Ma return -EFAULT; 8987909f2bfSTao Ma 899fef6925cSJan Kara status = mnt_want_write_file(filp); 900fef6925cSJan Kara if (status) 901fef6925cSJan Kara return status; 902fef6925cSJan Kara status = ocfs2_group_add(inode, &input); 903fef6925cSJan Kara mnt_drop_write_file(filp); 904fef6925cSJan Kara return status; 905bd50873dSTao Ma case OCFS2_IOC_REFLINK: 906f6a56903SAl Viro if (copy_from_user(&args, argp, sizeof(args))) 907bd50873dSTao Ma return -EFAULT; 908f6a56903SAl Viro old_path = (const char __user *)(unsigned long)args.old_path; 909f6a56903SAl Viro new_path = (const char __user *)(unsigned long)args.new_path; 910bd50873dSTao Ma preserve = (args.preserve != 0); 911bd50873dSTao Ma 912bd50873dSTao Ma return ocfs2_reflink_ioctl(inode, old_path, new_path, preserve); 913ddee5cdbSTristan Ye case OCFS2_IOC_INFO: 914f6a56903SAl Viro if (copy_from_user(&info, argp, sizeof(struct ocfs2_info))) 915ddee5cdbSTristan Ye return -EFAULT; 916ddee5cdbSTristan Ye 917ddee5cdbSTristan Ye return ocfs2_info_handle(inode, &info, 0); 91855e67872STao Ma case FITRIM: 91955e67872STao Ma { 92055e67872STao Ma struct super_block *sb = inode->i_sb; 92119e8ac27SJie Liu struct request_queue *q = bdev_get_queue(sb->s_bdev); 92255e67872STao Ma struct fstrim_range range; 92355e67872STao Ma int ret = 0; 92455e67872STao Ma 92555e67872STao Ma if (!capable(CAP_SYS_ADMIN)) 92655e67872STao Ma return -EPERM; 92755e67872STao Ma 92819e8ac27SJie Liu if (!blk_queue_discard(q)) 92919e8ac27SJie Liu return -EOPNOTSUPP; 93019e8ac27SJie Liu 931f6a56903SAl Viro if (copy_from_user(&range, argp, sizeof(range))) 93255e67872STao Ma return -EFAULT; 93355e67872STao Ma 9341ba2212bSJie Liu range.minlen = max_t(u64, q->limits.discard_granularity, 9351ba2212bSJie Liu range.minlen); 93655e67872STao Ma ret = ocfs2_trim_fs(sb, &range); 93755e67872STao Ma if (ret < 0) 93855e67872STao Ma return ret; 93955e67872STao Ma 940f6a56903SAl Viro if (copy_to_user(argp, &range, sizeof(range))) 94155e67872STao Ma return -EFAULT; 94255e67872STao Ma 94355e67872STao Ma return 0; 94455e67872STao Ma } 94553069d4eSTristan Ye case OCFS2_IOC_MOVE_EXT: 946f6a56903SAl Viro return ocfs2_ioctl_move_extents(filp, argp); 947ca4d147eSHerbert Poetzl default: 948ca4d147eSHerbert Poetzl return -ENOTTY; 949ca4d147eSHerbert Poetzl } 950ca4d147eSHerbert Poetzl } 951ca4d147eSHerbert Poetzl 952586d232bSMark Fasheh #ifdef CONFIG_COMPAT 953586d232bSMark Fasheh long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) 954586d232bSMark Fasheh { 95534e6c59aSTao Ma bool preserve; 95634e6c59aSTao Ma struct reflink_arguments args; 957496ad9aaSAl Viro struct inode *inode = file_inode(file); 958ddee5cdbSTristan Ye struct ocfs2_info info; 959f6a56903SAl Viro void __user *argp = (void __user *)arg; 96034e6c59aSTao Ma 961586d232bSMark Fasheh switch (cmd) { 962586d232bSMark Fasheh case OCFS2_IOC32_GETFLAGS: 963586d232bSMark Fasheh cmd = OCFS2_IOC_GETFLAGS; 964586d232bSMark Fasheh break; 965586d232bSMark Fasheh case OCFS2_IOC32_SETFLAGS: 966586d232bSMark Fasheh cmd = OCFS2_IOC_SETFLAGS; 967586d232bSMark Fasheh break; 968b2580103SMark Fasheh case OCFS2_IOC_RESVSP: 969b2580103SMark Fasheh case OCFS2_IOC_RESVSP64: 970b2580103SMark Fasheh case OCFS2_IOC_UNRESVSP: 971b2580103SMark Fasheh case OCFS2_IOC_UNRESVSP64: 972d659072fSTao Ma case OCFS2_IOC_GROUP_EXTEND: 9737909f2bfSTao Ma case OCFS2_IOC_GROUP_ADD: 9747909f2bfSTao Ma case OCFS2_IOC_GROUP_ADD64: 975b2580103SMark Fasheh break; 97634e6c59aSTao Ma case OCFS2_IOC_REFLINK: 977f6a56903SAl Viro if (copy_from_user(&args, argp, sizeof(args))) 97834e6c59aSTao Ma return -EFAULT; 97934e6c59aSTao Ma preserve = (args.preserve != 0); 98034e6c59aSTao Ma 98134e6c59aSTao Ma return ocfs2_reflink_ioctl(inode, compat_ptr(args.old_path), 98234e6c59aSTao Ma compat_ptr(args.new_path), preserve); 983ddee5cdbSTristan Ye case OCFS2_IOC_INFO: 984f6a56903SAl Viro if (copy_from_user(&info, argp, sizeof(struct ocfs2_info))) 985ddee5cdbSTristan Ye return -EFAULT; 986ddee5cdbSTristan Ye 987ddee5cdbSTristan Ye return ocfs2_info_handle(inode, &info, 1); 988*314999dcSArnd Bergmann case FITRIM: 98953069d4eSTristan Ye case OCFS2_IOC_MOVE_EXT: 99053069d4eSTristan Ye break; 991586d232bSMark Fasheh default: 992586d232bSMark Fasheh return -ENOIOCTLCMD; 993586d232bSMark Fasheh } 994586d232bSMark Fasheh 995c9ec1488SAndi Kleen return ocfs2_ioctl(file, cmd, arg); 996586d232bSMark Fasheh } 997586d232bSMark Fasheh #endif 998