[Ocfs2-devel] [PATCH 2/2] Ocfs2: Implement new OCFS2_IOC_INFO ioctl for ocfs2.
Sunil Mushran
sunil.mushran at oracle.com
Mon Nov 30 15:49:27 PST 2009
Tristan Ye wrote:
> We implement the request as simple as possible to avoid
> a possible extending if disk format get changed.
>
> Completenss of a request include the info required and a flag(FL_FILLED)
> filled being returned to the end-user.
>
> Note: the requests in a series from userspace should be NULL-terminated.
Pass in the buffer length. Expecting null-termination is asking for trouble.
>
> Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
> ---
> fs/ocfs2/ioctl.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 files changed, 184 insertions(+), 0 deletions(-)
>
> diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
> index 31fbb06..0ac5218 100644
> --- a/fs/ocfs2/ioctl.c
> +++ b/fs/ocfs2/ioctl.c
> @@ -108,6 +108,188 @@ bail:
> return status;
> }
>
> +static int ocfs2_get_request_info(struct inode *inode,
> + unsigned long arg)
> +{
> +
> + int ret = 0, i = 0, num_reqs = 0;
> +
> + struct ocfs2_info_request req, *preq = NULL;
> + struct ocfs2_info_request **reqs;
> + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
> +
> + typedef struct ocfs2_info_request OIR, *POIR;
> + typedef struct ocfs2_info_request_clustersize OIRC, *POIRC;
> + typedef struct ocfs2_info_request_blocksize OIRB, *POIRB;
> + typedef struct ocfs2_info_request_slotnum OIRS, *POIRS;
> + typedef struct ocfs2_info_request_label OIRL, *POIRL;
> + typedef struct ocfs2_info_request_uuid OIRU, *POIRU;
> + typedef struct ocfs2_info_request_fs_features OIRF, *POIRF;
> +
Three no-nos.
1. Do not typedef structures.
2. Use all-caps only for #defines.
3. Do not pre-pend type to the variable name.
For more refer to the kernel coding style.
http://lxr.linux.no/source/Documentation/CodingStyle
> + /*
> + * The requests series from userspace need to be NULL-terminated.
> + */
> + do {
> + preq = *((POIR *)((char *)arg + i * sizeof(POIR)));
> + if (!preq)
> + break;
> + i++;
> +
> + } while (preq);
> +
> + num_reqs = i;
If we pass in the length of the buffer, then num_reqs = len /
sizeof(struct ...);
> +
> + reqs = kmalloc(sizeof(POIR) * num_reqs, GFP_KERNEL);
> + if (!reqs) {
> + ret = -ENOMEM;
> + goto bail;
> + }
We can then copy_from_user the buffer in one go. The remaining
code have to change accordingly.
> +
> + ret = ocfs2_inode_lock(inode, NULL, 0);
> + if (ret < 0) {
> + mlog_errno(ret);
> + goto bail;
> + }
The superblock lock is special. See ocfs2_super_lock().
You'll need to traverse to the osb to use super_lock.
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
Also, make use of OCFS2_INFO_FL_NON_COHERENT.
> +
> + for (i = 0; i < num_reqs; i++) {
> +
> + reqs[i] = NULL;
> +
> + preq = *((POIR *)((char *)arg + i * sizeof(POIR)));
> +
> + if (copy_from_user(&req, preq, sizeof(req))) {
> + ret = -EFAULT;
> + goto bail;
> + }
> +
> + switch (req.ir_code) {
> + case OCFS2_INFO_CLUSTERSIZE:
> + reqs[i] = kmalloc(sizeof(OIRC), GFP_KERNEL);
> +
> + if (copy_from_user(reqs[i], preq, sizeof(OIRC))) {
> + ret = -EFAULT;
> + goto bail;
> + }
> +
> + ((POIRC)(reqs[i]))->ir_clustersize = osb->s_clustersize;
> + reqs[i]->ir_flags |= OCFS2_INFO_FL_FILLED;
> +
> + if (copy_to_user(preq, reqs[i], sizeof(OIRC))) {
> + ret = EFAULT;
-EFAULT.
> + goto bail;
> + }
> +
> + break;
> + case OCFS2_INFO_BLOCKSIZE:
> + reqs[i] = kmalloc(sizeof(OIRB), GFP_KERNEL);
> +
> + if (copy_from_user(reqs[i], preq, sizeof(OIRB))) {
> + ret = -EFAULT;
> + goto bail;
> + }
> +
> + ((POIRB)(reqs[i]))->ir_blocksize =
> + inode->i_sb->s_blocksize;
> + reqs[i]->ir_flags |= OCFS2_INFO_FL_FILLED;
> +
> + if (copy_to_user(preq, reqs[i], sizeof(OIRB))) {
> + ret = -EFAULT;
> + goto bail;
> + }
> +
> + break;
> + case OCFS2_INFO_SLOTNUM:
> + reqs[i] = kmalloc(sizeof(OIRS), GFP_KERNEL);
> +
> + if (copy_from_user(reqs[i], preq, sizeof(OIRS))) {
> + ret = -EFAULT;
> + goto bail;
> + }
> +
> + ((POIRS)(reqs[i]))->ir_slotnum = osb->max_slots;
> + reqs[i]->ir_flags |= OCFS2_INFO_FL_FILLED;
> +
> + if (copy_to_user(preq, reqs[i], sizeof(OIRS))) {
> + ret = -EFAULT;
> + goto bail;
> + }
> +
> + break;
> + case OCFS2_INFO_LABEL:
> + reqs[i] = kmalloc(sizeof(OIRL), GFP_KERNEL);
> +
> + if (copy_from_user(reqs[i], preq, sizeof(OIRL))) {
> + ret = -EFAULT;
> + goto bail;
> + }
> +
> + memmove(((POIRL)(reqs[i]))->ir_label, osb->vol_label,
> + OCFS2_MAX_VOL_LABEL_LEN);
Why memmove() when memcpy() will do?
> + reqs[i]->ir_flags |= OCFS2_INFO_FL_FILLED;
> +
> + if (copy_to_user(preq, reqs[i], sizeof(OIRL))) {
> + ret = -EFAULT;
> + goto bail;
> + }
> +
> + break;
> + case OCFS2_INFO_UUID:
> + reqs[i] = kmalloc(sizeof(OIRU), GFP_KERNEL);
> +
> + if (copy_from_user(reqs[i], preq, sizeof(OIRU))) {
> + ret = -EFAULT;
> + goto bail;
> + }
> +
> + memmove(((POIRU)(reqs[i]))->ir_uuid, osb->uuid,
> + OCFS2_VOL_UUID_LEN);
> + reqs[i]->ir_flags |= OCFS2_INFO_FL_FILLED;
> +
> + if (copy_to_user(preq, reqs[i], sizeof(OIRU))) {
> + ret = -EFAULT;
> + goto bail;
> + }
> +
> + break;
> + case OCFS2_INFO_FS_FEATURES:
> + reqs[i] = kmalloc(sizeof(OIRF), GFP_KERNEL);
> +
> + if (copy_from_user(reqs[i], preq, sizeof(OIRF))) {
> + ret = -EFAULT;
> + goto bail;
> + }
> +
> + ((POIRF)(reqs[i]))->ir_compat_features =
> + osb->s_feature_compat;
> + ((POIRF)(reqs[i]))->ir_incompat_features =
> + osb->s_feature_incompat;
> + ((POIRF)(reqs[i]))->ir_ro_compat_features =
> + osb->s_feature_ro_compat;
> + reqs[i]->ir_flags |= OCFS2_INFO_FL_FILLED;
> +
> + if (copy_to_user(preq, reqs[i], sizeof(OIRF))) {
> + ret = -EFAULT;
> + goto bail;
> + }
> +
> + break;
> + default:
> + break;
> + }
> +
> + }
> +bail:
> + for (i = 0; i < num_reqs; i++)
> + kfree(reqs[i]);
> +
> + kfree(reqs);
> +
> + ocfs2_inode_unlock(inode, 0);
> +
> + mlog_exit(ret);
> + return ret;
> +}
> +
> long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> {
> struct inode *inode = filp->f_path.dentry->d_inode;
> @@ -173,6 +355,8 @@ 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:
> + return ocfs2_get_request_info(inode, arg);
> default:
> return -ENOTTY;
> }
More information about the Ocfs2-devel
mailing list