Ocfs2: Move ocfs2 ioctl definitions from ocfs2_fs.h to newly added ocfs2_ioctl.h
PATCH 1/2 Ocfs2: Move ocfs2 ioctl definitions from ocfs2_fs.h to newly added ocfs2_ioctl.h
Currently we were adding ioctl cmds/structures for ocfs2 into ocfs2_fs.h which was used for define ocfs2 on-disk layout. That sounds a little bit confusing, and it may be quickly polluted espcially when growing the ocfs2_info_request ioctls afterwards(it will grow i bet).
As a result, such OCFS2 IOCs do need to be placed somewhere other than ocfs2_fs.h, a separated ocfs2_ioctl.h will be added to store such ioctl structures and definitions which could also be used from userspace to invoke ioctls call.
[This patch has already been in joel's fixes branch]
--- fs/ocfs2/ioctl.h | 6 ++-- fs/ocfs2/ocfs2.h | 1 + fs/ocfs2/ocfs2_fs.h | 57 ---------------------------------- fs/ocfs2/ocfs2_ioctl.h | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 60 deletions(-) create mode 100644 fs/ocfs2/ocfs2_ioctl.h
fs/ocfs2/ioctl.h +3 -3
@@ -7,10 +7,10 @@* */ -#ifndef OCFS2_IOCTL_H -#define OCFS2_IOCTL_H +#ifndef OCFS2_IOCTL_PROTO_H +#define OCFS2_IOCTL_PROTO_H long ocfs2_ioctl (struct file *filp,unsigned int cmd,unsigned long arg);long ocfs2_compat_ioctl (struct file *file,unsigned cmd,unsigned long arg); -#endif /* OCFS2_IOCTL_H */ +#endif /* OCFS2_IOCTL_PROTO_H */
fs/ocfs2/ocfs2.h +1 -0
@@ -42,6 +42,7 @@#include "ocfs2_fs.h" #include "ocfs2_lockid.h" +#include "ocfs2_ioctl.h" /* For struct ocfs2_blockcheck_stats */ #include "blockcheck.h"
fs/ocfs2/ocfs2_fs.h +0 -57
63 lines not on this page · raw message
fs/ocfs2/ocfs2_ioctl.h new file +79 -0
79 lines not on this page · raw message
Signature · 1 line
1.5.5
PATCH 2/2 Ocfs2: Add new OCFS2_IOC_INFO ioctl for ocfs2 v6.
The reason why we need this ioctl is to offer the none-privileged end-user a possibility to get filesys info gathering.
We use OCFS2_IOC_INFO to manipulate the new ioctl, userspace passes a structure to kernel containing an array of request pointers and request count, such as,
* From userspace:
struct ocfs2_info_blocksize brq = {
.ir_request = {
.ir_magic = OCFS2_INFO_MAGIC,
.ir_code = OCFS2_INFO_BLOCKSIZE,
...
}
...
}struct ocfs2_info_clustersize crq = {
...
}uint64_t reqs[2] = {(unsigned long)&brq,
(unsigned long)&crq};
struct ocfs2_info info = {
.ir_requests = reqs,
.ir_count = 2,
}
ret = ioctl(fd, OCFS2_IOC_INFO, &info);
* In kernel:
Get the request pointers from *info*, then handle each request one bye one.
Idea here is to make the spearated request small enough to guarantee a better backward&forward compatibility since a small piece of request would be less likely to be broken if filesys on raw disk get changed.
Currently, following 8 ioctls get implemented per the requirement from userspace tool o2info, and I believe it will grow over time:-)
OCFS2_INFO_CLUSTERSIZE
OCFS2_INFO_BLOCKSIZE
OCFS2_INFO_SLOTNUM
OCFS2_INFO_LABEL
OCFS2_INFO_UUID
OCFS2_INFO_FS_FEATURES
OCFS2_INFO_FREEFRAG
OCFS2_INFO_FREEINODE
This ioctl is only specific to OCFS2.
--- fs/ocfs2/ioctl.c | 677 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/ocfs2_ioctl.h | 117 +++++++++ 2 files changed, 794 insertions(+), 0 deletions(-)
fs/ocfs2/ioctl.c +677 -0
@@ -23,8 +23,13 @@#include "ioctl.h" #include "resize.h" #include "refcounttree.h" +#include "sysfile.h" +#include "buffer_head_io.h" +#include "suballoc.h" +#include <linux/ext2_fs.h> +#include <linux/compat.h> static int ocfs2_get_inode_attr (struct inode *inode,unsigned *flags) {
@@ -109,6 +114,664 @@ bail:return status; } +int ocfs2_info_handle_blocksize (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_blocksize req_bs; + +if (copy_from_user (&req_bs, user_req, +sizeof (struct ocfs2_info_blocksize ))) { + status = -EFAULT ; + goto bail; + } + + req_bs.ir_blocksize = inode->i_sb->s_blocksize; + req_bs.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_blocksize __user *)user_req, + &req_bs, +sizeof (struct ocfs2_info_blocksize ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_clustersize (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_clustersize req_cs; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_cs, user_req, +sizeof (struct ocfs2_info_clustersize ))) { + status = -EFAULT ; + goto bail; + } + + req_cs.ir_clustersize = osb->s_clustersize; + req_cs.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_clustersize __user *)user_req, + &req_cs, +sizeof (struct ocfs2_info_clustersize ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_slotnum (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_slotnum req_sn; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_sn, user_req, +sizeof (struct ocfs2_info_slotnum ))) { + status = -EFAULT ; + goto bail; + } + + req_sn.ir_slotnum = osb->max_slots; + req_sn.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_slotnum __user *)user_req, + &req_sn, +sizeof (struct ocfs2_info_slotnum ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_label (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_label req_lb; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_lb, user_req, +sizeof (struct ocfs2_info_label ))) { + status = -EFAULT ; + goto bail; + } + +memcpy (req_lb.ir_label, osb->vol_label,OCFS2_MAX_VOL_LABEL_LEN ); + req_lb.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_label __user *)user_req, + &req_lb, +sizeof (struct ocfs2_info_label ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_uuid (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_uuid req_uuid; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_uuid, user_req, +sizeof (struct ocfs2_info_uuid ))) { + status = -EFAULT ; + goto bail; + } + +memcpy (req_uuid.ir_uuid_str, osb->uuid_str,OCFS2_INFO_VOL_UUIDSTR_LEN ); + req_uuid.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_uuid __user *)user_req, + &req_uuid, +sizeof (struct ocfs2_info_uuid ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_fs_features (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_fs_features req_fs; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_fs, user_req, +sizeof (struct ocfs2_info_fs_features ))) { + status = -EFAULT ; + goto bail; + } + + req_fs.ir_compat_features = osb->s_feature_compat; + req_fs.ir_incompat_features = osb->s_feature_incompat; + req_fs.ir_ro_compat_features = osb->s_feature_ro_compat; + req_fs.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_fs_features __user *)user_req, + &req_fs, +sizeof (struct ocfs2_info_fs_features ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +void ocfs2_info_update_ffg (struct ocfs2_info_freefrag *ffg, +unsigned int chunksize) +{ +int index; + + index =__ilog2_u32 (chunksize); +if (index >=OCFS2_INFO_MAX_HIST ) + index =OCFS2_INFO_MAX_HIST -1 ; + + ffg->ir_ffg.ir_fc_hist.ir_fc_chunks[index]++; + ffg->ir_ffg.ir_fc_hist.ir_fc_clusters[index] += chunksize; + +if (chunksize > ffg->ir_ffg.ir_max) + ffg->ir_ffg.ir_max = chunksize; + +if (chunksize < ffg->ir_ffg.ir_min) + ffg->ir_ffg.ir_min = chunksize; + + ffg->ir_ffg.ir_avg += chunksize; + ffg->ir_ffg.ir_free_chunks_real++; +} + +int ocfs2_info_scan_chain (struct inode *gb_inode, +struct ocfs2_dinode *gb_dinode, +struct ocfs2_info_freefrag *ffg, +struct ocfs2_chain_rec *rec, +unsigned int chunks_in_group) +{ +int status =0 , used; +u64 blkno; + +struct buffer_head *bh =NULL ; +struct ocfs2_group_desc *bg =NULL ; + +unsigned int max_bits, num_clusters; +unsigned int offset =0 , cluster, chunk; +unsigned int chunk_free, last_chunksize =0 ; + +if (!le32_to_cpu (rec->c_free)) + goto bail; + +do { +if (!bg) + blkno =le64_to_cpu (rec->c_blkno); +else + blkno =le64_to_cpu (bg->bg_next_group); + +if (bh) { +brelse (bh); + bh =NULL ; + } + + status =ocfs2_read_group_descriptor (gb_inode, gb_dinode, + blkno, &bh); +if (status <0 ) { +mlog (ML_ERROR ,"Can't read the group descriptor # " +"%llu from device." , (unsigned long long )blkno); + status = -EIO ; + goto bail; + } + + bg = (struct ocfs2_group_desc *)bh->b_data; + +if (!le16_to_cpu (bg->bg_free_bits_count)) +continue ; + + max_bits =le16_to_cpu (bg->bg_bits); + offset =0 ; + +for (chunk =0 ; chunk < chunks_in_group; chunk++) { + +/* Last chunk may be not a entire one */ +if ((offset + ffg->ir_chunksize) > max_bits) + num_clusters = max_bits - offset; +else + num_clusters = ffg->ir_chunksize; + + chunk_free =0 ; +for (cluster =0 ; cluster < num_clusters; cluster++) { + used =ocfs2_test_bit (offset, + (unsigned long *)bg->bg_bitmap); +if (!used) { + last_chunksize++; + chunk_free++; + } + +if (used && (last_chunksize)) { +ocfs2_info_update_ffg (ffg, + last_chunksize); + last_chunksize =0 ; + } + + offset++; + } + +if (chunk_free == ffg->ir_chunksize) + ffg->ir_ffg.ir_free_chunks++; + } + +/* we need to update the info of last free chunk */ +if (last_chunksize) +ocfs2_info_update_ffg (ffg, last_chunksize); + + }while (le64_to_cpu (bg->bg_next_group)); + +bail: +brelse (bh); + +mlog_exit (status); +return status; +} + +int ocfs2_info_scan_bitmap (struct inode *gb_inode, +struct ocfs2_dinode *gb_dinode, +struct ocfs2_info_freefrag *ffg, +struct ocfs2_chain_list *cl) +{ +int status =0 , i; +unsigned int chunks_in_group; +struct ocfs2_chain_rec *rec =NULL ; + + chunks_in_group =le16_to_cpu (cl->cl_cpg) / ffg->ir_chunksize +1 ; + +for (i =0 ; i <le16_to_cpu (cl->cl_next_free_rec); i++) { + + rec = &(cl->cl_recs[i]); + status =ocfs2_info_scan_chain (gb_inode, gb_dinode, + ffg, rec, chunks_in_group); +if (status) + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_freefrag (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 , unlock =0 ; + +struct ocfs2_info_freefrag req_ffg; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); +struct buffer_head *bh =NULL ; +struct inode *gb_inode =NULL ; +struct ocfs2_dinode *gb_dinode =NULL ; +struct ocfs2_chain_list *cl =NULL ; + +if (copy_from_user (&req_ffg, user_req, +sizeof (struct ocfs2_info_freefrag ))) { + status = -EFAULT ; + goto bail; + } + +/* +* chunksize from userspace should be power of 2, +*/ +if ((req_ffg.ir_chunksize & (req_ffg.ir_chunksize -1 )) || + (!req_ffg.ir_chunksize)) { + status = -EINVAL ; + goto bail; + } + +memset (&req_ffg.ir_ffg,0 ,sizeof (struct ocfs2_info_freefrag_stats )); + req_ffg.ir_ffg.ir_min = ~0U ; + + gb_inode =ocfs2_get_system_file_inode (osb, +GLOBAL_BITMAP_SYSTEM_INODE , +OCFS2_INVALID_SLOT ); +if (!gb_inode) { +mlog (ML_ERROR ,"failed to get bitmap inode\n" ); + status = -EIO ; + goto bail; + } + +mutex_lock (&gb_inode->i_mutex); + +if (!(req_ffg.ir_request.ir_flags &OCFS2_INFO_FL_NON_COHERENT )) { + status =ocfs2_inode_lock (gb_inode, &bh,0 ); +if (status <0 ) { +mlog_errno (status); + goto bail_mutex_unlock; + } + unlock =1 ; + + }else { + status =ocfs2_read_inode_block (gb_inode, &bh); +if (status <0 ) { +mlog_errno (status); + goto bail; + } + } + + gb_dinode = (struct ocfs2_dinode *)bh->b_data; + + req_ffg.ir_ffg.ir_clusters = +le32_to_cpu (gb_dinode->id1.bitmap1.i_total); + req_ffg.ir_ffg.ir_free_clusters = req_ffg.ir_ffg.ir_clusters - +le32_to_cpu (gb_dinode->id1.bitmap1.i_used); + + cl = &(gb_dinode->id2.i_chain); + +/* Chunksize from userspace should be less than clusters in a group */ +if (req_ffg.ir_chunksize >le16_to_cpu (cl->cl_cpg)) { + status = -EINVAL ; + goto bail; + } + + status =ocfs2_info_scan_bitmap (gb_inode, gb_dinode, &req_ffg, cl); +if (status) + goto bail; + +if (req_ffg.ir_ffg.ir_free_chunks_real) + req_ffg.ir_ffg.ir_avg = (req_ffg.ir_ffg.ir_avg / + req_ffg.ir_ffg.ir_free_chunks_real); + + req_ffg.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_freefrag __user *)user_req, + &req_ffg, +sizeof (struct ocfs2_info_freefrag ))) { + status = -EFAULT ; + goto bail; + } + +bail: +if (unlock) +ocfs2_inode_unlock (gb_inode,0 ); + +bail_mutex_unlock: +if (gb_inode) +mutex_unlock (&gb_inode->i_mutex); + +iput (gb_inode); +brelse (bh); + +mlog_exit (status); +return status; +} + +int ocfs2_info_scan_inode_alloc (struct inode *inode_alloc, +struct ocfs2_info_freeinode *fi, +__u32 slotnum, +int flags) +{ +int status =0 , unlock =0 ; + +struct buffer_head *bh =NULL ; +struct ocfs2_dinode *dinode_alloc =NULL ; + +mutex_lock (&inode_alloc->i_mutex); + +if (!(flags &OCFS2_INFO_FL_NON_COHERENT )) { + status =ocfs2_inode_lock (inode_alloc, &bh,0 ); +if (status <0 ) { +mlog_errno (status); + goto bail_mutex_unlock; + } + unlock =1 ; + + }else { + + status =ocfs2_read_inode_block (inode_alloc, &bh); +if (status <0 ) { +mlog_errno (status); + goto bail; + } + } + + dinode_alloc = (struct ocfs2_dinode *)bh->b_data; + + fi->ir_fi_stat[slotnum].ir_total = +le32_to_cpu (dinode_alloc->id1.bitmap1.i_total); + fi->ir_fi_stat[slotnum].ir_free = +le32_to_cpu (dinode_alloc->id1.bitmap1.i_total) - +le32_to_cpu (dinode_alloc->id1.bitmap1.i_used); +bail: +if (unlock) +ocfs2_inode_unlock (inode_alloc,0 ); + +bail_mutex_unlock: +mutex_unlock (&inode_alloc->i_mutex); + +iput (inode_alloc); +brelse (bh); + +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_freeinode (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 , i; + +struct ocfs2_info_freeinode req_fi; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); +struct inode *inode_alloc =NULL ; + + +if (copy_from_user (&req_fi, user_req, +sizeof (struct ocfs2_info_freeinode ))) { + status = -EFAULT ; + goto bail; + } + + req_fi.ir_slotnum = osb->max_slots; + +for (i =0 ; i < req_fi.ir_slotnum; i++) { + inode_alloc = +ocfs2_get_system_file_inode (osb, +INODE_ALLOC_SYSTEM_INODE , + i); +if (!inode_alloc) { +mlog (ML_ERROR ,"unable to get alloc inode in slot %u\n" , + (u32 )i); + status = -EIO ; + goto bail; + } + + status =ocfs2_info_scan_inode_alloc (inode_alloc, &req_fi, i, + req_fi.ir_request.ir_flags); +if (status <0 ) + goto bail; + } + + req_fi.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_freeinode __user *)user_req, + &req_fi, +sizeof (struct ocfs2_info_freeinode ))) { + status = -EFAULT ; + } + +bail: + +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_unknown (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_request req; + +if (copy_from_user (&req, user_req,sizeof (struct ocfs2_info_request ))) { + status = -EFAULT ; + goto bail; + } + + req.ir_flags &= ~OCFS2_INFO_FL_FILLED ; + +if (copy_to_user (user_req, &req, +sizeof (struct ocfs2_info_request ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_request (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_request req; + +if (copy_from_user (&req, user_req,sizeof (struct ocfs2_info_request ))) { + status = -EFAULT ; + goto bail; + } + +if (req.ir_magic !=OCFS2_INFO_MAGIC ) { + status = -EINVAL ; + goto bail; + } + +switch (req.ir_code) { +case OCFS2_INFO_BLOCKSIZE : +if (req.ir_size !=sizeof (struct ocfs2_info_blocksize )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_blocksize (inode, user_req); +break ; +case OCFS2_INFO_CLUSTERSIZE : +if (req.ir_size !=sizeof (struct ocfs2_info_clustersize )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_clustersize (inode, user_req); +break ; +case OCFS2_INFO_SLOTNUM : +if (req.ir_size !=sizeof (struct ocfs2_info_slotnum )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_slotnum (inode, user_req); +break ; +case OCFS2_INFO_LABEL : +if (req.ir_size !=sizeof (struct ocfs2_info_label )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_label (inode, user_req); +break ; +case OCFS2_INFO_UUID : +if (req.ir_size !=sizeof (struct ocfs2_info_uuid )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_uuid (inode, user_req); +break ; +case OCFS2_INFO_FS_FEATURES : +if (req.ir_size !=sizeof (struct ocfs2_info_fs_features )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_fs_features (inode, user_req); +break ; +case OCFS2_INFO_FREEFRAG : +if (req.ir_size !=sizeof (struct ocfs2_info_freefrag )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_freefrag (inode, user_req); +break ; +case OCFS2_INFO_FREEINODE : +if (req.ir_size !=sizeof (struct ocfs2_info_freeinode )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_freeinode (inode, user_req); +break ; +default : + status =ocfs2_info_handle_unknown (inode, user_req); +break ; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle (struct inode *inode,struct ocfs2_info *info, +int compat_flag) +{ +int i, status =0 ; +u64 req_addr; +struct ocfs2_info_request __user *reqp; + +if ((info->info_count >OCFS2_INFO_MAX_REQUEST ) || + (!info->info_requests)) { + status = -EINVAL ; + goto bail; + } + +for (i =0 ; i < info->info_count; i++) { + status = -EFAULT ; +if (compat_flag) { +if (get_user (req_addr, + (u64 __user *)compat_ptr (info->info_requests) + i)) + goto bail; + }else { +if (get_user (req_addr, + (u64 __user *)(info->info_requests) + i)) + goto bail; + } + + reqp = (struct ocfs2_info_request *)req_addr; +if (!reqp) { + status = -EINVAL ; + goto bail; + } + + status =ocfs2_info_handle_request (inode, reqp); +if (status) + goto bail; + } + +bail: +mlog_exit (status); +return status; +} +long ocfs2_ioctl (struct file *filp,unsigned int cmd,unsigned long arg) {struct inode *inode = filp->f_path.dentry->d_inode;
@@ -120,6 +783,7 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)struct reflink_arguments args;const char *old_path, *new_path;bool preserve; +struct ocfs2_info info;switch (cmd) {case OCFS2_IOC_GETFLAGS :
@@ -174,6 +838,12 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) preserve = (args.preserve !=0 );return ocfs2_reflink_ioctl (inode, old_path, new_path, preserve); +case OCFS2_IOC_INFO : +if (copy_from_user (&info, (struct ocfs2_info __user *)arg, +sizeof (struct ocfs2_info ))) +return -EFAULT ; + +return ocfs2_info_handle (inode, &info,0 );default :return -ENOTTY ; }
@@ -185,6 +855,7 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)bool preserve;struct reflink_arguments args;struct inode *inode = file->f_path.dentry->d_inode; +struct ocfs2_info info;switch (cmd) {case OCFS2_IOC32_GETFLAGS :
@@ -209,6 +880,12 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)return ocfs2_reflink_ioctl (inode,compat_ptr (args.old_path),compat_ptr (args.new_path), preserve); +case OCFS2_IOC_INFO : +if (copy_from_user (&info, (struct ocfs2_info __user *)arg, +sizeof (struct ocfs2_info ))) +return -EFAULT ; + +return ocfs2_info_handle (inode, &info,1 );default :return -ENOIOCTLCMD ; }
fs/ocfs2/ocfs2_ioctl.h +117 -0
121 lines not on this page · raw message
Signature · 1 line
1.5.5
PATCH 2/2 Ocfs2: Add new OCFS2_IOC_INFO ioctl for ocfs2 v6.
I like the overall flow. I just have some comments on style.
Also, would prefer if you drop freeinode and freefrag for the first checkin. That not only needs a closer look.
For the next drop, just have this patch. The first one is in mainline.
Thanks
Quoted 80 lines · Tristan Ye
The reason why we need this ioctl is to offer the none-privileged end-user a possibility to get filesys info gathering.
We use
OCFS2_IOC_INFOto manipulate the new ioctl, userspace passes a structure to kernel containing an array of request pointers and request count, such as,* From userspace:
struct ocfs2_info_blocksize brq = { .ir_request = { .ir_magic = OCFS2_INFO_MAGIC, .ir_code = OCFS2_INFO_BLOCKSIZE, ... } ... }struct ocfs2_info_clustersize crq = { ... }
uint64_treqs[2] = {(unsigned long)&brq,(unsigned long)&crq};struct
ocfs2_infoinfo = {
.ir_requests = reqs,
.ir_count = 2,
}ret =
ioctl(fd, OCFS2_IOC_INFO, &info);* In kernel:
Get the request pointers from *info*, then handle each request one bye one.
Idea here is to make the spearated request small enough to guarantee a better backward&forward compatibility since a small piece of request would be less likely to be broken if filesys on raw disk get changed.
Currently, following 8 ioctls get implemented per the requirement from userspace tool o2info, and I believe it will grow over time:-)
OCFS2_INFO_CLUSTERSIZE
OCFS2_INFO_BLOCKSIZE
OCFS2_INFO_SLOTNUM
OCFS2_INFO_LABEL
OCFS2_INFO_UUID
OCFS2_INFO_FS_FEATURES
OCFS2_INFO_FREEFRAG
OCFS2_INFO_FREEINODEThis ioctl is only specific to OCFS2.
Signed-off-by Tristan Ye <[email protected]>Signed-off-by Joel Becker <[email protected]>--- fs/ocfs2/ioctl.c | 677 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/ocfs2_ioctl.h | 117 +++++++++ 2 files changed, 794 insertions(+), 0 deletions(-)fs/ocfs2/ioctl.c +5
-0@@ -23,8 +23,13 @@#include "ioctl.h" #include "resize.h" #include "refcounttree.h" +#include "sysfile.h" +#include "buffer_head_io.h" +#include "suballoc.h" +#include <linux/ext2_fs.h> +#include <linux/compat.h> static int ocfs2_get_inode_attr (struct inode *inode,unsigned *flags) {
fs/ocfs2/ioctl.c bail: · line 122
Quoted 9 lines
fs/ocfs2/ioctl.c +5
-0@@ -109,6 +114,664 @@ bail:return status; } +int ocfs2_info_handle_blocksize (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_blocksize req_bs;
req_bs is a mouthful. How about "oib"? For the next function it could be "oic"? We do this everywhere. eg, osb, di, et, el, etc.
Quoted 10 lines
fs/ocfs2/ioctl.c +10
-0+ +if (copy_from_user (&req_bs, user_req, +sizeof (struct ocfs2_info_blocksize ))) { + status = -EFAULT ; + goto bail; + } + + req_bs.ir_blocksize = inode->i_sb->s_blocksize; + req_bs.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; +
fs/ocfs2/ioctl.c bail:
Quoted 10 lines
fs/ocfs2/ioctl.c +9
-0+if (copy_to_user ((struct ocfs2_info_blocksize __user *)user_req, + &req_bs, +sizeof (struct ocfs2_info_blocksize ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status);
Don't have a exit without an entry. But I think we can do without the entry/exit mlogs in these ioctls.
fs/ocfs2/ioctl.c bail:
Quoted 8 lines
fs/ocfs2/ioctl.c +7
-0+return status; +} + +int ocfs2_info_handle_clustersize (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ;
Or, you could set it to -EFAULT here and set it to 0 just before bail.
Quoted 571 lines
fs/ocfs2/ioctl.c +570
-0+struct ocfs2_info_clustersize req_cs; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_cs, user_req, +sizeof (struct ocfs2_info_clustersize ))) { + status = -EFAULT ; + goto bail; + } + + req_cs.ir_clustersize = osb->s_clustersize; + req_cs.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_clustersize __user *)user_req, + &req_cs, +sizeof (struct ocfs2_info_clustersize ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_slotnum (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_slotnum req_sn; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_sn, user_req, +sizeof (struct ocfs2_info_slotnum ))) { + status = -EFAULT ; + goto bail; + } + + req_sn.ir_slotnum = osb->max_slots; + req_sn.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_slotnum __user *)user_req, + &req_sn, +sizeof (struct ocfs2_info_slotnum ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_label (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_label req_lb; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_lb, user_req, +sizeof (struct ocfs2_info_label ))) { + status = -EFAULT ; + goto bail; + } + +memcpy (req_lb.ir_label, osb->vol_label,OCFS2_MAX_VOL_LABEL_LEN ); + req_lb.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_label __user *)user_req, + &req_lb, +sizeof (struct ocfs2_info_label ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_uuid (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_uuid req_uuid; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_uuid, user_req, +sizeof (struct ocfs2_info_uuid ))) { + status = -EFAULT ; + goto bail; + } + +memcpy (req_uuid.ir_uuid_str, osb->uuid_str,OCFS2_INFO_VOL_UUIDSTR_LEN ); + req_uuid.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_uuid __user *)user_req, + &req_uuid, +sizeof (struct ocfs2_info_uuid ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_fs_features (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_fs_features req_fs; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_fs, user_req, +sizeof (struct ocfs2_info_fs_features ))) { + status = -EFAULT ; + goto bail; + } + + req_fs.ir_compat_features = osb->s_feature_compat; + req_fs.ir_incompat_features = osb->s_feature_incompat; + req_fs.ir_ro_compat_features = osb->s_feature_ro_compat; + req_fs.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_fs_features __user *)user_req, + &req_fs, +sizeof (struct ocfs2_info_fs_features ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +void ocfs2_info_update_ffg (struct ocfs2_info_freefrag *ffg, +unsigned int chunksize) +{ +int index; + + index =__ilog2_u32 (chunksize); +if (index >=OCFS2_INFO_MAX_HIST ) + index =OCFS2_INFO_MAX_HIST -1 ; + + ffg->ir_ffg.ir_fc_hist.ir_fc_chunks[index]++; + ffg->ir_ffg.ir_fc_hist.ir_fc_clusters[index] += chunksize; + +if (chunksize > ffg->ir_ffg.ir_max) + ffg->ir_ffg.ir_max = chunksize; + +if (chunksize < ffg->ir_ffg.ir_min) + ffg->ir_ffg.ir_min = chunksize; + + ffg->ir_ffg.ir_avg += chunksize; + ffg->ir_ffg.ir_free_chunks_real++; +} + +int ocfs2_info_scan_chain (struct inode *gb_inode, +struct ocfs2_dinode *gb_dinode, +struct ocfs2_info_freefrag *ffg, +struct ocfs2_chain_rec *rec, +unsigned int chunks_in_group) +{ +int status =0 , used; +u64 blkno; + +struct buffer_head *bh =NULL ; +struct ocfs2_group_desc *bg =NULL ; + +unsigned int max_bits, num_clusters; +unsigned int offset =0 , cluster, chunk; +unsigned int chunk_free, last_chunksize =0 ; + +if (!le32_to_cpu (rec->c_free)) + goto bail; + +do { +if (!bg) + blkno =le64_to_cpu (rec->c_blkno); +else + blkno =le64_to_cpu (bg->bg_next_group); + +if (bh) { +brelse (bh); + bh =NULL ; + } + + status =ocfs2_read_group_descriptor (gb_inode, gb_dinode, + blkno, &bh); +if (status <0 ) { +mlog (ML_ERROR ,"Can't read the group descriptor # " +"%llu from device." , (unsigned long long )blkno); + status = -EIO ; + goto bail; + } + + bg = (struct ocfs2_group_desc *)bh->b_data; + +if (!le16_to_cpu (bg->bg_free_bits_count)) +continue ; + + max_bits =le16_to_cpu (bg->bg_bits); + offset =0 ; + +for (chunk =0 ; chunk < chunks_in_group; chunk++) { + +/* Last chunk may be not a entire one */ +if ((offset + ffg->ir_chunksize) > max_bits) + num_clusters = max_bits - offset; +else + num_clusters = ffg->ir_chunksize; + + chunk_free =0 ; +for (cluster =0 ; cluster < num_clusters; cluster++) { + used =ocfs2_test_bit (offset, + (unsigned long *)bg->bg_bitmap); +if (!used) { + last_chunksize++; + chunk_free++; + } + +if (used && (last_chunksize)) { +ocfs2_info_update_ffg (ffg, + last_chunksize); + last_chunksize =0 ; + } + + offset++; + } + +if (chunk_free == ffg->ir_chunksize) + ffg->ir_ffg.ir_free_chunks++; + } + +/* we need to update the info of last free chunk */ +if (last_chunksize) +ocfs2_info_update_ffg (ffg, last_chunksize); + + }while (le64_to_cpu (bg->bg_next_group)); + +bail: +brelse (bh); + +mlog_exit (status); +return status; +} + +int ocfs2_info_scan_bitmap (struct inode *gb_inode, +struct ocfs2_dinode *gb_dinode, +struct ocfs2_info_freefrag *ffg, +struct ocfs2_chain_list *cl) +{ +int status =0 , i; +unsigned int chunks_in_group; +struct ocfs2_chain_rec *rec =NULL ; + + chunks_in_group =le16_to_cpu (cl->cl_cpg) / ffg->ir_chunksize +1 ; + +for (i =0 ; i <le16_to_cpu (cl->cl_next_free_rec); i++) { + + rec = &(cl->cl_recs[i]); + status =ocfs2_info_scan_chain (gb_inode, gb_dinode, + ffg, rec, chunks_in_group); +if (status) + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_freefrag (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 , unlock =0 ; + +struct ocfs2_info_freefrag req_ffg; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); +struct buffer_head *bh =NULL ; +struct inode *gb_inode =NULL ; +struct ocfs2_dinode *gb_dinode =NULL ; +struct ocfs2_chain_list *cl =NULL ; + +if (copy_from_user (&req_ffg, user_req, +sizeof (struct ocfs2_info_freefrag ))) { + status = -EFAULT ; + goto bail; + } + +/* +* chunksize from userspace should be power of 2, +*/ +if ((req_ffg.ir_chunksize & (req_ffg.ir_chunksize -1 )) || + (!req_ffg.ir_chunksize)) { + status = -EINVAL ; + goto bail; + } + +memset (&req_ffg.ir_ffg,0 ,sizeof (struct ocfs2_info_freefrag_stats )); + req_ffg.ir_ffg.ir_min = ~0U ; + + gb_inode =ocfs2_get_system_file_inode (osb, +GLOBAL_BITMAP_SYSTEM_INODE , +OCFS2_INVALID_SLOT ); +if (!gb_inode) { +mlog (ML_ERROR ,"failed to get bitmap inode\n" ); + status = -EIO ; + goto bail; + } + +mutex_lock (&gb_inode->i_mutex); + +if (!(req_ffg.ir_request.ir_flags &OCFS2_INFO_FL_NON_COHERENT )) { + status =ocfs2_inode_lock (gb_inode, &bh,0 ); +if (status <0 ) { +mlog_errno (status); + goto bail_mutex_unlock; + } + unlock =1 ; + + }else { + status =ocfs2_read_inode_block (gb_inode, &bh); +if (status <0 ) { +mlog_errno (status); + goto bail; + } + } + + gb_dinode = (struct ocfs2_dinode *)bh->b_data; + + req_ffg.ir_ffg.ir_clusters = +le32_to_cpu (gb_dinode->id1.bitmap1.i_total); + req_ffg.ir_ffg.ir_free_clusters = req_ffg.ir_ffg.ir_clusters - +le32_to_cpu (gb_dinode->id1.bitmap1.i_used); + + cl = &(gb_dinode->id2.i_chain); + +/* Chunksize from userspace should be less than clusters in a group */ +if (req_ffg.ir_chunksize >le16_to_cpu (cl->cl_cpg)) { + status = -EINVAL ; + goto bail; + } + + status =ocfs2_info_scan_bitmap (gb_inode, gb_dinode, &req_ffg, cl); +if (status) + goto bail; + +if (req_ffg.ir_ffg.ir_free_chunks_real) + req_ffg.ir_ffg.ir_avg = (req_ffg.ir_ffg.ir_avg / + req_ffg.ir_ffg.ir_free_chunks_real); + + req_ffg.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_freefrag __user *)user_req, + &req_ffg, +sizeof (struct ocfs2_info_freefrag ))) { + status = -EFAULT ; + goto bail; + } + +bail: +if (unlock) +ocfs2_inode_unlock (gb_inode,0 ); + +bail_mutex_unlock: +if (gb_inode) +mutex_unlock (&gb_inode->i_mutex); + +iput (gb_inode); +brelse (bh); + +mlog_exit (status); +return status; +} + +int ocfs2_info_scan_inode_alloc (struct inode *inode_alloc, +struct ocfs2_info_freeinode *fi, +__u32 slotnum, +int flags) +{ +int status =0 , unlock =0 ; + +struct buffer_head *bh =NULL ; +struct ocfs2_dinode *dinode_alloc =NULL ; + +mutex_lock (&inode_alloc->i_mutex); + +if (!(flags &OCFS2_INFO_FL_NON_COHERENT )) { + status =ocfs2_inode_lock (inode_alloc, &bh,0 ); +if (status <0 ) { +mlog_errno (status); + goto bail_mutex_unlock; + } + unlock =1 ; + + }else { + + status =ocfs2_read_inode_block (inode_alloc, &bh); +if (status <0 ) { +mlog_errno (status); + goto bail; + } + } + + dinode_alloc = (struct ocfs2_dinode *)bh->b_data; + + fi->ir_fi_stat[slotnum].ir_total = +le32_to_cpu (dinode_alloc->id1.bitmap1.i_total); + fi->ir_fi_stat[slotnum].ir_free = +le32_to_cpu (dinode_alloc->id1.bitmap1.i_total) - +le32_to_cpu (dinode_alloc->id1.bitmap1.i_used); +bail: +if (unlock) +ocfs2_inode_unlock (inode_alloc,0 ); + +bail_mutex_unlock: +mutex_unlock (&inode_alloc->i_mutex); + +iput (inode_alloc); +brelse (bh); + +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_freeinode (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 , i; + +struct ocfs2_info_freeinode req_fi; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); +struct inode *inode_alloc =NULL ; + + +if (copy_from_user (&req_fi, user_req, +sizeof (struct ocfs2_info_freeinode ))) { + status = -EFAULT ; + goto bail; + } + + req_fi.ir_slotnum = osb->max_slots; + +for (i =0 ; i < req_fi.ir_slotnum; i++) { + inode_alloc = +ocfs2_get_system_file_inode (osb, +INODE_ALLOC_SYSTEM_INODE , + i); +if (!inode_alloc) { +mlog (ML_ERROR ,"unable to get alloc inode in slot %u\n" , + (u32 )i); + status = -EIO ; + goto bail; + } + + status =ocfs2_info_scan_inode_alloc (inode_alloc, &req_fi, i, + req_fi.ir_request.ir_flags); +if (status <0 ) + goto bail; + } + + req_fi.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_freeinode __user *)user_req, + &req_fi, +sizeof (struct ocfs2_info_freeinode ))) { + status = -EFAULT ; + } + +bail: + +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_unknown (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_request req; + +if (copy_from_user (&req, user_req,sizeof (struct ocfs2_info_request ))) { + status = -EFAULT ; + goto bail; + } + + req.ir_flags &= ~OCFS2_INFO_FL_FILLED ; + +if (copy_to_user (user_req, &req, +sizeof (struct ocfs2_info_request ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_request (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_request req; + +if (copy_from_user (&req, user_req,sizeof (struct ocfs2_info_request ))) { + status = -EFAULT ; + goto bail; + } + +if (req.ir_magic !=OCFS2_INFO_MAGIC ) { + status = -EINVAL ; + goto bail; + } + +switch (req.ir_code) { +case OCFS2_INFO_BLOCKSIZE : +if (req.ir_size !=sizeof (struct ocfs2_info_blocksize )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_blocksize (inode, user_req); +break ; +case OCFS2_INFO_CLUSTERSIZE : +if (req.ir_size !=sizeof (struct ocfs2_info_clustersize )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_clustersize (inode, user_req); +break ; +case OCFS2_INFO_SLOTNUM : +if (req.ir_size !=sizeof (struct ocfs2_info_slotnum )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_slotnum (inode, user_req); +break ; +case OCFS2_INFO_LABEL : +if (req.ir_size !=sizeof (struct ocfs2_info_label )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_label (inode, user_req); +break ; +case OCFS2_INFO_UUID : +if (req.ir_size !=sizeof (struct ocfs2_info_uuid )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_uuid (inode, user_req); +break ; +case OCFS2_INFO_FS_FEATURES : +if (req.ir_size !=sizeof (struct ocfs2_info_fs_features )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_fs_features (inode, user_req); +break ; +case OCFS2_INFO_FREEFRAG : +if (req.ir_size !=sizeof (struct ocfs2_info_freefrag )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_freefrag (inode, user_req); +break ; +case OCFS2_INFO_FREEINODE :
fs/ocfs2/ioctl.c bail: · line 727
Quoted 10 lines
fs/ocfs2/ioctl.c +10
-0+if (req.ir_size !=sizeof (struct ocfs2_info_freeinode )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_freeinode (inode, user_req); +break ; +default : + status =ocfs2_info_handle_unknown (inode, user_req); +break ; + }
For the first round, can we remove the freefrag and freeinode. That needs a closer look. I would like the scalars entered first.
Quoted 97 lines
fs/ocfs2/ioctl.c +47
-0+ +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle (struct inode *inode,struct ocfs2_info *info, +int compat_flag) +{ +int i, status =0 ; +u64 req_addr; +struct ocfs2_info_request __user *reqp; + +if ((info->info_count >OCFS2_INFO_MAX_REQUEST ) || + (!info->info_requests)) { + status = -EINVAL ; + goto bail; + } + +for (i =0 ; i < info->info_count; i++) { + status = -EFAULT ; +if (compat_flag) { +if (get_user (req_addr, + (u64 __user *)compat_ptr (info->info_requests) + i)) + goto bail; + }else { +if (get_user (req_addr, + (u64 __user *)(info->info_requests) + i)) + goto bail; + } + + reqp = (struct ocfs2_info_request *)req_addr; +if (!reqp) { + status = -EINVAL ; + goto bail; + } + + status =ocfs2_info_handle_request (inode, reqp); +if (status) + goto bail; + } + +bail: +mlog_exit (status); +return status; +} +long
ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){fs/ocfs2/ioctl.c +14
-0struct inode *inode = filp->f_path.dentry->d_inode;@@ -120,6 +783,7 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)struct reflink_arguments args;const char *old_path, *new_path;bool preserve; +struct ocfs2_info info;switch (cmd) {case OCFS2_IOC_GETFLAGS :@@ -174,6 +838,12 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) preserve = (args.preserve !=0 );return ocfs2_reflink_ioctl (inode, old_path, new_path, preserve); +case OCFS2_IOC_INFO : +if (copy_from_user (&info, (struct ocfs2_info __user *)arg, +sizeof (struct ocfs2_info ))) +return -EFAULT ; + +return ocfs2_info_handle (inode, &info,0 );default :return -ENOTTY ; }@@ -185,6 +855,7 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)bool preserve;struct reflink_arguments args;struct inode *inode = file->f_path.dentry->d_inode; +struct ocfs2_info info;switch (cmd) {case OCFS2_IOC32_GETFLAGS :@@ -209,6 +880,12 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)return ocfs2_reflink_ioctl (inode,compat_ptr (args.old_path),compat_ptr (args.new_path), preserve); +case OCFS2_IOC_INFO : +if (copy_from_user (&info, (struct ocfs2_info __user *)arg, +sizeof (struct ocfs2_info ))) +return -EFAULT ; + +return ocfs2_info_handle (inode, &info,1 );default :return -ENOIOCTLCMD ; }fs/ocfs2/ocfs2_ioctl.h +0
-0
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 83
Quoted 8 lines
fs/ocfs2/ocfs2_ioctl.h +4
-0@@ -76,4 +76,121 @@ struct reflink_arguments { };#define OCFS2_IOC_REFLINK _IOW('o', 4, struct reflink_arguments) +/* Following definitions dedicated for ocfs2_info_request ioctls. */ + +#define OCFS2_INFO_VOL_UUID_LEN (16) +#define OCFS2_INFO_MAX_VOL_LABEL_LEN (64)
Why not use the existing #defines in ocfs2_fs.h
Quoted 9 lines
fs/ocfs2/ocfs2_ioctl.h +7
-0+#define OCFS2_INFO_VOL_UUIDSTR_LEN (OCFS2_INFO_VOL_UUID_LEN * 2 + 1) +#define OCFS2_INFO_MAX_SLOTS (255) +#define OCFS2_INFO_MAX_HIST (32) + +#define OCFS2_INFO_MAX_REQUEST (50) + +/* Magic number of all requests */
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 99
Quoted 10 lines
fs/ocfs2/ocfs2_ioctl.h +10
-0+#define OCFS2_INFO_MAGIC (0x4F32494E) + +/* +* Always try to separate info request into small pieces to +* guarantee the backward&forward compatibility. +*/ + +struct ocfs2_info { +__u64 info_requests;/* Array of __u64 pointers to requests */ +__u32 info_count;/* Number of requests in info_requests */
oi_requests, oi_count
Quoted 4 lines
fs/ocfs2/ocfs2_ioctl.h +3
-0+}; + +struct ocfs2_info_request {
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 112
Quoted 10 lines
fs/ocfs2/ocfs2_ioctl.h +10
-0+/*00*/ __u32 ir_magic;/* Magic number */ +__u32 ir_code;/* Info request code */ +__u32 ir_size;/* Size of request */ +__u32 ir_flags;/* Request flags */ +/*10*/ /* Request specific fields */ +}; + +struct ocfs2_info_clustersize { +struct ocfs2_info_request ir_request; +__u32 ir_clustersize;
ic_req, ic_clustersize
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 117
Quoted 6 lines
fs/ocfs2/ocfs2_ioctl.h +5
-0+}; + +struct ocfs2_info_blocksize { +struct ocfs2_info_request ir_request; +__u32 ir_blocksize;
ib_req, ib_blocksize
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 122
Quoted 6 lines
fs/ocfs2/ocfs2_ioctl.h +5
-0+}; + +struct ocfs2_info_slotnum { +struct ocfs2_info_request ir_request; +__u16 ir_slotnum;
ocfs2_info_maxslotsis_req, is_max_slots
(slotnum could be later used to query the slot use by that node)
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 128
Quoted 7 lines
fs/ocfs2/ocfs2_ioctl.h +6
-0+}; + +struct ocfs2_info_label { +struct ocfs2_info_request ir_request; +__u8 ir_label[OCFS2_INFO_MAX_VOL_LABEL_LEN ]; +};
il_req, il_label
You get the drift.
Quoted 42 lines
fs/ocfs2/ocfs2_ioctl.h +41
-0+ +struct ocfs2_info_uuid { +struct ocfs2_info_request ir_request; +__u8 ir_uuid_str[OCFS2_INFO_VOL_UUIDSTR_LEN ]; +}; + +struct ocfs2_info_fs_features { +struct ocfs2_info_request ir_request; +__u32 ir_compat_features; +__u32 ir_incompat_features; +__u32 ir_ro_compat_features; +}; + +struct ocfs2_info_freefrag { +struct ocfs2_info_request ir_request; +__u32 ir_chunksize;/* chunksize in clusters(in) */ +struct ocfs2_info_freefrag_stats {/* (out) */ +__u32 ir_clusters; +__u32 ir_free_clusters; +__u32 ir_free_chunks; +__u32 ir_free_chunks_real; +__u32 ir_min;/* Minimum free chunksize in clusters */ +__u32 ir_max; +__u32 ir_avg; +struct ocfs2_info_free_chunk_list { +__u32 ir_fc_chunks[OCFS2_INFO_MAX_HIST ]; +__u32 ir_fc_clusters[OCFS2_INFO_MAX_HIST ]; + } ir_fc_hist; + } ir_ffg; +}; + +struct ocfs2_info_freeinode { +struct ocfs2_info_request ir_request; +__u32 ir_slotnum;/* out */ +struct ocfs2_info_local_fi { +__u64 ir_total; +__u64 ir_free; + } ir_fi_stat[OCFS2_INFO_MAX_SLOTS ]; +}; + +/* Codes for ocfs2_info_request */
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 179
Quoted 10 lines
fs/ocfs2/ocfs2_ioctl.h +10
-0+enum ocfs2_info_type { +OCFS2_INFO_CLUSTERSIZE =1 , +OCFS2_INFO_BLOCKSIZE , +OCFS2_INFO_SLOTNUM , +OCFS2_INFO_LABEL , +OCFS2_INFO_UUID , +OCFS2_INFO_FS_FEATURES , +OCFS2_INFO_FREEFRAG , +OCFS2_INFO_FREEINODE , +NUM_OCFS2_INFO_TYPE
OCFS2_INFO_NUM_TYPES
Quoted 18 lines
fs/ocfs2/ocfs2_ioctl.h +16
-0+}; + +/* Flags for struct ocfs2_info_request */ +/* Filled by the caller */ +#define OCFS2_INFO_FL_NON_COHERENT (0x00000001)/* Cluster coherency not +required. This is a hint. +It is up to ocfs2 whether +the request can be fulfilled +without locking. */ +/* Filled by ocfs2 */ +#define OCFS2_INFO_FL_FILLED (0x80000000)/* Filesystem understood +this request and +filled in the answer */ + +#define OCFS2_IOC_INFO _IOR('o', 5, struct ocfs2_info) +#endif /* OCFS2_IOCTL_H */
PATCH 2/2 Ocfs2: Add new OCFS2_IOC_INFO ioctl for ocfs2 v6.
So just to expand on the style issue. My intention here is not to be a p-i-t-a.
Just want the code to be readable.
By making those few changes, the boiler plate code of from_user and to_user will look like this.
if (copy_from_user(&oic, req, sizeof(structocfs2_info_clustersize)))
goto bail;
if (copy_to_user((struct ocfs2_info_clustersize __user *)req, &oic,
sizeof(struct ocfs2_info_clustersize)))
goto bail;Or, you could take it a step further and make some macros. Keep these macros in close proximity to these functions.
#define _ocfs2_from_user(a, b) \
copy_from_user(&(a), (a), typeof(a))#define _ocfs2_to_user(a, b) \
copy_to_user((typeof(a) __user *)b, &(a), sizeof(a))
if (_ocfs2_from_user(oic, req))
goto bail;
if (_ocfs2_to_user(oic, req))
goto bail;Sunil
Quoted 1,006 lines · Sunil Mushran
I like the overall flow. I just have some comments on style.
Also, would prefer if you drop freeinode and freefrag for the first checkin. That not only needs a closer look.
For the next drop, just have this patch. The first one is in mainline.
Thanks
Quoted 80 lines · Tristan Ye
The reason why we need this ioctl is to offer the none-privileged end-user a possibility to get filesys info gathering.
We use
OCFS2_IOC_INFOto manipulate the new ioctl, userspace passes a structure to kernel containing an array of request pointers and request count, such as,* From userspace:
struct ocfs2_info_blocksize brq = { .ir_request = { .ir_magic = OCFS2_INFO_MAGIC, .ir_code = OCFS2_INFO_BLOCKSIZE, ... } ... }struct ocfs2_info_clustersize crq = { ... }
uint64_treqs[2] = {(unsigned long)&brq,(unsigned long)&crq};struct
ocfs2_infoinfo = {
.ir_requests = reqs,
.ir_count = 2,
}ret =
ioctl(fd, OCFS2_IOC_INFO, &info);* In kernel:
Get the request pointers from *info*, then handle each request one bye one.
Idea here is to make the spearated request small enough to guarantee a better backward&forward compatibility since a small piece of request would be less likely to be broken if filesys on raw disk get changed.
Currently, following 8 ioctls get implemented per the requirement from userspace tool o2info, and I believe it will grow over time:-)
OCFS2_INFO_CLUSTERSIZE
OCFS2_INFO_BLOCKSIZE
OCFS2_INFO_SLOTNUM
OCFS2_INFO_LABEL
OCFS2_INFO_UUID
OCFS2_INFO_FS_FEATURES
OCFS2_INFO_FREEFRAG
OCFS2_INFO_FREEINODEThis ioctl is only specific to OCFS2.
Signed-off-by Tristan Ye <[email protected]>Signed-off-by Joel Becker <[email protected]>--- fs/ocfs2/ioctl.c | 677 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/ocfs2_ioctl.h | 117 +++++++++ 2 files changed, 794 insertions(+), 0 deletions(-)fs/ocfs2/ioctl.c +5
-0@@ -23,8 +23,13 @@#include "ioctl.h" #include "resize.h" #include "refcounttree.h" +#include "sysfile.h" +#include "buffer_head_io.h" +#include "suballoc.h" +#include <linux/ext2_fs.h> +#include <linux/compat.h> static int ocfs2_get_inode_attr (struct inode *inode,unsigned *flags) {fs/ocfs2/ioctl.c bail: · line 123
Quoted 10 lines
fs/ocfs2/ioctl.c +5
-0@@ -109,6 +114,664 @@ bail:return status; } +int ocfs2_info_handle_blocksize (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_blocksize req_bs;
req_bsis a mouthful. How about "oib"? For the next function it could be "oic"? We do this everywhere. eg, osb, di, et, el, etc.Quoted 11 lines
fs/ocfs2/ioctl.c +10
-0+ +if (copy_from_user (&req_bs, user_req, +sizeof (struct ocfs2_info_blocksize ))) { + status = -EFAULT ; + goto bail; + } + + req_bs.ir_blocksize = inode->i_sb->s_blocksize; + req_bs.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; +fs/ocfs2/ioctl.c bail:
Quoted 10 lines
fs/ocfs2/ioctl.c +9
-0+if (copy_to_user ((struct ocfs2_info_blocksize __user *)user_req, + &req_bs, +sizeof (struct ocfs2_info_blocksize ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status);Don't have a exit without an entry. But I think we can do without the entry/exit mlogs in these ioctls.
fs/ocfs2/ioctl.c bail: · line 147
Quoted 9 lines
fs/ocfs2/ioctl.c +7
-0+return status; +} + +int ocfs2_info_handle_clustersize (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ;Or, you could set it to
-EFAULThere and set it to 0 just before bail.Quoted 572 lines
fs/ocfs2/ioctl.c +570
-0+struct ocfs2_info_clustersize req_cs; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_cs, user_req, +sizeof (struct ocfs2_info_clustersize ))) { + status = -EFAULT ; + goto bail; + } + + req_cs.ir_clustersize = osb->s_clustersize; + req_cs.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_clustersize __user *)user_req, + &req_cs, +sizeof (struct ocfs2_info_clustersize ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_slotnum (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_slotnum req_sn; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_sn, user_req, +sizeof (struct ocfs2_info_slotnum ))) { + status = -EFAULT ; + goto bail; + } + + req_sn.ir_slotnum = osb->max_slots; + req_sn.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_slotnum __user *)user_req, + &req_sn, +sizeof (struct ocfs2_info_slotnum ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_label (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_label req_lb; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_lb, user_req, +sizeof (struct ocfs2_info_label ))) { + status = -EFAULT ; + goto bail; + } + +memcpy (req_lb.ir_label, osb->vol_label,OCFS2_MAX_VOL_LABEL_LEN ); + req_lb.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_label __user *)user_req, + &req_lb, +sizeof (struct ocfs2_info_label ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_uuid (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_uuid req_uuid; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_uuid, user_req, +sizeof (struct ocfs2_info_uuid ))) { + status = -EFAULT ; + goto bail; + } + +memcpy (req_uuid.ir_uuid_str, osb->uuid_str,OCFS2_INFO_VOL_UUIDSTR_LEN ); + req_uuid.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_uuid __user *)user_req, + &req_uuid, +sizeof (struct ocfs2_info_uuid ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_fs_features (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_fs_features req_fs; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_fs, user_req, +sizeof (struct ocfs2_info_fs_features ))) { + status = -EFAULT ; + goto bail; + } + + req_fs.ir_compat_features = osb->s_feature_compat; + req_fs.ir_incompat_features = osb->s_feature_incompat; + req_fs.ir_ro_compat_features = osb->s_feature_ro_compat; + req_fs.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_fs_features __user *)user_req, + &req_fs, +sizeof (struct ocfs2_info_fs_features ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +void ocfs2_info_update_ffg (struct ocfs2_info_freefrag *ffg, +unsigned int chunksize) +{ +int index; + + index =__ilog2_u32 (chunksize); +if (index >=OCFS2_INFO_MAX_HIST ) + index =OCFS2_INFO_MAX_HIST -1 ; + + ffg->ir_ffg.ir_fc_hist.ir_fc_chunks[index]++; + ffg->ir_ffg.ir_fc_hist.ir_fc_clusters[index] += chunksize; + +if (chunksize > ffg->ir_ffg.ir_max) + ffg->ir_ffg.ir_max = chunksize; + +if (chunksize < ffg->ir_ffg.ir_min) + ffg->ir_ffg.ir_min = chunksize; + + ffg->ir_ffg.ir_avg += chunksize; + ffg->ir_ffg.ir_free_chunks_real++; +} + +int ocfs2_info_scan_chain (struct inode *gb_inode, +struct ocfs2_dinode *gb_dinode, +struct ocfs2_info_freefrag *ffg, +struct ocfs2_chain_rec *rec, +unsigned int chunks_in_group) +{ +int status =0 , used; +u64 blkno; + +struct buffer_head *bh =NULL ; +struct ocfs2_group_desc *bg =NULL ; + +unsigned int max_bits, num_clusters; +unsigned int offset =0 , cluster, chunk; +unsigned int chunk_free, last_chunksize =0 ; + +if (!le32_to_cpu (rec->c_free)) + goto bail; + +do { +if (!bg) + blkno =le64_to_cpu (rec->c_blkno); +else + blkno =le64_to_cpu (bg->bg_next_group); + +if (bh) { +brelse (bh); + bh =NULL ; + } + + status =ocfs2_read_group_descriptor (gb_inode, gb_dinode, + blkno, &bh); +if (status <0 ) { +mlog (ML_ERROR ,"Can't read the group descriptor # " +"%llu from device." , (unsigned long long )blkno); + status = -EIO ; + goto bail; + } + + bg = (struct ocfs2_group_desc *)bh->b_data; + +if (!le16_to_cpu (bg->bg_free_bits_count)) +continue ; + + max_bits =le16_to_cpu (bg->bg_bits); + offset =0 ; + +for (chunk =0 ; chunk < chunks_in_group; chunk++) { + +/* Last chunk may be not a entire one */ +if ((offset + ffg->ir_chunksize) > max_bits) + num_clusters = max_bits - offset; +else + num_clusters = ffg->ir_chunksize; + + chunk_free =0 ; +for (cluster =0 ; cluster < num_clusters; cluster++) { + used =ocfs2_test_bit (offset, + (unsigned long *)bg->bg_bitmap); +if (!used) { + last_chunksize++; + chunk_free++; + } + +if (used && (last_chunksize)) { +ocfs2_info_update_ffg (ffg, + last_chunksize); + last_chunksize =0 ; + } + + offset++; + } + +if (chunk_free == ffg->ir_chunksize) + ffg->ir_ffg.ir_free_chunks++; + } + +/* we need to update the info of last free chunk */ +if (last_chunksize) +ocfs2_info_update_ffg (ffg, last_chunksize); + + }while (le64_to_cpu (bg->bg_next_group)); + +bail: +brelse (bh); + +mlog_exit (status); +return status; +} + +int ocfs2_info_scan_bitmap (struct inode *gb_inode, +struct ocfs2_dinode *gb_dinode, +struct ocfs2_info_freefrag *ffg, +struct ocfs2_chain_list *cl) +{ +int status =0 , i; +unsigned int chunks_in_group; +struct ocfs2_chain_rec *rec =NULL ; + + chunks_in_group =le16_to_cpu (cl->cl_cpg) / ffg->ir_chunksize +1 ; + +for (i =0 ; i <le16_to_cpu (cl->cl_next_free_rec); i++) { + + rec = &(cl->cl_recs[i]); + status =ocfs2_info_scan_chain (gb_inode, gb_dinode, + ffg, rec, chunks_in_group); +if (status) + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_freefrag (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 , unlock =0 ; + +struct ocfs2_info_freefrag req_ffg; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); +struct buffer_head *bh =NULL ; +struct inode *gb_inode =NULL ; +struct ocfs2_dinode *gb_dinode =NULL ; +struct ocfs2_chain_list *cl =NULL ; + +if (copy_from_user (&req_ffg, user_req, +sizeof (struct ocfs2_info_freefrag ))) { + status = -EFAULT ; + goto bail; + } + +/* +* chunksize from userspace should be power of 2, +*/ +if ((req_ffg.ir_chunksize & (req_ffg.ir_chunksize -1 )) || + (!req_ffg.ir_chunksize)) { + status = -EINVAL ; + goto bail; + } + +memset (&req_ffg.ir_ffg,0 ,sizeof (struct ocfs2_info_freefrag_stats )); + req_ffg.ir_ffg.ir_min = ~0U ; + + gb_inode =ocfs2_get_system_file_inode (osb, +GLOBAL_BITMAP_SYSTEM_INODE , +OCFS2_INVALID_SLOT ); +if (!gb_inode) { +mlog (ML_ERROR ,"failed to get bitmap inode\n" ); + status = -EIO ; + goto bail; + } + +mutex_lock (&gb_inode->i_mutex); + +if (!(req_ffg.ir_request.ir_flags &OCFS2_INFO_FL_NON_COHERENT )) { + status =ocfs2_inode_lock (gb_inode, &bh,0 ); +if (status <0 ) { +mlog_errno (status); + goto bail_mutex_unlock; + } + unlock =1 ; + + }else { + status =ocfs2_read_inode_block (gb_inode, &bh); +if (status <0 ) { +mlog_errno (status); + goto bail; + } + } + + gb_dinode = (struct ocfs2_dinode *)bh->b_data; + + req_ffg.ir_ffg.ir_clusters = +le32_to_cpu (gb_dinode->id1.bitmap1.i_total); + req_ffg.ir_ffg.ir_free_clusters = req_ffg.ir_ffg.ir_clusters - +le32_to_cpu (gb_dinode->id1.bitmap1.i_used); + + cl = &(gb_dinode->id2.i_chain); + +/* Chunksize from userspace should be less than clusters in a group */ +if (req_ffg.ir_chunksize >le16_to_cpu (cl->cl_cpg)) { + status = -EINVAL ; + goto bail; + } + + status =ocfs2_info_scan_bitmap (gb_inode, gb_dinode, &req_ffg, cl); +if (status) + goto bail; + +if (req_ffg.ir_ffg.ir_free_chunks_real) + req_ffg.ir_ffg.ir_avg = (req_ffg.ir_ffg.ir_avg / + req_ffg.ir_ffg.ir_free_chunks_real); + + req_ffg.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_freefrag __user *)user_req, + &req_ffg, +sizeof (struct ocfs2_info_freefrag ))) { + status = -EFAULT ; + goto bail; + } + +bail: +if (unlock) +ocfs2_inode_unlock (gb_inode,0 ); + +bail_mutex_unlock: +if (gb_inode) +mutex_unlock (&gb_inode->i_mutex); + +iput (gb_inode); +brelse (bh); + +mlog_exit (status); +return status; +} + +int ocfs2_info_scan_inode_alloc (struct inode *inode_alloc, +struct ocfs2_info_freeinode *fi, +__u32 slotnum, +int flags) +{ +int status =0 , unlock =0 ; + +struct buffer_head *bh =NULL ; +struct ocfs2_dinode *dinode_alloc =NULL ; + +mutex_lock (&inode_alloc->i_mutex); + +if (!(flags &OCFS2_INFO_FL_NON_COHERENT )) { + status =ocfs2_inode_lock (inode_alloc, &bh,0 ); +if (status <0 ) { +mlog_errno (status); + goto bail_mutex_unlock; + } + unlock =1 ; + + }else { + + status =ocfs2_read_inode_block (inode_alloc, &bh); +if (status <0 ) { +mlog_errno (status); + goto bail; + } + } + + dinode_alloc = (struct ocfs2_dinode *)bh->b_data; + + fi->ir_fi_stat[slotnum].ir_total = +le32_to_cpu (dinode_alloc->id1.bitmap1.i_total); + fi->ir_fi_stat[slotnum].ir_free = +le32_to_cpu (dinode_alloc->id1.bitmap1.i_total) - +le32_to_cpu (dinode_alloc->id1.bitmap1.i_used); +bail: +if (unlock) +ocfs2_inode_unlock (inode_alloc,0 ); + +bail_mutex_unlock: +mutex_unlock (&inode_alloc->i_mutex); + +iput (inode_alloc); +brelse (bh); + +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_freeinode (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 , i; + +struct ocfs2_info_freeinode req_fi; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); +struct inode *inode_alloc =NULL ; + + +if (copy_from_user (&req_fi, user_req, +sizeof (struct ocfs2_info_freeinode ))) { + status = -EFAULT ; + goto bail; + } + + req_fi.ir_slotnum = osb->max_slots; + +for (i =0 ; i < req_fi.ir_slotnum; i++) { + inode_alloc = +ocfs2_get_system_file_inode (osb, +INODE_ALLOC_SYSTEM_INODE , + i); +if (!inode_alloc) { +mlog (ML_ERROR ,"unable to get alloc inode in slot %u\n" , + (u32 )i); + status = -EIO ; + goto bail; + } + + status =ocfs2_info_scan_inode_alloc (inode_alloc, &req_fi, i, + req_fi.ir_request.ir_flags); +if (status <0 ) + goto bail; + } + + req_fi.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_freeinode __user *)user_req, + &req_fi, +sizeof (struct ocfs2_info_freeinode ))) { + status = -EFAULT ; + } + +bail: + +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_unknown (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_request req; + +if (copy_from_user (&req, user_req,sizeof (struct ocfs2_info_request ))) { + status = -EFAULT ; + goto bail; + } + + req.ir_flags &= ~OCFS2_INFO_FL_FILLED ; + +if (copy_to_user (user_req, &req, +sizeof (struct ocfs2_info_request ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_request (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_request req; + +if (copy_from_user (&req, user_req,sizeof (struct ocfs2_info_request ))) { + status = -EFAULT ; + goto bail; + } + +if (req.ir_magic !=OCFS2_INFO_MAGIC ) { + status = -EINVAL ; + goto bail; + } + +switch (req.ir_code) { +case OCFS2_INFO_BLOCKSIZE : +if (req.ir_size !=sizeof (struct ocfs2_info_blocksize )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_blocksize (inode, user_req); +break ; +case OCFS2_INFO_CLUSTERSIZE : +if (req.ir_size !=sizeof (struct ocfs2_info_clustersize )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_clustersize (inode, user_req); +break ; +case OCFS2_INFO_SLOTNUM : +if (req.ir_size !=sizeof (struct ocfs2_info_slotnum )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_slotnum (inode, user_req); +break ; +case OCFS2_INFO_LABEL : +if (req.ir_size !=sizeof (struct ocfs2_info_label )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_label (inode, user_req); +break ; +case OCFS2_INFO_UUID : +if (req.ir_size !=sizeof (struct ocfs2_info_uuid )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_uuid (inode, user_req); +break ; +case OCFS2_INFO_FS_FEATURES : +if (req.ir_size !=sizeof (struct ocfs2_info_fs_features )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_fs_features (inode, user_req); +break ; +case OCFS2_INFO_FREEFRAG : +if (req.ir_size !=sizeof (struct ocfs2_info_freefrag )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_freefrag (inode, user_req); +break ; +case OCFS2_INFO_FREEINODE :fs/ocfs2/ioctl.c bail: · line 727
Quoted 10 lines
fs/ocfs2/ioctl.c +10
-0+if (req.ir_size !=sizeof (struct ocfs2_info_freeinode )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_freeinode (inode, user_req); +break ; +default : + status =ocfs2_info_handle_unknown (inode, user_req); +break ; + }For the first round, can we remove the freefrag and freeinode. That needs a closer look. I would like the scalars entered first.
Quoted 98 lines
fs/ocfs2/ioctl.c +47
-0+ +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle (struct inode *inode,struct ocfs2_info *info, +int compat_flag) +{ +int i, status =0 ; +u64 req_addr; +struct ocfs2_info_request __user *reqp; + +if ((info->info_count >OCFS2_INFO_MAX_REQUEST ) || + (!info->info_requests)) { + status = -EINVAL ; + goto bail; + } + +for (i =0 ; i < info->info_count; i++) { + status = -EFAULT ; +if (compat_flag) { +if (get_user (req_addr, + (u64 __user *)compat_ptr (info->info_requests) + i)) + goto bail; + }else { +if (get_user (req_addr, + (u64 __user *)(info->info_requests) + i)) + goto bail; + } + + reqp = (struct ocfs2_info_request *)req_addr; +if (!reqp) { + status = -EINVAL ; + goto bail; + } + + status =ocfs2_info_handle_request (inode, reqp); +if (status) + goto bail; + } + +bail: +mlog_exit (status); +return status; +} +long
ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){fs/ocfs2/ioctl.c +14
-0struct inode *inode = filp->f_path.dentry->d_inode;@@ -120,6 +783,7 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)struct reflink_arguments args;const char *old_path, *new_path;bool preserve; +struct ocfs2_info info;switch (cmd) {case OCFS2_IOC_GETFLAGS :@@ -174,6 +838,12 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) preserve = (args.preserve !=0 );return ocfs2_reflink_ioctl (inode, old_path, new_path, preserve); +case OCFS2_IOC_INFO : +if (copy_from_user (&info, (struct ocfs2_info __user *)arg, +sizeof (struct ocfs2_info ))) +return -EFAULT ; + +return ocfs2_info_handle (inode, &info,0 );default :return -ENOTTY ; }@@ -185,6 +855,7 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)bool preserve;struct reflink_arguments args;struct inode *inode = file->f_path.dentry->d_inode; +struct ocfs2_info info;switch (cmd) {case OCFS2_IOC32_GETFLAGS :@@ -209,6 +880,12 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)return ocfs2_reflink_ioctl (inode,compat_ptr (args.old_path),compat_ptr (args.new_path), preserve); +case OCFS2_IOC_INFO : +if (copy_from_user (&info, (struct ocfs2_info __user *)arg, +sizeof (struct ocfs2_info ))) +return -EFAULT ; + +return ocfs2_info_handle (inode, &info,1 );default :return -ENOIOCTLCMD ; }fs/ocfs2/ocfs2_ioctl.h +0
-0fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 83
Quoted 8 lines
fs/ocfs2/ocfs2_ioctl.h +4
-0@@ -76,4 +76,121 @@ struct reflink_arguments { };#define OCFS2_IOC_REFLINK _IOW('o', 4, struct reflink_arguments) +/* Following definitions dedicated for ocfs2_info_request ioctls. */ + +#define OCFS2_INFO_VOL_UUID_LEN (16) +#define OCFS2_INFO_MAX_VOL_LABEL_LEN (64)Why not use the existing #defines in
ocfs2_fs.hQuoted 10 lines
fs/ocfs2/ocfs2_ioctl.h +7
-0+#define OCFS2_INFO_VOL_UUIDSTR_LEN (OCFS2_INFO_VOL_UUID_LEN * 2 + 1) +#define OCFS2_INFO_MAX_SLOTS (255) +#define OCFS2_INFO_MAX_HIST (32) + +#define OCFS2_INFO_MAX_REQUEST (50) + +/* Magic number of all requests */ fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 99
Quoted 10 lines
fs/ocfs2/ocfs2_ioctl.h +10
-0+#define OCFS2_INFO_MAGIC (0x4F32494E) + +/* +* Always try to separate info request into small pieces to +* guarantee the backward&forward compatibility. +*/ + +struct ocfs2_info { +__u64 info_requests;/* Array of __u64 pointers to requests */ +__u32 info_count;/* Number of requests in info_requests */
oi_requests,oi_countQuoted 5 lines
fs/ocfs2/ocfs2_ioctl.h +3
-0+}; + +struct ocfs2_info_request {fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 112
Quoted 10 lines
fs/ocfs2/ocfs2_ioctl.h +10
-0+/*00*/ __u32 ir_magic;/* Magic number */ +__u32 ir_code;/* Info request code */ +__u32 ir_size;/* Size of request */ +__u32 ir_flags;/* Request flags */ +/*10*/ /* Request specific fields */ +}; + +struct ocfs2_info_clustersize { +struct ocfs2_info_request ir_request; +__u32 ir_clustersize;
ic_req,ic_clustersizefs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 117
Quoted 7 lines
fs/ocfs2/ocfs2_ioctl.h +5
-0+}; + +struct ocfs2_info_blocksize { +struct ocfs2_info_request ir_request; +__u32 ir_blocksize;
ib_req,ib_blocksizefs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 122
Quoted 7 lines
fs/ocfs2/ocfs2_ioctl.h +5
-0+}; + +struct ocfs2_info_slotnum { +struct ocfs2_info_request ir_request; +__u16 ir_slotnum;
ocfs2_info_maxslotsis_req,is_max_slots(slotnum could be later used to query the slot use by that node)
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 128
Quoted 8 lines
fs/ocfs2/ocfs2_ioctl.h +6
-0+}; + +struct ocfs2_info_label { +struct ocfs2_info_request ir_request; +__u8 ir_label[OCFS2_INFO_MAX_VOL_LABEL_LEN ]; +};
il_req,il_labelYou get the drift.
Quoted 43 lines
fs/ocfs2/ocfs2_ioctl.h +41
-0+ +struct ocfs2_info_uuid { +struct ocfs2_info_request ir_request; +__u8 ir_uuid_str[OCFS2_INFO_VOL_UUIDSTR_LEN ]; +}; + +struct ocfs2_info_fs_features { +struct ocfs2_info_request ir_request; +__u32 ir_compat_features; +__u32 ir_incompat_features; +__u32 ir_ro_compat_features; +}; + +struct ocfs2_info_freefrag { +struct ocfs2_info_request ir_request; +__u32 ir_chunksize;/* chunksize in clusters(in) */ +struct ocfs2_info_freefrag_stats {/* (out) */ +__u32 ir_clusters; +__u32 ir_free_clusters; +__u32 ir_free_chunks; +__u32 ir_free_chunks_real; +__u32 ir_min;/* Minimum free chunksize in clusters */ +__u32 ir_max; +__u32 ir_avg; +struct ocfs2_info_free_chunk_list { +__u32 ir_fc_chunks[OCFS2_INFO_MAX_HIST ]; +__u32 ir_fc_clusters[OCFS2_INFO_MAX_HIST ]; + } ir_fc_hist; + } ir_ffg; +}; + +struct ocfs2_info_freeinode { +struct ocfs2_info_request ir_request; +__u32 ir_slotnum;/* out */ +struct ocfs2_info_local_fi { +__u64 ir_total; +__u64 ir_free; + } ir_fi_stat[OCFS2_INFO_MAX_SLOTS ]; +}; + +/* Codes for ocfs2_info_request */ fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 179
Quoted 10 lines
fs/ocfs2/ocfs2_ioctl.h +10
-0+enum ocfs2_info_type { +OCFS2_INFO_CLUSTERSIZE =1 , +OCFS2_INFO_BLOCKSIZE , +OCFS2_INFO_SLOTNUM , +OCFS2_INFO_LABEL , +OCFS2_INFO_UUID , +OCFS2_INFO_FS_FEATURES , +OCFS2_INFO_FREEFRAG , +OCFS2_INFO_FREEINODE , +NUM_OCFS2_INFO_TYPE
OCFS2_INFO_NUM_TYPESQuoted 9 lines
fs/ocfs2/ocfs2_ioctl.h +7
-0+}; + +/* Flags for struct ocfs2_info_request */ +/* Filled by the caller */ +#define OCFS2_INFO_FL_NON_COHERENT (0x00000001)/* Cluster coherency not +required. This is a hint. +It is up to ocfs2 whether fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 196
Quoted 10 lines
fs/ocfs2/ocfs2_ioctl.h +9
-0+the request can be fulfilled +without locking. */ +/* Filled by ocfs2 */ +#define OCFS2_INFO_FL_FILLED (0x80000000)/* Filesystem understood +this request and +filled in the answer */ + +#define OCFS2_IOC_INFO _IOR('o', 5, struct ocfs2_info) +#endif /* OCFS2_IOCTL_H */ _______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com
http://oss.oracle.com/mailman/listinfo/ocfs2-devel
PATCH 2/2 Ocfs2: Add new OCFS2_IOC_INFO ioctl for ocfs2 v6.
Quoted 6 lines · Sunil Mushran
Or, you could take it a step further and make some macros. Keep these macros in close proximity to these functions.
#define _ocfs2_from_user(a, b) \ copy_from_user(&(a), (a), typeof(a))
Quoted 8 lines
#define _ocfs2_to_user(a, b) \
copy_to_user((typeof(a) __user *)b, &(a), sizeof(a))
if (_ocfs2_from_user(oic, req))
goto bail;
if (_ocfs2_to_user(oic, req))
goto bail; Give them a more specific name; no one should thing they are
generic c-t-u functions. ocfs2-info-to-user? bonus if they handle the info types automagically.
Joel
Signature · 10 lines
"Born under a bad sign. I been down since I began to crawl. If it wasn't for bad luck, I wouldn't have no luck at all." Joel Becker Principal Software Developer Oracle E-mail: joel.becker at oracle.com Phone: (650) 506-8127
PATCH 2/2 Ocfs2: Add new OCFS2_IOC_INFO ioctl for ocfs2 v6.
Agreed. o2info_from_user() would be one suggestion.
Quoted 34 lines · Joel Becker
Quoted 6 lines · Sunil Mushran
Or, you could take it a step further and make some macros. Keep these macros in close proximity to these functions.
#define _ocfs2_from_user(a, b) \ copy_from_user(&(a), (a), typeof(a))Quoted 8 lines
#define _ocfs2_to_user(a, b) \ copy_to_user((typeof(a) __user *)b, &(a), sizeof(a)) if (_ocfs2_from_user(oic, req)) goto bail; if (_ocfs2_to_user(oic, req)) goto bail;Give them a more specific name; no one should thing they are
generic c-t-u functions. ocfs2-info-to-user? bonus if they handle the
info types automagically.Joel
Signature · 10 lines
"Born under a bad sign. I been down since I began to crawl. If it wasn't for bad luck, I wouldn't have no luck at all." Joel Becker Principal Software Developer Oracle E-mail: joel.becker at oracle.com Phone: (650) 506-8127
PATCH 2/2 Ocfs2: Add new OCFS2_IOC_INFO ioctl for ocfs2 v6.
In reply to Sunil MushranQuoted 8 lines · Sunil Mushran
So just to expand on the style issue. My intention here is not to be a p-i-t-a.
Just want the code to be readable.By making those few changes, the boiler plate code of
from_userandto_user
will look like this.
Quoted 8 lines
if (copy_from_user(&oic, req, sizeof(struct
ocfs2_info_clustersize)))
goto bail;if (copy_to_user((struct
ocfs2_info_clustersize__user*)req,
&oic,sizeof(struct ocfs2_info_clustersize))) goto bail;
Yes, sunil, you're right, 'oic' makes more sense.
Quoted 8 lines
Or, you could take it a step further and make some macros. Keep these macros in close proximity to these functions.
#define
_ocfs2_from_user(a, b)\copy_from_user(&(a), (a), typeof(a))
Quoted 8 lines
#define
_ocfs2_to_user(a, b)\copy_to_user((typeof(a) __user *)b, &(a), sizeof(a))if (_ocfs2_from_user(oic, req)) goto bail; if (_ocfs2_to_user(oic, req)) goto bail;
Thanks a lot for giving so many comments and conventions on naming issues, they're all helpful:)
Quoted 110 lines
Sunil
Quoted 105 lines · Sunil Mushran
I like the overall flow. I just have some comments on style.
Also, would prefer if you drop freeinode and freefrag for the first checkin. That not only needs a closer look.
For the next drop, just have this patch. The first one is in mainline.
Thanks
Quoted 82 lines · Tristan Ye
The reason why we need this ioctl is to offer the none-privileged end-user a possibility to get filesys info gathering.
We use
OCFS2_IOC_INFOto manipulate the new ioctl, userspace passes a structure to kernel containing an array of request pointers and request count, such as,* From userspace:
struct ocfs2_info_blocksize brq = { .ir_request = { .ir_magic = OCFS2_INFO_MAGIC, .ir_code = OCFS2_INFO_BLOCKSIZE, ... } ... }struct ocfs2_info_clustersize crq = { ... }
uint64_treqs[2] = {(unsigned long)&brq,(unsigned long)&crq};struct
ocfs2_infoinfo = {
.ir_requests = reqs,
.ir_count = 2,
}ret =
ioctl(fd, OCFS2_IOC_INFO, &info);* In kernel:
Get the request pointers from *info*, then handle each request one bye one.
Idea here is to make the spearated request small enough to guarantee a better backward&forward compatibility since a small piece of request would be less likely to be broken if filesys on raw disk get changed.
Currently, following 8 ioctls get implemented per the requirement from userspace tool o2info, and I believe it will grow over time:-)
OCFS2_INFO_CLUSTERSIZE
OCFS2_INFO_BLOCKSIZE
OCFS2_INFO_SLOTNUM
OCFS2_INFO_LABEL
OCFS2_INFO_UUID
OCFS2_INFO_FS_FEATURES
OCFS2_INFO_FREEFRAG
OCFS2_INFO_FREEINODEThis ioctl is only specific to OCFS2.
Signed-off-by Tristan Ye <[email protected]>Signed-off-by Joel Becker <[email protected]>--- fs/ocfs2/ioctl.c | 677 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/ocfs2_ioctl.h | 117 +++++++++ 2 files changed, 794 insertions(+), 0 deletions(-)fs/ocfs2/ioctl.c +5
-0@@ -23,8 +23,13 @@#include "ioctl.h" #include "resize.h" #include "refcounttree.h" +#include "sysfile.h" +#include "buffer_head_io.h" +#include "suballoc.h" +#include <linux/ext2_fs.h> +#include <linux/compat.h> static int ocfs2_get_inode_attr (struct inode *inode,unsigned *flags) {fs/ocfs2/ioctl.c bail: · line 122
Quoted 9 lines
fs/ocfs2/ioctl.c +5
-0@@ -109,6 +114,664 @@ bail:return status; } +int ocfs2_info_handle_blocksize (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_blocksize req_bs;
req_bsis a mouthful. How about "oib"? For the next function it could be "oic"? We do this everywhere. eg, osb, di, et, el, etc.
Agree, makes more sense than stuffs like 'req_bs', now I realised how obscure it looks when being compared to 'oic'...
Quoted 27 lines
Quoted 27 lines
Quoted 12 lines
fs/ocfs2/ioctl.c +10
-0+ +if (copy_from_user (&req_bs, user_req, +sizeof (struct ocfs2_info_blocksize ))) { + status = -EFAULT ; + goto bail; + } + + req_bs.ir_blocksize = inode->i_sb->s_blocksize; + req_bs.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; +fs/ocfs2/ioctl.c bail:
Quoted 10 lines
fs/ocfs2/ioctl.c +9
-0+if (copy_to_user ((struct ocfs2_info_blocksize __user *)user_req, + &req_bs, +sizeof (struct ocfs2_info_blocksize ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status);Don't have a exit without an entry. But I think we can do without the entry/exit mlogs in these ioctls.
Quoted 10 lines
Quoted 10 lines
fs/ocfs2/ioctl.c bail:
Quoted 8 lines
fs/ocfs2/ioctl.c +7
-0+return status; +} + +int ocfs2_info_handle_clustersize (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ;Or, you could set it to
-EFAULThere and set it to 0 just before bail.
All right.
Quoted 584 lines
Quoted 584 lines
Quoted 584 lines
fs/ocfs2/ioctl.c +94
-0+struct ocfs2_info_clustersize req_cs; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_cs, user_req, +sizeof (struct ocfs2_info_clustersize ))) { + status = -EFAULT ; + goto bail; + } + + req_cs.ir_clustersize = osb->s_clustersize; + req_cs.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_clustersize __user *)user_req, + &req_cs, +sizeof (struct ocfs2_info_clustersize ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_slotnum (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_slotnum req_sn; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_sn, user_req, +sizeof (struct ocfs2_info_slotnum ))) { + status = -EFAULT ; + goto bail; + } + + req_sn.ir_slotnum = osb->max_slots; + req_sn.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_slotnum __user *)user_req, + &req_sn, +sizeof (struct ocfs2_info_slotnum ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_label (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_label req_lb; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_lb, user_req, +sizeof (struct ocfs2_info_label ))) { + status = -EFAULT ; + goto bail; + } + +memcpy (req_lb.ir_label, osb->vol_label,OCFS2_MAX_VOL_LABEL_LEN ); + req_lb.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_label __user *)user_req, + &req_lb, +sizeof (struct ocfs2_info_label ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_uuid (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_uuid req_uuid; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_uuid, user_req, +sizeof (struct ocfs2_info_uuid ))) { + status = -EFAULT ; + goto bail; + } + + memcpy(req_uuid.ir_uuid_str, osb->uuid_str,
OCFS2_INFO_VOL_UUIDSTR_LEN);fs/ocfs2/ioctl.c +209
-0+ req_uuid.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_uuid __user *)user_req, + &req_uuid, +sizeof (struct ocfs2_info_uuid ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_fs_features (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_fs_features req_fs; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_fs, user_req, +sizeof (struct ocfs2_info_fs_features ))) { + status = -EFAULT ; + goto bail; + } + + req_fs.ir_compat_features = osb->s_feature_compat; + req_fs.ir_incompat_features = osb->s_feature_incompat; + req_fs.ir_ro_compat_features = osb->s_feature_ro_compat; + req_fs.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_fs_features __user *)user_req, + &req_fs, +sizeof (struct ocfs2_info_fs_features ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +void ocfs2_info_update_ffg (struct ocfs2_info_freefrag *ffg, +unsigned int chunksize) +{ +int index; + + index =__ilog2_u32 (chunksize); +if (index >=OCFS2_INFO_MAX_HIST ) + index =OCFS2_INFO_MAX_HIST -1 ; + + ffg->ir_ffg.ir_fc_hist.ir_fc_chunks[index]++; + ffg->ir_ffg.ir_fc_hist.ir_fc_clusters[index] += chunksize; + +if (chunksize > ffg->ir_ffg.ir_max) + ffg->ir_ffg.ir_max = chunksize; + +if (chunksize < ffg->ir_ffg.ir_min) + ffg->ir_ffg.ir_min = chunksize; + + ffg->ir_ffg.ir_avg += chunksize; + ffg->ir_ffg.ir_free_chunks_real++; +} + +int ocfs2_info_scan_chain (struct inode *gb_inode, +struct ocfs2_dinode *gb_dinode, +struct ocfs2_info_freefrag *ffg, +struct ocfs2_chain_rec *rec, +unsigned int chunks_in_group) +{ +int status =0 , used; +u64 blkno; + +struct buffer_head *bh =NULL ; +struct ocfs2_group_desc *bg =NULL ; + +unsigned int max_bits, num_clusters; +unsigned int offset =0 , cluster, chunk; +unsigned int chunk_free, last_chunksize =0 ; + +if (!le32_to_cpu (rec->c_free)) + goto bail; + +do { +if (!bg) + blkno =le64_to_cpu (rec->c_blkno); +else + blkno =le64_to_cpu (bg->bg_next_group); + +if (bh) { +brelse (bh); + bh =NULL ; + } + + status =ocfs2_read_group_descriptor (gb_inode, gb_dinode, + blkno, &bh); +if (status <0 ) { +mlog (ML_ERROR ,"Can't read the group descriptor # " +"%llu from device." , (unsigned long long )blkno); + status = -EIO ; + goto bail; + } + + bg = (struct ocfs2_group_desc *)bh->b_data; + +if (!le16_to_cpu (bg->bg_free_bits_count)) +continue ; + + max_bits =le16_to_cpu (bg->bg_bits); + offset =0 ; + +for (chunk =0 ; chunk < chunks_in_group; chunk++) { + +/* Last chunk may be not a entire one */ +if ((offset + ffg->ir_chunksize) > max_bits) + num_clusters = max_bits - offset; +else + num_clusters = ffg->ir_chunksize; + + chunk_free =0 ; +for (cluster =0 ; cluster < num_clusters; cluster++) { + used =ocfs2_test_bit (offset, + (unsigned long *)bg->bg_bitmap); +if (!used) { + last_chunksize++; + chunk_free++; + } + +if (used && (last_chunksize)) { +ocfs2_info_update_ffg (ffg, + last_chunksize); + last_chunksize =0 ; + } + + offset++; + } + +if (chunk_free == ffg->ir_chunksize) + ffg->ir_ffg.ir_free_chunks++; + } + +/* we need to update the info of last free chunk */ +if (last_chunksize) +ocfs2_info_update_ffg (ffg, last_chunksize); + + }while (le64_to_cpu (bg->bg_next_group)); + +bail: +brelse (bh); + +mlog_exit (status); +return status; +} + +int ocfs2_info_scan_bitmap (struct inode *gb_inode, +struct ocfs2_dinode *gb_dinode, +struct ocfs2_info_freefrag *ffg, +struct ocfs2_chain_list *cl) +{ +int status =0 , i; +unsigned int chunks_in_group; +struct ocfs2_chain_rec *rec =NULL ; + + chunks_in_group =le16_to_cpu (cl->cl_cpg) / ffg->ir_chunksize +1 ; + +for (i =0 ; i <le16_to_cpu (cl->cl_next_free_rec); i++) { + + rec = &(cl->cl_recs[i]); + status =ocfs2_info_scan_chain (gb_inode, gb_dinode, + ffg, rec, chunks_in_group); +if (status) + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_freefrag (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 , unlock =0 ; + +struct ocfs2_info_freefrag req_ffg; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); +struct buffer_head *bh =NULL ; +struct inode *gb_inode =NULL ; +struct ocfs2_dinode *gb_dinode =NULL ; +struct ocfs2_chain_list *cl =NULL ; + +if (copy_from_user (&req_ffg, user_req, +sizeof (struct ocfs2_info_freefrag ))) { + status = -EFAULT ; + goto bail; + } + +/* +* chunksize from userspace should be power of 2, +*/ +if ((req_ffg.ir_chunksize & (req_ffg.ir_chunksize -1 )) || + (!req_ffg.ir_chunksize)) { + status = -EINVAL ; + goto bail; + } + + memset(&req_ffg.ir_ffg, 0, sizeof(struct
ocfs2_info_freefrag_stats));fs/ocfs2/ioctl.c +39
-0+ req_ffg.ir_ffg.ir_min = ~0U ; + + gb_inode =ocfs2_get_system_file_inode (osb, +GLOBAL_BITMAP_SYSTEM_INODE , +OCFS2_INVALID_SLOT ); +if (!gb_inode) { +mlog (ML_ERROR ,"failed to get bitmap inode\n" ); + status = -EIO ; + goto bail; + } + +mutex_lock (&gb_inode->i_mutex); + +if (!(req_ffg.ir_request.ir_flags &OCFS2_INFO_FL_NON_COHERENT )) { + status =ocfs2_inode_lock (gb_inode, &bh,0 ); +if (status <0 ) { +mlog_errno (status); + goto bail_mutex_unlock; + } + unlock =1 ; + + }else { + status =ocfs2_read_inode_block (gb_inode, &bh); +if (status <0 ) { +mlog_errno (status); + goto bail; + } + } + + gb_dinode = (struct ocfs2_dinode *)bh->b_data; + + req_ffg.ir_ffg.ir_clusters = +le32_to_cpu (gb_dinode->id1.bitmap1.i_total); + req_ffg.ir_ffg.ir_free_clusters = req_ffg.ir_ffg.ir_clusters - +le32_to_cpu (gb_dinode->id1.bitmap1.i_used); + + cl = &(gb_dinode->id2.i_chain); + +/* Chunksize from userspace should be less than clusters in a group */
fs/ocfs2/ioctl.c +6
-0+if (req_ffg.ir_chunksize >le16_to_cpu (cl->cl_cpg)) { + status = -EINVAL ; + goto bail; + } + + status = ocfs2_info_scan_bitmap(gb_inode, gb_dinode, &req_ffg,cl);
fs/ocfs2/ioctl.c +138
-0+if (status) + goto bail; + +if (req_ffg.ir_ffg.ir_free_chunks_real) + req_ffg.ir_ffg.ir_avg = (req_ffg.ir_ffg.ir_avg / + req_ffg.ir_ffg.ir_free_chunks_real); + + req_ffg.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_freefrag __user *)user_req, + &req_ffg, +sizeof (struct ocfs2_info_freefrag ))) { + status = -EFAULT ; + goto bail; + } + +bail: +if (unlock) +ocfs2_inode_unlock (gb_inode,0 ); + +bail_mutex_unlock: +if (gb_inode) +mutex_unlock (&gb_inode->i_mutex); + +iput (gb_inode); +brelse (bh); + +mlog_exit (status); +return status; +} + +int ocfs2_info_scan_inode_alloc (struct inode *inode_alloc, +struct ocfs2_info_freeinode *fi, +__u32 slotnum, +int flags) +{ +int status =0 , unlock =0 ; + +struct buffer_head *bh =NULL ; +struct ocfs2_dinode *dinode_alloc =NULL ; + +mutex_lock (&inode_alloc->i_mutex); + +if (!(flags &OCFS2_INFO_FL_NON_COHERENT )) { + status =ocfs2_inode_lock (inode_alloc, &bh,0 ); +if (status <0 ) { +mlog_errno (status); + goto bail_mutex_unlock; + } + unlock =1 ; + + }else { + + status =ocfs2_read_inode_block (inode_alloc, &bh); +if (status <0 ) { +mlog_errno (status); + goto bail; + } + } + + dinode_alloc = (struct ocfs2_dinode *)bh->b_data; + + fi->ir_fi_stat[slotnum].ir_total = +le32_to_cpu (dinode_alloc->id1.bitmap1.i_total); + fi->ir_fi_stat[slotnum].ir_free = +le32_to_cpu (dinode_alloc->id1.bitmap1.i_total) - +le32_to_cpu (dinode_alloc->id1.bitmap1.i_used); +bail: +if (unlock) +ocfs2_inode_unlock (inode_alloc,0 ); + +bail_mutex_unlock: +mutex_unlock (&inode_alloc->i_mutex); + +iput (inode_alloc); +brelse (bh); + +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_freeinode (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 , i; + +struct ocfs2_info_freeinode req_fi; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); +struct inode *inode_alloc =NULL ; + + +if (copy_from_user (&req_fi, user_req, +sizeof (struct ocfs2_info_freeinode ))) { + status = -EFAULT ; + goto bail; + } + + req_fi.ir_slotnum = osb->max_slots; + +for (i =0 ; i < req_fi.ir_slotnum; i++) { + inode_alloc = +ocfs2_get_system_file_inode (osb, +INODE_ALLOC_SYSTEM_INODE , + i); +if (!inode_alloc) { +mlog (ML_ERROR ,"unable to get alloc inode in slot %u\n" , + (u32 )i); + status = -EIO ; + goto bail; + } + + status =ocfs2_info_scan_inode_alloc (inode_alloc, &req_fi, i, + req_fi.ir_request.ir_flags); +if (status <0 ) + goto bail; + } + + req_fi.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_freeinode __user *)user_req, + &req_fi, +sizeof (struct ocfs2_info_freeinode ))) { + status = -EFAULT ; + } + +bail: + +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_unknown (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_request req; + + if (copy_from_user(&req, user_req, sizeof(struct
ocfs2_info_request))) {fs/ocfs2/ioctl.c +24
-0+ status = -EFAULT ; + goto bail; + } + + req.ir_flags &= ~OCFS2_INFO_FL_FILLED ; + +if (copy_to_user (user_req, &req, +sizeof (struct ocfs2_info_request ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_request (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_request req; + + if (copy_from_user(&req, user_req, sizeof(struct
ocfs2_info_request))) {fs/ocfs2/ioctl.c +66
-0+ status = -EFAULT ; + goto bail; + } + +if (req.ir_magic !=OCFS2_INFO_MAGIC ) { + status = -EINVAL ; + goto bail; + } + +switch (req.ir_code) { +case OCFS2_INFO_BLOCKSIZE : +if (req.ir_size !=sizeof (struct ocfs2_info_blocksize )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_blocksize (inode, user_req); +break ; +case OCFS2_INFO_CLUSTERSIZE : +if (req.ir_size !=sizeof (struct ocfs2_info_clustersize )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_clustersize (inode, user_req); +break ; +case OCFS2_INFO_SLOTNUM : +if (req.ir_size !=sizeof (struct ocfs2_info_slotnum )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_slotnum (inode, user_req); +break ; +case OCFS2_INFO_LABEL : +if (req.ir_size !=sizeof (struct ocfs2_info_label )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_label (inode, user_req); +break ; +case OCFS2_INFO_UUID : +if (req.ir_size !=sizeof (struct ocfs2_info_uuid )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_uuid (inode, user_req); +break ; +case OCFS2_INFO_FS_FEATURES : +if (req.ir_size !=sizeof (struct ocfs2_info_fs_features )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_fs_features (inode, user_req); +break ; +case OCFS2_INFO_FREEFRAG : +if (req.ir_size !=sizeof (struct ocfs2_info_freefrag )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_freefrag (inode, user_req); +break ; +case OCFS2_INFO_FREEINODE : +if (req.ir_size !=sizeof (struct ocfs2_info_freeinode )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_freeinode (inode, user_req); +break ;
Quoted 8 lines
Quoted 8 lines
fs/ocfs2/ioctl.c bail: · line 727
Quoted 5 lines
fs/ocfs2/ioctl.c +4
-0+default : + status =ocfs2_info_handle_unknown (inode, user_req); +break ; + }For the first round, can we remove the freefrag and freeinode. That needs a closer look. I would like the scalars entered first.
Fine to me.
Quoted 109 lines
Quoted 109 lines
Quoted 109 lines
fs/ocfs2/ioctl.c +47
-0+ +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle (struct inode *inode,struct ocfs2_info *info, +int compat_flag) +{ +int i, status =0 ; +u64 req_addr; +struct ocfs2_info_request __user *reqp; + +if ((info->info_count >OCFS2_INFO_MAX_REQUEST ) || + (!info->info_requests)) { + status = -EINVAL ; + goto bail; + } + +for (i =0 ; i < info->info_count; i++) { + status = -EFAULT ; +if (compat_flag) { +if (get_user (req_addr, + (u64 __user *)compat_ptr (info->info_requests) + i)) + goto bail; + }else { +if (get_user (req_addr, + (u64 __user *)(info->info_requests) + i)) + goto bail; + } + + reqp = (struct ocfs2_info_request *)req_addr; +if (!reqp) { + status = -EINVAL ; + goto bail; + } + + status =ocfs2_info_handle_request (inode, reqp); +if (status) + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned longarg)
{ struct inode *inode = filp->f_path.dentry->d_inode;fs/ocfs2/ioctl.c +1
-0@@ -120,6 +783,7 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)struct reflink_arguments args;const char *old_path, *new_path;bool preserve; +struct ocfs2_info info;switch (cmd) {case
OCFS2_IOC_GETFLAGS:fs/ocfs2/ioctl.c +6
-0@@ -174,6 +838,12 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) preserve = (args.preserve !=0 );return ocfs2_reflink_ioctl (inode, old_path, new_path, preserve); +case OCFS2_IOC_INFO : +if (copy_from_user (&info, (struct ocfs2_info __user *)arg, +sizeof (struct ocfs2_info ))) +return -EFAULT ; + +return ocfs2_info_handle (inode, &info,0 );default :return -ENOTTY; }fs/ocfs2/ioctl.c +1
-0@@ -185,6 +855,7 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) bool preserve;struct reflink_arguments args;struct inode *inode = file->f_path.dentry->d_inode; +struct ocfs2_info info;switch (cmd) {case
OCFS2_IOC32_GETFLAGS:fs/ocfs2/ioctl.c +6
-0@@ -209,6 +880,12 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) return ocfs2_reflink_ioctl(inode, compat_ptr(args.old_path), compat_ptr(args.new_path), preserve); +case OCFS2_IOC_INFO : +if (copy_from_user (&info, (struct ocfs2_info __user *)arg, +sizeof (struct ocfs2_info ))) +return -EFAULT ; + +return ocfs2_info_handle (inode, &info,1 );default :return -ENOIOCTLCMD ;}fs/ocfs2/ocfs2_ioctl.h +0
-0@@ -76,4 +76,121 @@ struct reflink_arguments { };#define OCFS2_IOC_REFLINK _IOW('o', 4, struct reflink_arguments)
Quoted 7 lines
Quoted 7 lines
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments {
Quoted 5 lines
fs/ocfs2/ocfs2_ioctl.h +4
-0+/* Following definitions dedicated for ocfs2_info_request ioctls. */ + +#define OCFS2_INFO_VOL_UUID_LEN (16) +#define OCFS2_INFO_MAX_VOL_LABEL_LEN (64)Why not use the existing #defines in
ocfs2_fs.h
Good catch, thanks for pointing this out, originally I define this in ocfs2_fs.h, where 'OCFS2_VOL_UUID_LEN' and 'OCFS2_MAX_VOL_LABEL_LEN' were too far away from being referred, now we're free to use them:)
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
fs/ocfs2/ocfs2_ioctl.h +11
-0+#define OCFS2_INFO_VOL_UUIDSTR_LEN (OCFS2_INFO_VOL_UUID_LEN * 2 + 1) +#define OCFS2_INFO_MAX_SLOTS (255) +#define OCFS2_INFO_MAX_HIST (32) + +#define OCFS2_INFO_MAX_REQUEST (50) + +/* Magic number of all requests */ +#define OCFS2_INFO_MAGIC (0x4F32494E) + +/* +* Always try to separate info request into small pieces to
Quoted 8 lines
Quoted 8 lines
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 99
Quoted 7 lines
+ * guarantee the backward&forward compatibility.
+ */fs/ocfs2/ocfs2_ioctl.h +4
-0+ +struct ocfs2_info { +__u64 info_requests;/* Array of __u64 pointers to requests */ +__u32 info_count;/* Number of requests in info_requests */
oi_requests,oi_count
Makes sense.
Quoted 17 lines
Quoted 17 lines
Quoted 6 lines
fs/ocfs2/ocfs2_ioctl.h +3
-0+}; + +struct ocfs2_info_request {fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 112
Quoted 10 lines
fs/ocfs2/ocfs2_ioctl.h +10
-0+/*00*/ __u32 ir_magic;/* Magic number */ +__u32 ir_code;/* Info request code */ +__u32 ir_size;/* Size of request */ +__u32 ir_flags;/* Request flags */ +/*10*/ /* Request specific fields */ +}; + +struct ocfs2_info_clustersize { +struct ocfs2_info_request ir_request; +__u32 ir_clustersize;
ic_req,ic_clustersize
Just puzzled, why not 'oic_req' and 'oic_clustersize'?
Quoted 10 lines
Quoted 10 lines
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 117
Quoted 8 lines
fs/ocfs2/ocfs2_ioctl.h +5
-0+}; + +struct ocfs2_info_blocksize { +struct ocfs2_info_request ir_request; +__u32 ir_blocksize;
ib_req,ib_blocksize
also, why not 'oib_request' and 'oib_blocksize'?
Quoted 12 lines
Quoted 12 lines
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 122
Quoted 8 lines
fs/ocfs2/ocfs2_ioctl.h +5
-0+}; + +struct ocfs2_info_slotnum { +struct ocfs2_info_request ir_request; +__u16 ir_slotnum;
ocfs2_info_maxslotsis_req,is_max_slots
Quoted 1 line
Quoted 1 line
(slotnum could be later used to query the slot use by that node)
Thanks for making things more clear!
Quoted 61 lines
Quoted 61 lines
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 128
Quoted 9 lines
fs/ocfs2/ocfs2_ioctl.h +6
-0+}; + +struct ocfs2_info_label { +struct ocfs2_info_request ir_request; +__u8 ir_label[OCFS2_INFO_MAX_VOL_LABEL_LEN ]; +};
il_req,il_labelYou get the drift.
Quoted 46 lines
fs/ocfs2/ocfs2_ioctl.h +46
-0+ +struct ocfs2_info_uuid { +struct ocfs2_info_request ir_request; +__u8 ir_uuid_str[OCFS2_INFO_VOL_UUIDSTR_LEN ]; +}; + +struct ocfs2_info_fs_features { +struct ocfs2_info_request ir_request; +__u32 ir_compat_features; +__u32 ir_incompat_features; +__u32 ir_ro_compat_features; +}; + +struct ocfs2_info_freefrag { +struct ocfs2_info_request ir_request; +__u32 ir_chunksize;/* chunksize in clusters(in) */ +struct ocfs2_info_freefrag_stats {/* (out) */ +__u32 ir_clusters; +__u32 ir_free_clusters; +__u32 ir_free_chunks; +__u32 ir_free_chunks_real; +__u32 ir_min;/* Minimum free chunksize in clusters */ +__u32 ir_max; +__u32 ir_avg; +struct ocfs2_info_free_chunk_list { +__u32 ir_fc_chunks[OCFS2_INFO_MAX_HIST ]; +__u32 ir_fc_clusters[OCFS2_INFO_MAX_HIST ]; + } ir_fc_hist; + } ir_ffg; +}; + +struct ocfs2_info_freeinode { +struct ocfs2_info_request ir_request; +__u32 ir_slotnum;/* out */ +struct ocfs2_info_local_fi { +__u64 ir_total; +__u64 ir_free; + } ir_fi_stat[OCFS2_INFO_MAX_SLOTS ]; +}; + +/* Codes for ocfs2_info_request */ +enum ocfs2_info_type { +OCFS2_INFO_CLUSTERSIZE =1 , +OCFS2_INFO_BLOCKSIZE , +OCFS2_INFO_SLOTNUM , +OCFS2_INFO_LABEL ,
Quoted 8 lines
Quoted 8 lines
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 179
Quoted 6 lines
fs/ocfs2/ocfs2_ioctl.h +5
-0+OCFS2_INFO_UUID , +OCFS2_INFO_FS_FEATURES , +OCFS2_INFO_FREEFRAG , +OCFS2_INFO_FREEINODE , +NUM_OCFS2_INFO_TYPE
OCFS2_INFO_NUM_TYPES
All right.
Quoted 30 lines
Quoted 29 lines
Quoted 16 lines
fs/ocfs2/ocfs2_ioctl.h +5
-0+}; + +/* Flags for struct ocfs2_info_request */ +/* Filled by the caller */ +#define OCFS2_INFO_FL_NON_COHERENT (0x00000001)/* Cluster coherency not
fs/ocfs2/ocfs2_ioctl.h +6
-0+required. This is a hint. +It is up to ocfs2 whether +the request can be fulfilled +without locking. */ +/* Filled by ocfs2 */ +#define OCFS2_INFO_FL_FILLED (0x80000000)/* Filesystem understood
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 196
Quoted 6 lines
fs/ocfs2/ocfs2_ioctl.h +5
-0+this request and +filled in the answer */ + +#define OCFS2_IOC_INFO _IOR('o', 5, struct ocfs2_info) +#endif /* OCFS2_IOCTL_H */ _______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com
http://oss.oracle.com/mailman/listinfo/ocfs2-devel
PATCH 2/2 Ocfs2: Add new OCFS2_IOC_INFO ioctl for ocfs2 v6.
In reply to Sunil MushranQuoted 4 lines · Sunil Mushran
I like the overall flow. I just have some comments on style.
Also, would prefer if you drop freeinode and freefrag for the first checkin. That not only needs a closer look.
It will be fine to me.
Quoted 2 lines
For the next drop, just have this patch. The first one is in mainline.
Yes, the first patch of moving ioctl definitions from ocfs2_fs.h to ocfs2_ioctl.h has been in mainline now, the reason why I post here is for readability.
Quoted 984 lines
Thanks
Quoted 82 lines · Tristan Ye
The reason why we need this ioctl is to offer the none-privileged end-user a possibility to get filesys info gathering.
We use
OCFS2_IOC_INFOto manipulate the new ioctl, userspace passes a structure to kernel containing an array of request pointers and request count, such as,* From userspace:
struct ocfs2_info_blocksize brq = { .ir_request = { .ir_magic = OCFS2_INFO_MAGIC, .ir_code = OCFS2_INFO_BLOCKSIZE, ... } ... }struct ocfs2_info_clustersize crq = { ... }
uint64_treqs[2] = {(unsigned long)&brq,(unsigned long)&crq};struct
ocfs2_infoinfo = {
.ir_requests = reqs,
.ir_count = 2,
}ret =
ioctl(fd, OCFS2_IOC_INFO, &info);* In kernel:
Get the request pointers from *info*, then handle each request one bye one.
Idea here is to make the spearated request small enough to guarantee a better backward&forward compatibility since a small piece of request would be less likely to be broken if filesys on raw disk get changed.
Currently, following 8 ioctls get implemented per the requirement from userspace tool o2info, and I believe it will grow over time:-)
OCFS2_INFO_CLUSTERSIZE
OCFS2_INFO_BLOCKSIZE
OCFS2_INFO_SLOTNUM
OCFS2_INFO_LABEL
OCFS2_INFO_UUID
OCFS2_INFO_FS_FEATURES
OCFS2_INFO_FREEFRAG
OCFS2_INFO_FREEINODEThis ioctl is only specific to OCFS2.
Signed-off-by Tristan Ye <[email protected]>Signed-off-by Joel Becker <[email protected]>--- fs/ocfs2/ioctl.c | 677 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/ocfs2_ioctl.h | 117 +++++++++ 2 files changed, 794 insertions(+), 0 deletions(-)fs/ocfs2/ioctl.c +5
-0@@ -23,8 +23,13 @@#include "ioctl.h" #include "resize.h" #include "refcounttree.h" +#include "sysfile.h" +#include "buffer_head_io.h" +#include "suballoc.h" +#include <linux/ext2_fs.h> +#include <linux/compat.h> static int ocfs2_get_inode_attr (struct inode *inode,unsigned *flags) {fs/ocfs2/ioctl.c bail: · line 122
Quoted 9 lines
fs/ocfs2/ioctl.c +5
-0@@ -109,6 +114,664 @@ bail:return status; } +int ocfs2_info_handle_blocksize (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_blocksize req_bs;
req_bsis a mouthful. How about "oib"? For the next function it could be "oic"? We do this everywhere. eg, osb, di, et, el, etc.Quoted 10 lines
fs/ocfs2/ioctl.c +10
-0+ +if (copy_from_user (&req_bs, user_req, +sizeof (struct ocfs2_info_blocksize ))) { + status = -EFAULT ; + goto bail; + } + + req_bs.ir_blocksize = inode->i_sb->s_blocksize; + req_bs.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; +fs/ocfs2/ioctl.c bail:
Quoted 10 lines
fs/ocfs2/ioctl.c +9
-0+if (copy_to_user ((struct ocfs2_info_blocksize __user *)user_req, + &req_bs, +sizeof (struct ocfs2_info_blocksize ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status);Don't have a exit without an entry. But I think we can do without the entry/exit mlogs in these ioctls.
fs/ocfs2/ioctl.c bail:
Quoted 8 lines
fs/ocfs2/ioctl.c +7
-0+return status; +} + +int ocfs2_info_handle_clustersize (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ;Or, you could set it to
-EFAULThere and set it to 0 just before bail.Quoted 576 lines
fs/ocfs2/ioctl.c +94
-0+struct ocfs2_info_clustersize req_cs; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_cs, user_req, +sizeof (struct ocfs2_info_clustersize ))) { + status = -EFAULT ; + goto bail; + } + + req_cs.ir_clustersize = osb->s_clustersize; + req_cs.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_clustersize __user *)user_req, + &req_cs, +sizeof (struct ocfs2_info_clustersize ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_slotnum (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_slotnum req_sn; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_sn, user_req, +sizeof (struct ocfs2_info_slotnum ))) { + status = -EFAULT ; + goto bail; + } + + req_sn.ir_slotnum = osb->max_slots; + req_sn.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_slotnum __user *)user_req, + &req_sn, +sizeof (struct ocfs2_info_slotnum ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_label (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_label req_lb; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_lb, user_req, +sizeof (struct ocfs2_info_label ))) { + status = -EFAULT ; + goto bail; + } + +memcpy (req_lb.ir_label, osb->vol_label,OCFS2_MAX_VOL_LABEL_LEN ); + req_lb.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_label __user *)user_req, + &req_lb, +sizeof (struct ocfs2_info_label ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_uuid (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_uuid req_uuid; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_uuid, user_req, +sizeof (struct ocfs2_info_uuid ))) { + status = -EFAULT ; + goto bail; + } + + memcpy(req_uuid.ir_uuid_str, osb->uuid_str,
OCFS2_INFO_VOL_UUIDSTR_LEN);fs/ocfs2/ioctl.c +209
-0+ req_uuid.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_uuid __user *)user_req, + &req_uuid, +sizeof (struct ocfs2_info_uuid ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_fs_features (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_fs_features req_fs; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); + +if (copy_from_user (&req_fs, user_req, +sizeof (struct ocfs2_info_fs_features ))) { + status = -EFAULT ; + goto bail; + } + + req_fs.ir_compat_features = osb->s_feature_compat; + req_fs.ir_incompat_features = osb->s_feature_incompat; + req_fs.ir_ro_compat_features = osb->s_feature_ro_compat; + req_fs.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_fs_features __user *)user_req, + &req_fs, +sizeof (struct ocfs2_info_fs_features ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +void ocfs2_info_update_ffg (struct ocfs2_info_freefrag *ffg, +unsigned int chunksize) +{ +int index; + + index =__ilog2_u32 (chunksize); +if (index >=OCFS2_INFO_MAX_HIST ) + index =OCFS2_INFO_MAX_HIST -1 ; + + ffg->ir_ffg.ir_fc_hist.ir_fc_chunks[index]++; + ffg->ir_ffg.ir_fc_hist.ir_fc_clusters[index] += chunksize; + +if (chunksize > ffg->ir_ffg.ir_max) + ffg->ir_ffg.ir_max = chunksize; + +if (chunksize < ffg->ir_ffg.ir_min) + ffg->ir_ffg.ir_min = chunksize; + + ffg->ir_ffg.ir_avg += chunksize; + ffg->ir_ffg.ir_free_chunks_real++; +} + +int ocfs2_info_scan_chain (struct inode *gb_inode, +struct ocfs2_dinode *gb_dinode, +struct ocfs2_info_freefrag *ffg, +struct ocfs2_chain_rec *rec, +unsigned int chunks_in_group) +{ +int status =0 , used; +u64 blkno; + +struct buffer_head *bh =NULL ; +struct ocfs2_group_desc *bg =NULL ; + +unsigned int max_bits, num_clusters; +unsigned int offset =0 , cluster, chunk; +unsigned int chunk_free, last_chunksize =0 ; + +if (!le32_to_cpu (rec->c_free)) + goto bail; + +do { +if (!bg) + blkno =le64_to_cpu (rec->c_blkno); +else + blkno =le64_to_cpu (bg->bg_next_group); + +if (bh) { +brelse (bh); + bh =NULL ; + } + + status =ocfs2_read_group_descriptor (gb_inode, gb_dinode, + blkno, &bh); +if (status <0 ) { +mlog (ML_ERROR ,"Can't read the group descriptor # " +"%llu from device." , (unsigned long long )blkno); + status = -EIO ; + goto bail; + } + + bg = (struct ocfs2_group_desc *)bh->b_data; + +if (!le16_to_cpu (bg->bg_free_bits_count)) +continue ; + + max_bits =le16_to_cpu (bg->bg_bits); + offset =0 ; + +for (chunk =0 ; chunk < chunks_in_group; chunk++) { + +/* Last chunk may be not a entire one */ +if ((offset + ffg->ir_chunksize) > max_bits) + num_clusters = max_bits - offset; +else + num_clusters = ffg->ir_chunksize; + + chunk_free =0 ; +for (cluster =0 ; cluster < num_clusters; cluster++) { + used =ocfs2_test_bit (offset, + (unsigned long *)bg->bg_bitmap); +if (!used) { + last_chunksize++; + chunk_free++; + } + +if (used && (last_chunksize)) { +ocfs2_info_update_ffg (ffg, + last_chunksize); + last_chunksize =0 ; + } + + offset++; + } + +if (chunk_free == ffg->ir_chunksize) + ffg->ir_ffg.ir_free_chunks++; + } + +/* we need to update the info of last free chunk */ +if (last_chunksize) +ocfs2_info_update_ffg (ffg, last_chunksize); + + }while (le64_to_cpu (bg->bg_next_group)); + +bail: +brelse (bh); + +mlog_exit (status); +return status; +} + +int ocfs2_info_scan_bitmap (struct inode *gb_inode, +struct ocfs2_dinode *gb_dinode, +struct ocfs2_info_freefrag *ffg, +struct ocfs2_chain_list *cl) +{ +int status =0 , i; +unsigned int chunks_in_group; +struct ocfs2_chain_rec *rec =NULL ; + + chunks_in_group =le16_to_cpu (cl->cl_cpg) / ffg->ir_chunksize +1 ; + +for (i =0 ; i <le16_to_cpu (cl->cl_next_free_rec); i++) { + + rec = &(cl->cl_recs[i]); + status =ocfs2_info_scan_chain (gb_inode, gb_dinode, + ffg, rec, chunks_in_group); +if (status) + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_freefrag (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 , unlock =0 ; + +struct ocfs2_info_freefrag req_ffg; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); +struct buffer_head *bh =NULL ; +struct inode *gb_inode =NULL ; +struct ocfs2_dinode *gb_dinode =NULL ; +struct ocfs2_chain_list *cl =NULL ; + +if (copy_from_user (&req_ffg, user_req, +sizeof (struct ocfs2_info_freefrag ))) { + status = -EFAULT ; + goto bail; + } + +/* +* chunksize from userspace should be power of 2, +*/ +if ((req_ffg.ir_chunksize & (req_ffg.ir_chunksize -1 )) || + (!req_ffg.ir_chunksize)) { + status = -EINVAL ; + goto bail; + } + + memset(&req_ffg.ir_ffg, 0, sizeof(struct
ocfs2_info_freefrag_stats));fs/ocfs2/ioctl.c +39
-0+ req_ffg.ir_ffg.ir_min = ~0U ; + + gb_inode =ocfs2_get_system_file_inode (osb, +GLOBAL_BITMAP_SYSTEM_INODE , +OCFS2_INVALID_SLOT ); +if (!gb_inode) { +mlog (ML_ERROR ,"failed to get bitmap inode\n" ); + status = -EIO ; + goto bail; + } + +mutex_lock (&gb_inode->i_mutex); + +if (!(req_ffg.ir_request.ir_flags &OCFS2_INFO_FL_NON_COHERENT )) { + status =ocfs2_inode_lock (gb_inode, &bh,0 ); +if (status <0 ) { +mlog_errno (status); + goto bail_mutex_unlock; + } + unlock =1 ; + + }else { + status =ocfs2_read_inode_block (gb_inode, &bh); +if (status <0 ) { +mlog_errno (status); + goto bail; + } + } + + gb_dinode = (struct ocfs2_dinode *)bh->b_data; + + req_ffg.ir_ffg.ir_clusters = +le32_to_cpu (gb_dinode->id1.bitmap1.i_total); + req_ffg.ir_ffg.ir_free_clusters = req_ffg.ir_ffg.ir_clusters - +le32_to_cpu (gb_dinode->id1.bitmap1.i_used); + + cl = &(gb_dinode->id2.i_chain); + +/* Chunksize from userspace should be less than clusters in a group */
fs/ocfs2/ioctl.c +144
-0+if (req_ffg.ir_chunksize >le16_to_cpu (cl->cl_cpg)) { + status = -EINVAL ; + goto bail; + } + + status =ocfs2_info_scan_bitmap (gb_inode, gb_dinode, &req_ffg, cl); +if (status) + goto bail; + +if (req_ffg.ir_ffg.ir_free_chunks_real) + req_ffg.ir_ffg.ir_avg = (req_ffg.ir_ffg.ir_avg / + req_ffg.ir_ffg.ir_free_chunks_real); + + req_ffg.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_freefrag __user *)user_req, + &req_ffg, +sizeof (struct ocfs2_info_freefrag ))) { + status = -EFAULT ; + goto bail; + } + +bail: +if (unlock) +ocfs2_inode_unlock (gb_inode,0 ); + +bail_mutex_unlock: +if (gb_inode) +mutex_unlock (&gb_inode->i_mutex); + +iput (gb_inode); +brelse (bh); + +mlog_exit (status); +return status; +} + +int ocfs2_info_scan_inode_alloc (struct inode *inode_alloc, +struct ocfs2_info_freeinode *fi, +__u32 slotnum, +int flags) +{ +int status =0 , unlock =0 ; + +struct buffer_head *bh =NULL ; +struct ocfs2_dinode *dinode_alloc =NULL ; + +mutex_lock (&inode_alloc->i_mutex); + +if (!(flags &OCFS2_INFO_FL_NON_COHERENT )) { + status =ocfs2_inode_lock (inode_alloc, &bh,0 ); +if (status <0 ) { +mlog_errno (status); + goto bail_mutex_unlock; + } + unlock =1 ; + + }else { + + status =ocfs2_read_inode_block (inode_alloc, &bh); +if (status <0 ) { +mlog_errno (status); + goto bail; + } + } + + dinode_alloc = (struct ocfs2_dinode *)bh->b_data; + + fi->ir_fi_stat[slotnum].ir_total = +le32_to_cpu (dinode_alloc->id1.bitmap1.i_total); + fi->ir_fi_stat[slotnum].ir_free = +le32_to_cpu (dinode_alloc->id1.bitmap1.i_total) - +le32_to_cpu (dinode_alloc->id1.bitmap1.i_used); +bail: +if (unlock) +ocfs2_inode_unlock (inode_alloc,0 ); + +bail_mutex_unlock: +mutex_unlock (&inode_alloc->i_mutex); + +iput (inode_alloc); +brelse (bh); + +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_freeinode (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 , i; + +struct ocfs2_info_freeinode req_fi; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); +struct inode *inode_alloc =NULL ; + + +if (copy_from_user (&req_fi, user_req, +sizeof (struct ocfs2_info_freeinode ))) { + status = -EFAULT ; + goto bail; + } + + req_fi.ir_slotnum = osb->max_slots; + +for (i =0 ; i < req_fi.ir_slotnum; i++) { + inode_alloc = +ocfs2_get_system_file_inode (osb, +INODE_ALLOC_SYSTEM_INODE , + i); +if (!inode_alloc) { +mlog (ML_ERROR ,"unable to get alloc inode in slot %u\n" , + (u32 )i); + status = -EIO ; + goto bail; + } + + status =ocfs2_info_scan_inode_alloc (inode_alloc, &req_fi, i, + req_fi.ir_request.ir_flags); +if (status <0 ) + goto bail; + } + + req_fi.ir_request.ir_flags |=OCFS2_INFO_FL_FILLED ; + +if (copy_to_user ((struct ocfs2_info_freeinode __user *)user_req, + &req_fi, +sizeof (struct ocfs2_info_freeinode ))) { + status = -EFAULT ; + } + +bail: + +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_unknown (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_request req; + + if (copy_from_user(&req, user_req, sizeof(struct
ocfs2_info_request))) {fs/ocfs2/ioctl.c +24
-0+ status = -EFAULT ; + goto bail; + } + + req.ir_flags &= ~OCFS2_INFO_FL_FILLED ; + +if (copy_to_user (user_req, &req, +sizeof (struct ocfs2_info_request ))) { + status = -EFAULT ; + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle_request (struct inode *inode, +struct ocfs2_info_request __user *user_req) +{ +int status =0 ; +struct ocfs2_info_request req; + + if (copy_from_user(&req, user_req, sizeof(struct
ocfs2_info_request))) {fs/ocfs2/ioctl.c +60
-0+ status = -EFAULT ; + goto bail; + } + +if (req.ir_magic !=OCFS2_INFO_MAGIC ) { + status = -EINVAL ; + goto bail; + } + +switch (req.ir_code) { +case OCFS2_INFO_BLOCKSIZE : +if (req.ir_size !=sizeof (struct ocfs2_info_blocksize )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_blocksize (inode, user_req); +break ; +case OCFS2_INFO_CLUSTERSIZE : +if (req.ir_size !=sizeof (struct ocfs2_info_clustersize )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_clustersize (inode, user_req); +break ; +case OCFS2_INFO_SLOTNUM : +if (req.ir_size !=sizeof (struct ocfs2_info_slotnum )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_slotnum (inode, user_req); +break ; +case OCFS2_INFO_LABEL : +if (req.ir_size !=sizeof (struct ocfs2_info_label )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_label (inode, user_req); +break ; +case OCFS2_INFO_UUID : +if (req.ir_size !=sizeof (struct ocfs2_info_uuid )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_uuid (inode, user_req); +break ; +case OCFS2_INFO_FS_FEATURES : +if (req.ir_size !=sizeof (struct ocfs2_info_fs_features )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_fs_features (inode, user_req); +break ; +case OCFS2_INFO_FREEFRAG : +if (req.ir_size !=sizeof (struct ocfs2_info_freefrag )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_freefrag (inode, user_req); +break ; +case OCFS2_INFO_FREEINODE :fs/ocfs2/ioctl.c bail: · line 727
Quoted 10 lines
fs/ocfs2/ioctl.c +10
-0+if (req.ir_size !=sizeof (struct ocfs2_info_freeinode )) { + status = -EINVAL ; +break ; + } + status =ocfs2_info_handle_freeinode (inode, user_req); +break ; +default : + status =ocfs2_info_handle_unknown (inode, user_req); +break ; + }For the first round, can we remove the freefrag and freeinode. That needs a closer look. I would like the scalars entered first.
Quoted 103 lines
fs/ocfs2/ioctl.c +47
-0+ +bail: +mlog_exit (status); +return status; +} + +int ocfs2_info_handle (struct inode *inode,struct ocfs2_info *info, +int compat_flag) +{ +int i, status =0 ; +u64 req_addr; +struct ocfs2_info_request __user *reqp; + +if ((info->info_count >OCFS2_INFO_MAX_REQUEST ) || + (!info->info_requests)) { + status = -EINVAL ; + goto bail; + } + +for (i =0 ; i < info->info_count; i++) { + status = -EFAULT ; +if (compat_flag) { +if (get_user (req_addr, + (u64 __user *)compat_ptr (info->info_requests) + i)) + goto bail; + }else { +if (get_user (req_addr, + (u64 __user *)(info->info_requests) + i)) + goto bail; + } + + reqp = (struct ocfs2_info_request *)req_addr; +if (!reqp) { + status = -EINVAL ; + goto bail; + } + + status =ocfs2_info_handle_request (inode, reqp); +if (status) + goto bail; + } + +bail: +mlog_exit (status); +return status; +} + long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned longarg)
{ struct inode *inode = filp->f_path.dentry->d_inode;fs/ocfs2/ioctl.c +1
-0@@ -120,6 +783,7 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)struct reflink_arguments args;const char *old_path, *new_path;bool preserve; +struct ocfs2_info info;switch (cmd) {case
OCFS2_IOC_GETFLAGS:fs/ocfs2/ioctl.c +6
-0@@ -174,6 +838,12 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) preserve = (args.preserve !=0 );return ocfs2_reflink_ioctl (inode, old_path, new_path, preserve); +case OCFS2_IOC_INFO : +if (copy_from_user (&info, (struct ocfs2_info __user *)arg, +sizeof (struct ocfs2_info ))) +return -EFAULT ; + +return ocfs2_info_handle (inode, &info,0 );default :return -ENOTTY; }fs/ocfs2/ioctl.c +1
-0@@ -185,6 +855,7 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) bool preserve;struct reflink_arguments args;struct inode *inode = file->f_path.dentry->d_inode; +struct ocfs2_info info;switch (cmd) {case
OCFS2_IOC32_GETFLAGS:fs/ocfs2/ioctl.c +6
-0@@ -209,6 +880,12 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) return ocfs2_reflink_ioctl(inode, compat_ptr(args.old_path), compat_ptr(args.new_path), preserve); +case OCFS2_IOC_INFO : +if (copy_from_user (&info, (struct ocfs2_info __user *)arg, +sizeof (struct ocfs2_info ))) +return -EFAULT ; + +return ocfs2_info_handle (inode, &info,1 );default :return -ENOIOCTLCMD ;}fs/ocfs2/ocfs2_ioctl.h +0
-0fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 83
Quoted 8 lines
fs/ocfs2/ocfs2_ioctl.h +4
-0@@ -76,4 +76,121 @@ struct reflink_arguments { };#define OCFS2_IOC_REFLINK _IOW('o', 4, struct reflink_arguments) +/* Following definitions dedicated for ocfs2_info_request ioctls. */ + +#define OCFS2_INFO_VOL_UUID_LEN (16) +#define OCFS2_INFO_MAX_VOL_LABEL_LEN (64)Why not use the existing #defines in
ocfs2_fs.hQuoted 8 lines
fs/ocfs2/ocfs2_ioctl.h +6
-0+#define OCFS2_INFO_VOL_UUIDSTR_LEN (OCFS2_INFO_VOL_UUID_LEN * 2 + 1) +#define OCFS2_INFO_MAX_SLOTS (255) +#define OCFS2_INFO_MAX_HIST (32) + +#define OCFS2_INFO_MAX_REQUEST (50) + +/* Magic number of all requests */ fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 99
Quoted 10 lines
fs/ocfs2/ocfs2_ioctl.h +10
-0+#define OCFS2_INFO_MAGIC (0x4F32494E) + +/* +* Always try to separate info request into small pieces to +* guarantee the backward&forward compatibility. +*/ + +struct ocfs2_info { +__u64 info_requests;/* Array of __u64 pointers to requests */ +__u32 info_count;/* Number of requests in info_requests */
oi_requests,oi_countQuoted 4 lines
fs/ocfs2/ocfs2_ioctl.h +3
-0+}; + +struct ocfs2_info_request {fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 112
Quoted 10 lines
fs/ocfs2/ocfs2_ioctl.h +10
-0+/*00*/ __u32 ir_magic;/* Magic number */ +__u32 ir_code;/* Info request code */ +__u32 ir_size;/* Size of request */ +__u32 ir_flags;/* Request flags */ +/*10*/ /* Request specific fields */ +}; + +struct ocfs2_info_clustersize { +struct ocfs2_info_request ir_request; +__u32 ir_clustersize;
ic_req,ic_clustersizefs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 117
Quoted 6 lines
fs/ocfs2/ocfs2_ioctl.h +5
-0+}; + +struct ocfs2_info_blocksize { +struct ocfs2_info_request ir_request; +__u32 ir_blocksize;
ib_req,ib_blocksizefs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 122
Quoted 6 lines
fs/ocfs2/ocfs2_ioctl.h +5
-0+}; + +struct ocfs2_info_slotnum { +struct ocfs2_info_request ir_request; +__u16 ir_slotnum;
ocfs2_info_maxslotsis_req,is_max_slots(slotnum could be later used to query the slot use by that node)
fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 128
Quoted 7 lines
fs/ocfs2/ocfs2_ioctl.h +6
-0+}; + +struct ocfs2_info_label { +struct ocfs2_info_request ir_request; +__u8 ir_label[OCFS2_INFO_MAX_VOL_LABEL_LEN ]; +};
il_req,il_labelYou get the drift.
Quoted 42 lines
fs/ocfs2/ocfs2_ioctl.h +41
-0+ +struct ocfs2_info_uuid { +struct ocfs2_info_request ir_request; +__u8 ir_uuid_str[OCFS2_INFO_VOL_UUIDSTR_LEN ]; +}; + +struct ocfs2_info_fs_features { +struct ocfs2_info_request ir_request; +__u32 ir_compat_features; +__u32 ir_incompat_features; +__u32 ir_ro_compat_features; +}; + +struct ocfs2_info_freefrag { +struct ocfs2_info_request ir_request; +__u32 ir_chunksize;/* chunksize in clusters(in) */ +struct ocfs2_info_freefrag_stats {/* (out) */ +__u32 ir_clusters; +__u32 ir_free_clusters; +__u32 ir_free_chunks; +__u32 ir_free_chunks_real; +__u32 ir_min;/* Minimum free chunksize in clusters */ +__u32 ir_max; +__u32 ir_avg; +struct ocfs2_info_free_chunk_list { +__u32 ir_fc_chunks[OCFS2_INFO_MAX_HIST ]; +__u32 ir_fc_clusters[OCFS2_INFO_MAX_HIST ]; + } ir_fc_hist; + } ir_ffg; +}; + +struct ocfs2_info_freeinode { +struct ocfs2_info_request ir_request; +__u32 ir_slotnum;/* out */ +struct ocfs2_info_local_fi { +__u64 ir_total; +__u64 ir_free; + } ir_fi_stat[OCFS2_INFO_MAX_SLOTS ]; +}; + +/* Codes for ocfs2_info_request */ fs/ocfs2/ocfs2_ioctl.h struct reflink_arguments { · line 179
Quoted 10 lines
fs/ocfs2/ocfs2_ioctl.h +10
-0+enum ocfs2_info_type { +OCFS2_INFO_CLUSTERSIZE =1 , +OCFS2_INFO_BLOCKSIZE , +OCFS2_INFO_SLOTNUM , +OCFS2_INFO_LABEL , +OCFS2_INFO_UUID , +OCFS2_INFO_FS_FEATURES , +OCFS2_INFO_FREEFRAG , +OCFS2_INFO_FREEINODE , +NUM_OCFS2_INFO_TYPE
OCFS2_INFO_NUM_TYPESQuoted 20 lines
fs/ocfs2/ocfs2_ioctl.h +5
-0+}; + +/* Flags for struct ocfs2_info_request */ +/* Filled by the caller */ +#define OCFS2_INFO_FL_NON_COHERENT (0x00000001)/* Cluster coherency not
fs/ocfs2/ocfs2_ioctl.h +6
-0+required. This is a hint. +It is up to ocfs2 whether +the request can be fulfilled +without locking. */ +/* Filled by ocfs2 */ +#define OCFS2_INFO_FL_FILLED (0x80000000)/* Filesystem understood
fs/ocfs2/ocfs2_ioctl.h +5
-0+this request and +filled in the answer */ + +#define OCFS2_IOC_INFO _IOR('o', 5, struct ocfs2_info) +#endif /* OCFS2_IOCTL_H */