/** * test_update - check volume update and atomic LEB change capabilities. * * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) * * This function returns %0 in case of success and %-1 in case of failure. */ static int test_update(int type) { struct ubi_mkvol_request req; const char *name = TESTNAME ":io_update()"; int alignments[] = ALIGNMENTS(dev_info.leb_size); struct ubi_vol_info vol_info; char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; unsigned int i; for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { int leb_size; req.vol_id = UBI_VOL_NUM_AUTO; req.vol_type = type; req.name = name; req.alignment = alignments[i]; req.alignment -= req.alignment % dev_info.min_io_size; if (req.alignment == 0) req.alignment = dev_info.min_io_size; leb_size = dev_info.leb_size - dev_info.leb_size % req.alignment; req.bytes = MIN_AVAIL_EBS * leb_size; if (ubi_mkvol(libubi, node, &req)) { failed("ubi_mkvol"); return -1; } sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id); if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { failed("ubi_get_vol_info"); goto remove; } if (test_update1(&vol_info, 0)) { err_msg("alignment = %d", req.alignment); goto remove; } if (vol_info.type != UBI_STATIC_VOLUME) { if (test_update1(&vol_info, 1)) { err_msg("alignment = %d", req.alignment); goto remove; } } if (ubi_rmvol(libubi, node, req.vol_id)) { failed("ubi_rmvol"); return -1; } } return 0; remove: ubi_rmvol(libubi, node, req.vol_id); return -1; }
/** * mkvol_multiple - test multiple volumes creation * * Thus function returns %0 if the test passed and %-1 if not. */ static int mkvol_multiple(void) { struct ubi_mkvol_request req; int i, ret, max = dev_info.max_vol_count; const char *name = PROGRAM_NAME ":mkvol_multiple()"; /* Create maximum number of volumes */ for (i = 0; i < max; i++) { char nm[strlen(name) + 50]; req.vol_id = UBI_VOL_NUM_AUTO; req.alignment = 1; req.bytes = 1; req.vol_type = UBI_STATIC_VOLUME; sprintf(nm, "%s:%d", name, i); req.name = nm; if (ubi_mkvol(libubi, node, &req)) { if (errno == ENFILE) { max = i; break; } failed("ubi_mkvol"); errorm("vol_id %d", i); goto remove; } if (check_volume(req.vol_id, &req)) { errorm("vol_id %d", i); goto remove; } } for (i = 0; i < max; i++) { struct ubi_vol_info vol_info; if (ubi_rmvol(libubi, node, i)) { failed("ubi_rmvol"); return -1; } /* Make sure volume does not exist */ ret = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info); if (ret == 0) { errorm("removed volume %d exists", i); goto remove; } } return 0; remove: for (i = 0; i < dev_info.max_vol_count + 1; i++) ubi_rmvol(libubi, node, i); return -1; }
/** * test_basic - check volume re-size capability. * * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) * * Thus function returns %0 in case of success and %-1 in case of failure. */ static int test_basic(int type) { struct ubi_mkvol_request req; const char *name = PROGRAM_NAME ":test_basic()"; req.vol_id = UBI_VOL_NUM_AUTO; req.alignment = 1; req.bytes = MIN_AVAIL_EBS * dev_info.leb_size; req.vol_type = type; req.name = name; if (ubi_mkvol(libubi, node, &req)) { failed("ubi_mkvol"); return -1; } req.bytes = dev_info.leb_size; if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) { failed("ubi_rsvol"); goto remove; } if (check_volume(req.vol_id, &req)) goto remove; req.bytes = (MIN_AVAIL_EBS + 1) * dev_info.leb_size; if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) { failed("ubi_rsvol"); goto remove; } if (check_volume(req.vol_id, &req)) goto remove; req.bytes -= 1; if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) { failed("ubi_rsvol"); goto remove; } if (check_volume(req.vol_id, &req)) goto remove; if (ubi_rmvol(libubi, node, req.vol_id)) { failed("ubi_rmvol"); return -1; } return 0; remove: ubi_rmvol(libubi, node, req.vol_id); return -1; }
/** * test_aligned - test volume alignment feature. * * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) * * Thus function returns %0 in case of success and %-1 in case of failure. */ static int test_aligned(int type) { unsigned int i, ebsz; struct ubi_mkvol_request req; const char *name = TESTNAME ":test_aligned()"; char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; int alignments[] = ALIGNMENTS(dev_info.leb_size); req.vol_type = type; req.name = name; for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { req.vol_id = UBI_VOL_NUM_AUTO; req.alignment = alignments[i]; req.alignment -= req.alignment % dev_info.min_io_size; if (req.alignment == 0) req.alignment = dev_info.min_io_size; ebsz = dev_info.leb_size - dev_info.leb_size % req.alignment; req.bytes = MIN_AVAIL_EBS * ebsz; if (ubi_mkvol(libubi, node, &req)) { failed("ubi_mkvol"); return -1; } sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id); /* Make sure newly created volume contains only 0xFF bytes */ if (check_vol_patt(vol_node, 0xFF)) goto remove; /* Write 0xA5 bytes to the volume */ if (update_vol_patt(vol_node, req.bytes, 0xA5)) goto remove; if (check_vol_patt(vol_node, 0xA5)) goto remove; if (ubi_rmvol(libubi, node, req.vol_id)) { failed("ubi_rmvol"); return -1; } } return 0; remove: ubi_rmvol(libubi, node, req.vol_id); return -1; }
/** * the_thread - the testing thread. * * @ptr thread number */ static void * the_thread(void *ptr) { int n = (long)ptr, iter = iterations; struct ubi_mkvol_request req; const char *name = TESTNAME ":the_thread()"; char nm[strlen(name) + 50]; req.alignment = 1; req.bytes = dev_info.avail_bytes/ITERATIONS; req.vol_type = UBI_DYNAMIC_VOLUME; sprintf(nm, "%s:%d", name, n); req.name = nm; while (iter--) { req.vol_id = UBI_VOL_NUM_AUTO; if (ubi_mkvol(libubi, node, &req)) { failed("ubi_mkvol"); return NULL; } if (ubi_rmvol(libubi, node, req.vol_id)) { failed("ubi_rmvol"); return NULL; } } return NULL; }
/** * mkvol_alignment - create volumes with different alignments. * * Thus function returns %0 in case of success and %-1 in case of failure. */ static int mkvol_alignment(void) { struct ubi_mkvol_request req; int i, vol_id, ebsz; const char *name = PROGRAM_NAME ":mkvol_alignment()"; int alignments[] = ALIGNMENTS(dev_info.leb_size); for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { req.vol_id = UBI_VOL_NUM_AUTO; /* Alignment should actually be multiple of min. I/O size */ req.alignment = alignments[i]; req.alignment -= req.alignment % dev_info.min_io_size; if (req.alignment == 0) req.alignment = dev_info.min_io_size; /* Bear in mind alignment reduces EB size */ ebsz = dev_info.leb_size - dev_info.leb_size % req.alignment; req.bytes = (long long)dev_info.avail_lebs * ebsz; req.vol_type = UBI_DYNAMIC_VOLUME; req.name = name; if (ubi_mkvol(libubi, node, &req)) { failed("ubi_mkvol"); errorm("alignment %d", req.alignment); return -1; } vol_id = req.vol_id; if (check_volume(vol_id, &req)) goto remove; if (ubi_rmvol(libubi, node, vol_id)) { failed("ubi_rmvol"); return -1; } } return 0; remove: ubi_rmvol(libubi, node, vol_id); return -1; }
/** * test_rmvol - test that UBI rmvol ioctl rejects bad input parameters. * * This function returns %0 if the test passed and %-1 if not. */ static int test_rmvol(void) { int ret; struct ubi_mkvol_request req; const char *name = TESTNAME ":test_rmvol()"; /* Bad vol_id */ ret = ubi_rmvol(libubi, node, -1); if (check_failed(ret, EINVAL, "ubi_rmvol", "vol_id = -1")) return -1; ret = ubi_rmvol(libubi, node, dev_info.max_vol_count); if (check_failed(ret, EINVAL, "ubi_rmvol", "vol_id = %d", dev_info.max_vol_count)) return -1; /* Try to remove non-existing volume */ ret = ubi_rmvol(libubi, node, 0); if (check_failed(ret, ENODEV, "ubi_rmvol", "removed non-existing volume 0")) return -1; /* Try to remove volume twice */ req.vol_id = UBI_VOL_NUM_AUTO; req.alignment = 1; req.bytes = dev_info.avail_bytes; req.vol_type = UBI_DYNAMIC_VOLUME; req.name = name; if (ubi_mkvol(libubi, node, &req)) { failed("ubi_mkvol"); return -1; } if (ubi_rmvol(libubi, node, req.vol_id)) { failed("ubi_rmvol"); return -1; } ret = ubi_rmvol(libubi, node, req.vol_id); if (check_failed(ret, ENODEV, "ubi_rmvol", "volume %d removed twice", req.vol_id)) return -1; return 0; }
/** * test_basic - check basic volume read and update capabilities. * * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) * * Thus function returns %0 in case of success and %-1 in case of failure. */ static int test_basic(int type) { struct ubi_mkvol_request req; const char *name = TESTNAME ":test_basic()"; char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; req.vol_id = UBI_VOL_NUM_AUTO; req.alignment = 1; req.bytes = dev_info.avail_bytes; req.vol_type = type; req.name = name; if (ubi_mkvol(libubi, node, &req)) { failed("ubi_mkvol"); return -1; } sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id); /* Make sure newly created volume contains only 0xFF bytes */ if (check_vol_patt(vol_node, 0xFF)) goto remove; /* Write 0xA5 bytes to the volume */ if (update_vol_patt(vol_node, dev_info.avail_bytes, 0xA5)) goto remove; if (check_vol_patt(vol_node, 0xA5)) goto remove; if (ubi_rmvol(libubi, node, req.vol_id)) { failed("ubi_rmvol"); return -1; } return 0; remove: ubi_rmvol(libubi, node, req.vol_id); return -1; }
/** * mkvol_basic - simple test that checks basic volume creation capability. * * Thus function returns %0 in case of success and %-1 in case of failure. */ static int mkvol_basic(void) { struct ubi_mkvol_request req; struct ubi_vol_info vol_info; int vol_id, ret; const char *name = PROGRAM_NAME ":mkvol_basic()"; /* Create dynamic volume of maximum size */ req.vol_id = UBI_VOL_NUM_AUTO; req.alignment = 1; req.bytes = dev_info.avail_bytes; req.vol_type = UBI_DYNAMIC_VOLUME; req.name = name; if (ubi_mkvol(libubi, node, &req)) { failed("ubi_mkvol"); return -1; } vol_id = req.vol_id; if (check_volume(vol_id, &req)) goto remove; if (ubi_rmvol(libubi, node, vol_id)) { failed("ubi_rmvol"); return -1; } /* Create static volume of maximum size */ req.vol_id = UBI_VOL_NUM_AUTO; req.alignment = 1; req.bytes = dev_info.avail_bytes; req.vol_type = UBI_STATIC_VOLUME; req.name = name; if (ubi_mkvol(libubi, node, &req)) { failed("ubi_mkvol"); return -1; } vol_id = req.vol_id; if (check_volume(vol_id, &req)) goto remove; if (ubi_rmvol(libubi, node, vol_id)) { failed("ubi_rmvol"); return -1; } /* Make sure volume does not exist */ ret = ubi_get_vol_info1(libubi, dev_info.dev_num, vol_id, &vol_info); if (ret == 0) { errorm("removed volume %d exists", vol_id); goto remove; } return 0; remove: ubi_rmvol(libubi, node, vol_id); return -1; }
int main(int argc, char * const argv[]) { int i, ret; pthread_t threads[THREADS_NUM]; struct ubi_mkvol_request req; long long mem_limit; if (initial_check(argc, argv)) return 1; node = argv[1]; libubi = libubi_open(); if (libubi == NULL) { failed("libubi_open"); return 1; } if (ubi_get_dev_info(libubi, node, &dev_info)) { failed("ubi_get_dev_info"); goto close; } req.alignment = 1; mem_limit = memory_limit(); if (mem_limit && mem_limit < dev_info.avail_bytes) total_bytes = req.bytes = (mem_limit / dev_info.eb_size / THREADS_NUM) * dev_info.eb_size; else total_bytes = req.bytes = ((dev_info.avail_ebs - 3) / THREADS_NUM) * dev_info.eb_size; for (i = 0; i < THREADS_NUM; i++) { char name[100]; req.vol_id = i; sprintf(&name[0], TESTNAME":%d", i); req.name = &name[0]; req.vol_type = (i & 1) ? UBI_STATIC_VOLUME : UBI_DYNAMIC_VOLUME; if (ubi_mkvol(libubi, node, &req)) { failed("ubi_mkvol"); goto remove; } } /* Create one volume with static data to make WL work more */ req.vol_id = THREADS_NUM; req.name = TESTNAME ":static"; req.vol_type = UBI_DYNAMIC_VOLUME; req.bytes = 3*dev_info.eb_size; if (ubi_mkvol(libubi, node, &req)) { failed("ubi_mkvol"); goto remove; } for (i = 0; i < THREADS_NUM; i++) { ret = pthread_create(&threads[i], NULL, &the_thread, (void*)i); if (ret) { failed("pthread_create"); goto remove; } } for (i = 0; i < THREADS_NUM; i++) pthread_join(threads[i], NULL); for (i = 0; i <= THREADS_NUM; i++) { if (ubi_rmvol(libubi, node, i)) { failed("ubi_rmvol"); goto remove; } } libubi_close(libubi); return 0; remove: for (i = 0; i <= THREADS_NUM; i++) ubi_rmvol(libubi, node, i); close: libubi_close(libubi); return 1; }
/** * test_mkvol - test that UBI mkvol ioctl rejects bad input parameters. * * This function returns %0 if the test passed and %-1 if not. */ static int test_mkvol(void) { int ret, i; struct ubi_mkvol_request req; const char *name = TESTNAME ":test_mkvol()"; req.alignment = 1; req.bytes = dev_info.avail_bytes; req.vol_type = UBI_DYNAMIC_VOLUME; req.name = name; /* Bad volume ID */ req.vol_id = -2; ret = ubi_mkvol(libubi, node, &req); if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_id = %d", req.vol_id)) return -1; req.vol_id = dev_info.max_vol_count; ret = ubi_mkvol(libubi, node, &req); if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_id = %d", req.vol_id)) return -1; /* Bad alignment */ req.vol_id = 0; req.alignment = 0; ret = ubi_mkvol(libubi, node, &req); if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", req.alignment)) return -1; req.alignment = -1; ret = ubi_mkvol(libubi, node, &req); if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", req.alignment)) return -1; req.alignment = dev_info.leb_size + 1; ret = ubi_mkvol(libubi, node, &req); if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", req.alignment)) return -1; if (dev_info.min_io_size > 1) { req.alignment = dev_info.min_io_size + 1; ret = ubi_mkvol(libubi, node, &req); if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", req.alignment)) return -1; } /* Bad bytes */ req.alignment = 1; req.bytes = -1; ret = ubi_mkvol(libubi, node, &req); if (check_failed(ret, EINVAL, "ubi_mkvol", "bytes = %lld", req.bytes)) return -1; req.bytes = 0; ret = ubi_mkvol(libubi, node, &req); if (check_failed(ret, EINVAL, "ubi_mkvol", "bytes = %lld", req.bytes)) return -1; req.bytes = dev_info.avail_bytes + 1; ret = ubi_mkvol(libubi, node, &req); if (check_failed(ret, ENOSPC, "ubi_mkvol", "bytes = %lld", req.bytes)) return -1; req.alignment = dev_info.leb_size - dev_info.min_io_size; req.bytes = (dev_info.leb_size - dev_info.leb_size % req.alignment) * dev_info.avail_lebs + 1; ret = ubi_mkvol(libubi, node, &req); if (check_failed(ret, ENOSPC, "ubi_mkvol", "bytes = %lld", req.bytes)) return -1; /* Bad vol_type */ req.alignment = 1; req.bytes = dev_info.leb_size; req.vol_type = UBI_DYNAMIC_VOLUME + UBI_STATIC_VOLUME; ret = ubi_mkvol(libubi, node, &req); if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_type = %d", req.vol_type)) return -1; req.vol_type = UBI_DYNAMIC_VOLUME; /* Too long name */ { char name[UBI_VOL_NAME_MAX + 5]; memset(name, 'x', UBI_VOL_NAME_MAX + 1); name[UBI_VOL_NAME_MAX + 1] = '\0'; req.name = name; ret = ubi_mkvol(libubi, node, &req); if (check_failed(ret, EINVAL, "ubi_mkvol", "name_len = %d", UBI_VOL_NAME_MAX + 1)) return -1; } /* Try to create 2 volumes with the same ID and name */ req.name = name; req.vol_id = 0; if (ubi_mkvol(libubi, node, &req)) { failed("ubi_mkvol"); return -1; } ret = ubi_mkvol(libubi, node, &req); if (check_failed(ret, EEXIST, "ubi_mkvol", "volume with ID 0 created twice")) return -1; req.vol_id = 1; ret = ubi_mkvol(libubi, node, &req); if (check_failed(ret, EEXIST, "ubi_mkvol", "volume with name \"%s\" created twice", name)) return -1; if (ubi_rmvol(libubi, node, 0)) { failed("ubi_rmvol"); return -1; } /* Try to use too much space */ req.vol_id = 0; req.bytes = dev_info.avail_bytes; if (ubi_mkvol(libubi, node, &req)) { failed("ubi_mkvol"); return -1; } req.bytes = 1; req.vol_id = 1; ret = ubi_mkvol(libubi, node, &req); if (check_failed(ret, EEXIST, "ubi_mkvol", "created volume of maximum size %lld, but still " "can create more volumes", dev_info.avail_bytes)) return -1; if (ubi_rmvol(libubi, node, 0)) { failed("ubi_rmvol"); return -1; } /* Try to create too many volumes */ for (i = 0; i < dev_info.max_vol_count; i++) { char nm[strlen(name) + 50]; req.vol_id = UBI_VOL_NUM_AUTO; req.alignment = 1; req.bytes = 1; req.vol_type = UBI_STATIC_VOLUME; sprintf(nm, "%s:%d", name, i); req.name = nm; if (ubi_mkvol(libubi, node, &req)) { /* * Note, because of gluebi we may be unable to create * dev_info.max_vol_count devices (MTD restrictions). */ if (errno == ENFILE) break; failed("ubi_mkvol"); err_msg("vol_id %d", i); goto remove; } } for (i = 0; i < dev_info.max_vol_count + 1; i++) ubi_rmvol(libubi, node, i); return 0; remove: for (i = 0; i < dev_info.max_vol_count + 1; i++) ubi_rmvol(libubi, node, i); return -1; }
/** * my_ubi_rmvol - a wrapper around the UBI library function ubi_rmvol * @devno UBI device number * @id UBI volume id to remove * * If the volume does not exist, the function will return success. * * Error handling: * when UBI system couldn't be opened * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err * when UBI system couldn't update (truncate) a volume * - returns -PFIFLASH_ERR_UBI_VOL_UPDATE, err_buf matches text to err * when UBI system couldn't remove a volume * - returns -PFIFLASH_ERR_UBI_RMVOL, err_buf matches text to err **/ static int my_ubi_rmvol(int devno, uint32_t id, char *err_buf, size_t err_buf_size) { int rc, fd; ubi_lib_t ulib; rc = 0; ulib = NULL; log_msg("[ ubirmvol id=%d", id); rc = ubi_open(&ulib); if (rc != 0) { rc = -PFIFLASH_ERR_UBI_OPEN; EBUF(PFIFLASH_ERRSTR[-rc]); goto err; } /* truncate whether it exist or not */ fd = ubi_vol_open(ulib, devno, id, O_RDWR); if (fd == -1) return 0; /* not existent, return 0 */ rc = ubi_vol_update(fd, 0); ubi_vol_close(fd); if (rc < 0) { rc = -PFIFLASH_ERR_UBI_VOL_UPDATE; EBUF(PFIFLASH_ERRSTR[-rc], id); goto err; /* if EBUSY than empty device, continue */ } rc = ubi_rmvol(ulib, devno, id); if (rc != 0) { #ifdef DEBUG int rc_old = rc; dbg_msg("Remove UBI volume %d returned with error: %d " "errno=%d", id, rc_old, errno); #endif rc = -PFIFLASH_ERR_UBI_RMVOL; EBUF(PFIFLASH_ERRSTR[-rc], id); /* TODO Define a ubi_rmvol return value which says * sth like EUBI_NOSUCHDEV. In this case, a failed * operation is acceptable. Everything else has to be * classified as real error. But talk to Andreas Arnez * before defining something odd... */ /* if ((errno == EINVAL) || (errno == ENODEV)) return 0; */ /* currently it is EINVAL or ENODEV */ goto err; } err: if (ulib != NULL) ubi_close(&ulib); return rc; }