/** * zfcp_sg_setup_table - init scatterlist and allocate, assign buffers * @sg: pointer to struct scatterlist * @count: number of scatterlists which should be assigned with buffers * of size page * * Returns: 0 on success, -ENOMEM otherwise */ int zfcp_sg_setup_table(struct scatterlist *sg, int count) { void *addr; int i; sg_init_table(sg, count); for (i = 0; i < count; i++, sg++) { addr = (void *) get_zeroed_page(GFP_KERNEL); if (!addr) { zfcp_sg_free_table(sg, i); return -ENOMEM; } sg_set_buf(sg, addr, PAGE_SIZE); } return 0; }
static int zfcp_cfdc_sg_setup(int command, struct scatterlist *sg, u8 __user *control_file) { int retval; retval = zfcp_sg_setup_table(sg, ZFCP_CFDC_PAGES); if (retval) return retval; sg[ZFCP_CFDC_PAGES - 1].length = ZFCP_CFDC_MAX_SIZE % PAGE_SIZE; if (command & ZFCP_CFDC_WITH_CONTROL_FILE && command & ZFCP_CFDC_DOWNLOAD) { retval = zfcp_cfdc_copy_from_user(sg, control_file); if (retval) { zfcp_sg_free_table(sg, ZFCP_CFDC_PAGES); return -EFAULT; } } return 0; }
static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, unsigned long arg) { struct zfcp_cfdc_data *data; struct zfcp_cfdc_data __user *data_user; struct zfcp_adapter *adapter; struct zfcp_fsf_req *req; struct zfcp_fsf_cfdc *fsf_cfdc; int retval; if (command != ZFCP_CFDC_IOC) return -ENOTTY; if (is_compat_task()) data_user = compat_ptr(arg); else data_user = (void __user *)arg; if (!data_user) return -EINVAL; fsf_cfdc = kmalloc(sizeof(struct zfcp_fsf_cfdc), GFP_KERNEL); if (!fsf_cfdc) return -ENOMEM; data = kmalloc(sizeof(struct zfcp_cfdc_data), GFP_KERNEL); if (!data) { retval = -ENOMEM; goto no_mem_sense; } retval = copy_from_user(data, data_user, sizeof(*data)); if (retval) { retval = -EFAULT; goto free_buffer; } if (data->signature != 0xCFDCACDF) { retval = -EINVAL; goto free_buffer; } retval = zfcp_cfdc_set_fsf(fsf_cfdc, data->command); adapter = zfcp_cfdc_get_adapter(data->devno); if (!adapter) { retval = -ENXIO; goto free_buffer; } retval = zfcp_cfdc_sg_setup(data->command, fsf_cfdc->sg, data_user->control_file); if (retval) goto adapter_put; req = zfcp_fsf_control_file(adapter, fsf_cfdc); if (IS_ERR(req)) { retval = PTR_ERR(req); goto free_sg; } if (req->status & ZFCP_STATUS_FSFREQ_ERROR) { retval = -ENXIO; goto free_fsf; } zfcp_cfdc_req_to_sense(data, req); retval = copy_to_user(data_user, data, sizeof(*data_user)); if (retval) { retval = -EFAULT; goto free_fsf; } if (data->command & ZFCP_CFDC_UPLOAD) retval = zfcp_cfdc_copy_to_user(&data_user->control_file, fsf_cfdc->sg); free_fsf: zfcp_fsf_req_free(req); free_sg: zfcp_sg_free_table(fsf_cfdc->sg, ZFCP_CFDC_PAGES); adapter_put: zfcp_ccw_adapter_put(adapter); free_buffer: kfree(data); no_mem_sense: kfree(fsf_cfdc); return retval; }