cdev.c

来自「基于linux-2.6.28的mtd驱动」· C语言 代码 · 共 1,011 行 · 第 1/2 页

C
1,011
字号
		if (lnum < 0 || lnum >= vol->reserved_pebs) {			err = -EINVAL;			break;		}		dbg_gen("erase LEB %d:%d", vol->vol_id, lnum);		err = ubi_eba_unmap_leb(ubi, vol, lnum);		if (err)			break;		err = ubi_wl_flush(ubi);		break;	}#endif	default:		err = -ENOTTY;		break;	}	return err;}/** * verify_mkvol_req - verify volume creation request. * @ubi: UBI device description object * @req: the request to check * * This function zero if the request is correct, and %-EINVAL if not. */static int verify_mkvol_req(const struct ubi_device *ubi,			    const struct ubi_mkvol_req *req){	int n, err = -EINVAL;	if (req->bytes < 0 || req->alignment < 0 || req->vol_type < 0 ||	    req->name_len < 0)		goto bad;	if ((req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots) &&	    req->vol_id != UBI_VOL_NUM_AUTO)		goto bad;	if (req->alignment == 0)		goto bad;	if (req->bytes == 0)		goto bad;	if (req->vol_type != UBI_DYNAMIC_VOLUME &&	    req->vol_type != UBI_STATIC_VOLUME)		goto bad;	if (req->alignment > ubi->leb_size)		goto bad;	n = req->alignment & (ubi->min_io_size - 1);	if (req->alignment != 1 && n)		goto bad;	if (req->name_len > UBI_VOL_NAME_MAX) {		err = -ENAMETOOLONG;		goto bad;	}	n = strnlen(req->name, req->name_len + 1);	if (n != req->name_len)		goto bad;	return 0;bad:	dbg_err("bad volume creation request");	ubi_dbg_dump_mkvol_req(req);	return err;}/** * verify_rsvol_req - verify volume re-size request. * @ubi: UBI device description object * @req: the request to check * * This function returns zero if the request is correct, and %-EINVAL if not. */static int verify_rsvol_req(const struct ubi_device *ubi,			    const struct ubi_rsvol_req *req){	if (req->bytes <= 0)		return -EINVAL;	if (req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots)		return -EINVAL;	return 0;}/** * rename_volumes - rename UBI volumes. * @ubi: UBI device description object * @req: volumes re-name request * * This is a helper function for the volume re-name IOCTL which validates the * the request, opens the volume and calls corresponding volumes management * function. Returns zero in case of success and a negative error code in case * of failure. */static int rename_volumes(struct ubi_device *ubi,			  struct ubi_rnvol_req *req){	int i, n, err;	struct list_head rename_list;	struct ubi_rename_entry *re, *re1;	if (req->count < 0 || req->count > UBI_MAX_RNVOL)		return -EINVAL;	if (req->count == 0)		return 0;	/* Validate volume IDs and names in the request */	for (i = 0; i < req->count; i++) {		if (req->ents[i].vol_id < 0 ||		    req->ents[i].vol_id >= ubi->vtbl_slots)			return -EINVAL;		if (req->ents[i].name_len < 0)			return -EINVAL;		if (req->ents[i].name_len > UBI_VOL_NAME_MAX)			return -ENAMETOOLONG;		req->ents[i].name[req->ents[i].name_len] = '\0';		n = strlen(req->ents[i].name);		if (n != req->ents[i].name_len)			err = -EINVAL;	}	/* Make sure volume IDs and names are unique */	for (i = 0; i < req->count - 1; i++) {		for (n = i + 1; n < req->count; n++) {			if (req->ents[i].vol_id == req->ents[n].vol_id) {				dbg_err("duplicated volume id %d",					req->ents[i].vol_id);				return -EINVAL;			}			if (!strcmp(req->ents[i].name, req->ents[n].name)) {				dbg_err("duplicated volume name \"%s\"",					req->ents[i].name);				return -EINVAL;			}		}	}	/* Create the re-name list */	INIT_LIST_HEAD(&rename_list);	for (i = 0; i < req->count; i++) {		int vol_id = req->ents[i].vol_id;		int name_len = req->ents[i].name_len;		const char *name = req->ents[i].name;		re = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL);		if (!re) {			err = -ENOMEM;			goto out_free;		}		re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE);		if (IS_ERR(re->desc)) {			err = PTR_ERR(re->desc);			dbg_err("cannot open volume %d, error %d", vol_id, err);			kfree(re);			goto out_free;		}		/* Skip this re-naming if the name does not really change */		if (re->desc->vol->name_len == name_len &&		    !memcmp(re->desc->vol->name, name, name_len)) {			ubi_close_volume(re->desc);			kfree(re);			continue;		}		re->new_name_len = name_len;		memcpy(re->new_name, name, name_len);		list_add_tail(&re->list, &rename_list);		dbg_msg("will rename volume %d from \"%s\" to \"%s\"",			vol_id, re->desc->vol->name, name);	}	if (list_empty(&rename_list))		return 0;	/* Find out the volumes which have to be removed */	list_for_each_entry(re, &rename_list, list) {		struct ubi_volume_desc *desc;		int no_remove_needed = 0;		/*		 * Volume @re->vol_id is going to be re-named to		 * @re->new_name, while its current name is @name. If a volume		 * with name @re->new_name currently exists, it has to be		 * removed, unless it is also re-named in the request (@req).		 */		list_for_each_entry(re1, &rename_list, list) {			if (re->new_name_len == re1->desc->vol->name_len &&			    !memcmp(re->new_name, re1->desc->vol->name,				    re1->desc->vol->name_len)) {				no_remove_needed = 1;				break;			}		}		if (no_remove_needed)			continue;		/*		 * It seems we need to remove volume with name @re->new_name,		 * if it exists.		 */		desc = ubi_open_volume_nm(ubi->ubi_num, re->new_name, UBI_EXCLUSIVE);		if (IS_ERR(desc)) {			err = PTR_ERR(desc);			if (err == -ENODEV)				/* Re-naming into a non-existing volume name */				continue;			/* The volume exists but busy, or an error occurred */			dbg_err("cannot open volume \"%s\", error %d",				re->new_name, err);			goto out_free;		}		re = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL);		if (!re) {			err = -ENOMEM;			ubi_close_volume(desc);			goto out_free;		}		re->remove = 1;		re->desc = desc;		list_add(&re->list, &rename_list);		dbg_msg("will remove volume %d, name \"%s\"",			re->desc->vol->vol_id, re->desc->vol->name);	}	mutex_lock(&ubi->volumes_mutex);	err = ubi_rename_volumes(ubi, &rename_list);	mutex_unlock(&ubi->volumes_mutex);out_free:	list_for_each_entry_safe(re, re1, &rename_list, list) {		ubi_close_volume(re->desc);		list_del(&re->list);		kfree(re);	}	return err;}static int ubi_cdev_ioctl(struct inode *inode, struct file *file,			  unsigned int cmd, unsigned long arg){	int err = 0;	struct ubi_device *ubi;	struct ubi_volume_desc *desc;	void __user *argp = (void __user *)arg;	if (!capable(CAP_SYS_RESOURCE))		return -EPERM;	ubi = ubi_get_by_major(imajor(inode));	if (!ubi)		return -ENODEV;	switch (cmd) {	/* Create volume command */	case UBI_IOCMKVOL:	{		struct ubi_mkvol_req req;		dbg_gen("create volume");		err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req));		if (err) {			err = -EFAULT;			break;		}		req.name[req.name_len] = '\0';		err = verify_mkvol_req(ubi, &req);		if (err)			break;		mutex_lock(&ubi->volumes_mutex);		err = ubi_create_volume(ubi, &req);		mutex_unlock(&ubi->volumes_mutex);		if (err)			break;		err = put_user(req.vol_id, (__user int32_t *)argp);		if (err)			err = -EFAULT;		break;	}	/* Remove volume command */	case UBI_IOCRMVOL:	{		int vol_id;		dbg_gen("remove volume");		err = get_user(vol_id, (__user int32_t *)argp);		if (err) {			err = -EFAULT;			break;		}		desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE);		if (IS_ERR(desc)) {			err = PTR_ERR(desc);			break;		}		mutex_lock(&ubi->volumes_mutex);		err = ubi_remove_volume(desc, 0);		mutex_unlock(&ubi->volumes_mutex);		/*		 * The volume is deleted (unless an error occurred), and the		 * 'struct ubi_volume' object will be freed when		 * 'ubi_close_volume()' will call 'put_device()'.		 */		ubi_close_volume(desc);		break;	}	/* Re-size volume command */	case UBI_IOCRSVOL:	{		int pebs;		uint64_t tmp;		struct ubi_rsvol_req req;		dbg_gen("re-size volume");		err = copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req));		if (err) {			err = -EFAULT;			break;		}		err = verify_rsvol_req(ubi, &req);		if (err)			break;		desc = ubi_open_volume(ubi->ubi_num, req.vol_id, UBI_EXCLUSIVE);		if (IS_ERR(desc)) {			err = PTR_ERR(desc);			break;		}		tmp = req.bytes;		pebs = !!do_div(tmp, desc->vol->usable_leb_size);		pebs += tmp;		mutex_lock(&ubi->volumes_mutex);		err = ubi_resize_volume(desc, pebs);		mutex_unlock(&ubi->volumes_mutex);		ubi_close_volume(desc);		break;	}	/* Re-name volumes command */	case UBI_IOCRNVOL:	{		struct ubi_rnvol_req *req;		dbg_msg("re-name volumes");		req = kmalloc(sizeof(struct ubi_rnvol_req), GFP_KERNEL);		if (!req) {			err = -ENOMEM;			break;		};		err = copy_from_user(req, argp, sizeof(struct ubi_rnvol_req));		if (err) {			err = -EFAULT;			kfree(req);			break;		}		mutex_lock(&ubi->mult_mutex);		err = rename_volumes(ubi, req);		mutex_unlock(&ubi->mult_mutex);		kfree(req);		break;	}	default:		err = -ENOTTY;		break;	}	ubi_put_device(ubi);	return err;}static int ctrl_cdev_ioctl(struct inode *inode, struct file *file,			   unsigned int cmd, unsigned long arg){	int err = 0;	void __user *argp = (void __user *)arg;	if (!capable(CAP_SYS_RESOURCE))		return -EPERM;	switch (cmd) {	/* Attach an MTD device command */	case UBI_IOCATT:	{		struct ubi_attach_req req;		struct mtd_info *mtd;		dbg_gen("attach MTD device");		err = copy_from_user(&req, argp, sizeof(struct ubi_attach_req));		if (err) {			err = -EFAULT;			break;		}		if (req.mtd_num < 0 ||		    (req.ubi_num < 0 && req.ubi_num != UBI_DEV_NUM_AUTO)) {			err = -EINVAL;			break;		}		mtd = get_mtd_device(NULL, req.mtd_num);		if (IS_ERR(mtd)) {			err = PTR_ERR(mtd);			break;		}		/*		 * Note, further request verification is done by		 * 'ubi_attach_mtd_dev()'.		 */		mutex_lock(&ubi_devices_mutex);		err = ubi_attach_mtd_dev(mtd, req.ubi_num, req.vid_hdr_offset);		mutex_unlock(&ubi_devices_mutex);		if (err < 0)			put_mtd_device(mtd);		else			/* @err contains UBI device number */			err = put_user(err, (__user int32_t *)argp);		break;	}	/* Detach an MTD device command */	case UBI_IOCDET:	{		int ubi_num;		dbg_gen("dettach MTD device");		err = get_user(ubi_num, (__user int32_t *)argp);		if (err) {			err = -EFAULT;			break;		}		mutex_lock(&ubi_devices_mutex);		err = ubi_detach_mtd_dev(ubi_num, 0);		mutex_unlock(&ubi_devices_mutex);		break;	}	default:		err = -ENOTTY;		break;	}	return err;}/* UBI control character device operations */struct file_operations ubi_ctrl_cdev_operations = {	.ioctl = ctrl_cdev_ioctl,	.owner = THIS_MODULE,};/* UBI character device operations */struct file_operations ubi_cdev_operations = {	.owner = THIS_MODULE,	.ioctl = ubi_cdev_ioctl,	.llseek = no_llseek,};/* UBI volume character device operations */struct file_operations ubi_vol_cdev_operations = {	.owner   = THIS_MODULE,	.open    = vol_cdev_open,	.release = vol_cdev_release,	.llseek  = vol_cdev_llseek,	.read    = vol_cdev_read,	.write   = vol_cdev_write,	.ioctl   = vol_cdev_ioctl,};

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?