| // SPDX-License-Identifier: GPL-2.0 |
| // Author: Shaoxiong Li <dahefanteng@gmail.com> |
| |
| #include <stdbool.h> |
| #include <blkid.h> |
| #include <dirent.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| #include <stdio.h> |
| #include <fcntl.h> |
| #include <uuid.h> |
| #include <string.h> |
| #include <malloc.h> |
| #include <regex.h> |
| |
| #include "bcache.h" |
| #include "lib.h" |
| #include "bitwise.h" |
| /* |
| * utils function |
| */ |
| |
| static void trim_prefix(char *dest, char *src, int num) |
| { |
| strcpy(dest, src + num); |
| } |
| |
| static void get_tail(char *dest, char *src, int n) |
| { |
| int num, i; |
| |
| num = strlen(src); |
| for (i = 0; i < n; i++) |
| dest[i] = src[num - n + i]; |
| dest[i] = '\0'; |
| } |
| |
| static void get_tail_compoment(char *dest, char *src) |
| { |
| int num = strlen(src); |
| int i, index = 0; |
| |
| for (i = 0; i < num; i++) { |
| if (src[i] == '/') |
| index = i + 1; |
| } |
| strcpy(dest, src + index); |
| } |
| |
| static void trim_tail(char *src, int n) |
| { |
| int num; |
| |
| num = strlen(src); |
| src[num - n] = '\0'; |
| } |
| |
| bool prefix_with(char *dst, char *prefix) |
| { |
| int length = strlen(prefix); |
| |
| if (length > strlen(dst)) |
| return false; |
| int i; |
| |
| for (i = 0; i < length; i++) { |
| if (prefix[i] != dst[i]) |
| return false; |
| } |
| return true; |
| } |
| |
| bool part_of_disk(char *devname, char *partname) |
| { |
| char pattern[40]; |
| int status; |
| regmatch_t regmatche; |
| regex_t reg; |
| |
| sprintf(pattern, "^%s.*[0-9]$", devname); |
| if (regcomp(®, pattern, REG_EXTENDED) != 0) |
| fprintf(stderr, "Error happen when compile reg\n"); |
| status = regexec(®, partname, 1, ®matche, 0); |
| regfree(®); |
| if (status == REG_NOMATCH) |
| return false; |
| else |
| return true; |
| } |
| |
| int find_location(char *location, char *devname) |
| { |
| char path[300]; |
| DIR *blockdir, *bcachedir, *partdir = NULL; |
| struct dirent *ptr; |
| |
| blockdir = opendir("/sys/block"); |
| if (blockdir == NULL) { |
| fprintf(stderr, "Failed to open dir /sys/block/\n"); |
| return 1; |
| } |
| sprintf(path, "/sys/block/%s/bcache", devname); |
| bcachedir = opendir(path); |
| if (bcachedir != NULL) { |
| strcpy(location, devname); |
| closedir(bcachedir); |
| return 0; |
| } |
| while ((ptr = readdir(blockdir)) != NULL) { |
| if (prefix_with(devname, ptr->d_name)) { |
| sprintf(path, "/sys/block/%s/%s", ptr->d_name, |
| devname); |
| partdir = opendir(path); |
| if (partdir != NULL) { |
| sprintf(location, "%s/%s", ptr->d_name, |
| devname); |
| closedir(partdir); |
| break; |
| } |
| } |
| } |
| closedir(blockdir); |
| return 0; |
| } |
| |
| |
| int get_backdev_state(char *devname, char *state) |
| { |
| FILE *fd; |
| int ret; |
| char path[150]; |
| char location[100] = ""; |
| char buf[40]; |
| |
| trim_prefix(buf, devname, DEV_PREFIX_LEN); |
| ret = find_location(location, buf); |
| if (ret < 0) |
| return ret; |
| sprintf(path, "/sys/block/%s/bcache/state", location); |
| fd = fopen(path, "r"); |
| if (fd == NULL) { |
| strcpy(state, BCACHE_BASIC_STATE_INACTIVE); |
| return 0; |
| } |
| int i = 0; |
| |
| while ((state[i] = getc(fd)) != '\n') |
| i++; |
| state[i] = '\0'; |
| fclose(fd); |
| |
| int fd_run; |
| |
| sprintf(path, "/sys/block/%s/bcache/running", location); |
| fd_run = open(path, O_RDONLY); |
| if (fd_run < 0) { |
| fprintf(stderr, |
| "Failed to open %s\n", path); |
| return 1; |
| } |
| |
| char running[20]; |
| int num; |
| |
| num = read(fd_run, running, 10); |
| if (num < 0) { |
| fprintf(stderr, "Failed to fetch running infomation\n"); |
| close(fd_run); |
| return 1; |
| } |
| close(fd_run); |
| if (running[0] == '1') |
| strcat(state, "(running)"); |
| return 0; |
| } |
| |
| int get_cachedev_state(char *cset_id, char *state) |
| { |
| DIR *dir = NULL; |
| char path[100]; |
| |
| sprintf(path, "/sys/fs/bcache/%s/", cset_id); |
| dir = opendir(path); |
| if (dir == NULL) |
| strcpy(state, BCACHE_BASIC_STATE_INACTIVE); |
| else |
| strcpy(state, BCACHE_BASIC_STATE_ACTIVE); |
| closedir(dir); |
| return 0; |
| } |
| |
| int get_state(struct dev *dev, char *state) |
| { |
| if (dev->version == BCACHE_SB_VERSION_CDEV |
| || dev->version == BCACHE_SB_VERSION_CDEV_WITH_UUID) |
| return get_cachedev_state(dev->cset, state); |
| else if (dev->version == BCACHE_SB_VERSION_BDEV |
| || dev->version == BCACHE_SB_VERSION_BDEV_WITH_OFFSET) |
| return get_backdev_state(dev->name, state); |
| else |
| return 1; |
| } |
| |
| |
| int get_dev_bname(char *devname, char *bname) |
| { |
| int ret; |
| char path[150]; |
| char location[100] = ""; |
| char buf[40]; |
| char link[100]; |
| |
| trim_prefix(buf, devname, DEV_PREFIX_LEN); |
| ret = find_location(location, buf); |
| if (ret < 0) |
| return ret; |
| sprintf(path, "/sys/block/%s/bcache/dev", location); |
| ret = readlink(path, link, sizeof(link)); |
| if (ret < 0) |
| strcpy(bname, BCACHE_BNAME_NOT_EXIST); |
| else { |
| trim_tail(link, strlen(link) - ret); |
| get_tail_compoment(bname, link); |
| } |
| return 0; |
| } |
| |
| int get_bname(struct dev *dev, char *bname) |
| { |
| if (dev->version == BCACHE_SB_VERSION_CDEV |
| || dev->version == BCACHE_SB_VERSION_CDEV_WITH_UUID) |
| strcpy(bname, BCACHE_NO_SUPPORT); |
| else if (dev->version == BCACHE_SB_VERSION_BDEV |
| || dev->version == BCACHE_SB_VERSION_BDEV_WITH_OFFSET) |
| return get_dev_bname(dev->name, bname); |
| return 0; |
| } |
| |
| int get_backdev_attachpoint(char *devname, char *point) |
| { |
| int ret; |
| char path[150]; |
| char location[100] = ""; |
| char buf[20]; |
| char link[100]; |
| char uuid[40]; |
| |
| trim_prefix(buf, devname, DEV_PREFIX_LEN); |
| ret = find_location(location, buf); |
| if (ret < 0) |
| return ret; |
| sprintf(path, "/sys/block/%s/bcache/cache", location); |
| ret = readlink(path, link, sizeof(link)); |
| if (ret < 0) |
| strcpy(point, BCACHE_BNAME_NOT_EXIST); |
| else { |
| trim_tail(link, strlen(link) - ret); |
| get_tail(uuid, link, 36); |
| strcpy(point, uuid); |
| } |
| return 0; |
| } |
| |
| int get_point(struct dev *dev, char *point) |
| { |
| if (dev->version == BCACHE_SB_VERSION_CDEV |
| || dev->version == BCACHE_SB_VERSION_CDEV_WITH_UUID) |
| strcpy(point, BCACHE_NO_SUPPORT); |
| else if (dev->version == BCACHE_SB_VERSION_BDEV |
| || dev->version == BCACHE_SB_VERSION_BDEV_WITH_OFFSET) |
| return get_backdev_attachpoint(dev->name, point); |
| return 0; |
| } |
| |
| int cset_to_devname(struct list_head *head, char *cset, char *devname) |
| { |
| struct dev *dev; |
| |
| list_for_each_entry(dev, head, dev_list) { |
| if ((dev->version == BCACHE_SB_VERSION_CDEV |
| || dev->version == BCACHE_SB_VERSION_CDEV_WITH_UUID) |
| && strcmp(dev->cset, cset) == 0) |
| strcpy(devname, dev->name); |
| } |
| return 0; |
| } |
| |
| |
| int detail_base(char *devname, struct cache_sb sb, struct dev *base) |
| { |
| int ret; |
| |
| strcpy(base->name, devname); |
| base->magic = "ok"; |
| base->first_sector = SB_SECTOR; |
| base->version = sb.version; |
| |
| strncpy(base->label, (char *) sb.label, SB_LABEL_SIZE); |
| base->label[SB_LABEL_SIZE] = '\0'; |
| |
| uuid_unparse(sb.uuid, base->uuid); |
| uuid_unparse(sb.set_uuid, base->cset); |
| base->sectors_per_block = sb.block_size; |
| base->sectors_per_bucket = sb.bucket_size; |
| ret = get_state(base, base->state); |
| if (ret != 0) { |
| fprintf(stderr, "Failed to get state for %s\n", devname); |
| return ret; |
| } |
| ret = get_bname(base, base->bname); |
| if (ret != 0) { |
| fprintf(stderr, "Failed to get bname for %s\n", devname); |
| return ret; |
| } |
| ret = get_point(base, base->attachuuid); |
| if (ret != 0) { |
| fprintf(stderr, "Failed to get attachuuid for %s\n", |
| devname); |
| return ret; |
| } |
| return 0; |
| } |
| |
| |
| int may_add_item(char *devname, struct list_head *head) |
| { |
| struct cache_sb_disk sb_disk; |
| struct cache_sb sb; |
| |
| if (strcmp(devname, ".") == 0 || strcmp(devname, "..") == 0) |
| return 0; |
| char dev[261]; |
| |
| sprintf(dev, "/dev/%s", devname); |
| int fd = open(dev, O_RDONLY); |
| |
| if (fd == -1) |
| return 0; |
| if (pread(fd, &sb_disk, sizeof(sb_disk), SB_START) != sizeof(sb_disk)) { |
| close(fd); |
| return 0; |
| } |
| |
| to_cache_sb(&sb, &sb_disk); |
| |
| if (memcmp(sb.magic, bcache_magic, 16)) { |
| close(fd); |
| return 0; |
| } |
| struct dev *tmp; |
| int ret; |
| |
| tmp = (struct dev *) malloc(DEVLEN); |
| |
| tmp->csum = le64_to_cpu(sb_disk.csum); |
| ret = detail_base(dev, sb, tmp); |
| if (ret != 0) { |
| fprintf(stderr, "Failed to get information for %s\n", dev); |
| return 1; |
| } |
| list_add_tail(&tmp->dev_list, head); |
| return 0; |
| } |
| |
| int list_bdevs(struct list_head *head) |
| { |
| int ret; |
| DIR *dir, *subdir; |
| struct dirent *ptr, *subptr; |
| char path[300]; |
| |
| dir = opendir("/sys/block"); |
| if (dir == NULL) { |
| fprintf(stderr, "Unable to open dir /sys/block\n"); |
| return 1; |
| } |
| while ((ptr = readdir(dir)) != NULL) { |
| if (strcmp(ptr->d_name, ".") == 0 |
| || strcmp(ptr->d_name, "..") == 0) |
| continue; |
| sprintf(path, "/sys/block/%s", ptr->d_name); |
| subdir = opendir(path); |
| if (subdir == NULL) { |
| fprintf(stderr, "Unable to open dir /sys/block\n"); |
| return 1; |
| } |
| while ((subptr = readdir(subdir)) != NULL) { |
| if (strcmp(subptr->d_name, ".") == 0 |
| || strcmp(subptr->d_name, "..") == 0) |
| continue; |
| if (part_of_disk(ptr->d_name, subptr->d_name)) { |
| ret = may_add_item(subptr->d_name, head); |
| if (ret != 0) |
| return ret; |
| } |
| } |
| ret = may_add_item(ptr->d_name, head); |
| if (ret != 0) |
| return ret; |
| } |
| closedir(dir); |
| return 0; |
| } |
| |
| int detail_dev(char *devname, struct bdev *bd, struct cdev *cd, int *type) |
| { |
| struct cache_sb_disk sb_disk; |
| struct cache_sb sb; |
| uint64_t expected_csum; |
| int fd = open(devname, O_RDONLY); |
| |
| if (fd < 0) { |
| fprintf(stderr, "Error: Can't open dev %s\n", devname); |
| return 1; |
| } |
| |
| if (pread(fd, &sb_disk, sizeof(sb_disk), SB_START) != sizeof(sb_disk)) { |
| fprintf(stderr, "Couldn't read\n"); |
| goto Fail; |
| } |
| |
| to_cache_sb(&sb, &sb_disk); |
| |
| if (memcmp(sb.magic, bcache_magic, 16)) { |
| fprintf(stderr, |
| "Bad magic,make sure this is an bcache device\n"); |
| goto Fail; |
| } |
| |
| if (!(sb.offset == SB_SECTOR)) { |
| fprintf(stderr, "Invalid superblock (bad sector)\n"); |
| goto Fail; |
| } |
| |
| expected_csum = csum_set(&sb_disk); |
| if (le64_to_cpu(sb_disk.csum) != expected_csum) { |
| fprintf(stderr, "Csum is not match with expected one\n"); |
| goto Fail; |
| } |
| |
| *type = sb.version; |
| if (sb.version == BCACHE_SB_VERSION_BDEV) { |
| detail_base(devname, sb, &bd->base); |
| bd->first_sector = BDEV_DATA_START_DEFAULT; |
| bd->cache_mode = BDEV_CACHE_MODE(&sb); |
| bd->cache_state = BDEV_STATE(&sb); |
| } else if (sb.version == BCACHE_SB_VERSION_CDEV |
| || sb.version == BCACHE_SB_VERSION_CDEV_WITH_UUID) { |
| detail_base(devname, sb, &cd->base); |
| cd->first_sector = sb.bucket_size * sb.first_bucket; |
| cd->cache_sectors = |
| sb.bucket_size * (sb.nbuckets - sb.first_bucket); |
| cd->total_sectors = sb.bucket_size * sb.nbuckets; |
| cd->ordered = CACHE_SYNC(&sb); |
| cd->discard = CACHE_DISCARD(&sb); |
| cd->pos = sb.nr_this_dev; |
| cd->replacement = CACHE_REPLACEMENT(&sb); |
| } else { |
| fprintf(stderr, "Unknown bcache device type found\n"); |
| goto Fail; |
| } |
| return 0; |
| Fail: |
| close(fd); |
| return 1; |
| } |
| |
| int register_dev(char *devname) |
| { |
| int fd; |
| |
| fd = open("/sys/fs/bcache/register", O_WRONLY); |
| if (fd < 0) { |
| perror("Error opening /sys/fs/bcache/register"); |
| fprintf(stderr, |
| "The bcache kernel module must be loaded\n"); |
| return 1; |
| } |
| if (dprintf(fd, "%s\n", devname) < 0) { |
| fprintf(stderr, "Error registering %s with bcache: %m\n", |
| devname); |
| close(fd); |
| return 1; |
| } |
| close(fd); |
| return 0; |
| } |
| |
| int unregister_cset(char *cset) |
| { |
| int fd; |
| char path[100]; |
| |
| sprintf(path, "/sys/fs/bcache/%s/unregister", cset); |
| fd = open(path, O_WRONLY); |
| if (fd < 0) { |
| fprintf(stderr, "Can't open %s\n", path); |
| return 1; |
| } |
| if (dprintf(fd, "%d\n", 1) < 0) { |
| fprintf(stderr, "Failed to unregister this cache device\n"); |
| close(fd); |
| return 1; |
| } |
| close(fd); |
| return 0; |
| } |
| |
| int stop_backdev(char *devname) |
| { |
| char path[150]; |
| char location[100] = ""; |
| int fd, ret; |
| char buf[20]; |
| |
| trim_prefix(buf, devname, DEV_PREFIX_LEN); |
| ret = find_location(location, buf); |
| if (ret < 0) |
| return ret; |
| sprintf(path, "/sys/block/%s/bcache/stop", location); |
| fd = open(path, O_WRONLY); |
| if (fd < 0) { |
| fprintf(stderr, "Can't open %s\n", path); |
| return 1; |
| } |
| if (dprintf(fd, "%s\n", "1") < 0) { |
| fprintf(stderr, "Error stop back device %s\n", devname); |
| close(fd); |
| return 1; |
| } |
| close(fd); |
| return 0; |
| } |
| |
| //preserved for future use |
| int unregister_both(char *cset) |
| { |
| int fd; |
| char path[100]; |
| |
| sprintf(path, "/sys/fs/bcache/%s/stop", cset); |
| fd = open(path, O_WRONLY); |
| if (fd < 0) { |
| fprintf(stderr, "Can't open %s\n", path); |
| return 1; |
| } |
| if (dprintf(fd, "%d\n", 1) < 0) { |
| fprintf(stderr, "Failed to stop cset and its backends %m\n"); |
| close(fd); |
| return 1; |
| } |
| close(fd); |
| return 0; |
| } |
| |
| int attach_backdev(char *cset, char *devname) |
| { |
| int fd, ret; |
| char buf[20]; |
| char location[100] = ""; |
| char path[150]; |
| |
| trim_prefix(buf, devname, DEV_PREFIX_LEN); |
| ret = find_location(location, buf); |
| if (ret < 0) |
| return ret; |
| sprintf(path, "/sys/block/%s/bcache/attach", location); |
| fd = open(path, O_WRONLY); |
| if (fd < 0) { |
| fprintf(stderr, "Can't open %s:%m\n", path); |
| return 1; |
| } |
| if (dprintf(fd, "%s\n", cset) < 0) { |
| fprintf(stderr, "Failed to attache to cset %s\n", cset); |
| close(fd); |
| return 1; |
| } |
| close(fd); |
| return 0; |
| } |
| |
| int detach_backdev(char *devname) |
| { |
| int fd, ret; |
| char buf[20]; |
| char path[150]; |
| char location[100] = ""; |
| |
| trim_prefix(buf, devname, DEV_PREFIX_LEN); |
| ret = find_location(location, buf); |
| if (ret < 0) |
| return ret; |
| sprintf(path, "/sys/block/%s/bcache/detach", location); |
| fd = open(path, O_WRONLY); |
| if (fd < 0) { |
| fprintf(stderr, |
| "Can't open %s,Make sure the device name is correct\n", |
| path); |
| return 1; |
| } |
| if (dprintf(fd, "%d\n", 1) < 0) { |
| close(fd); |
| fprintf(stderr, "Error detach device %s:%m\n", devname); |
| return 1; |
| } |
| close(fd); |
| return 0; |
| } |
| |
| int set_backdev_cachemode(char *devname, char *cachemode) |
| { |
| int fd, ret; |
| char path[150]; |
| char location[100] = ""; |
| char buf[20]; |
| |
| trim_prefix(buf, devname, DEV_PREFIX_LEN); |
| ret = find_location(location, buf); |
| if (ret < 0) |
| return ret; |
| sprintf(path, "/sys/block/%s/bcache/cache_mode", location); |
| fd = open(path, O_WRONLY); |
| if (fd < 0) { |
| fprintf(stderr, |
| "Can't open %s,Make sure the device name is correct\n", |
| path); |
| return 1; |
| } |
| if (dprintf(fd, "%s\n", cachemode) < 0) { |
| fprintf(stderr, "Failed to set cachemode for device %s:%m\n", |
| devname); |
| close(fd); |
| return 1; |
| } |
| close(fd); |
| return 0; |
| } |
| |
| int get_backdev_cachemode(char *devname, char *mode) |
| { |
| int fd, ret; |
| char path[150]; |
| char location[100] = ""; |
| |
| ret = find_location(location, devname); |
| if (ret < 0) |
| return ret; |
| sprintf(path, "/sys/block/%s/bcache/cache_mode", location); |
| fd = open(path, O_RDONLY); |
| if (fd < 0) { |
| perror("Error opening /sys/fs/bcache/register"); |
| fprintf(stderr, |
| "The bcache kernel module must be loaded\n"); |
| return 1; |
| } |
| if (read(fd, mode, 100) < 0) { |
| fprintf(stderr, "Failed to fetch device cache mode\n"); |
| close(fd); |
| return 1; |
| } |
| close(fd); |
| return 0; |
| } |
| |
| int set_label(char *devname, char *label) |
| { |
| int fd, ret; |
| char path[150]; |
| char location[100] = ""; |
| char buf[20]; |
| |
| trim_prefix(buf, devname, DEV_PREFIX_LEN); |
| ret = find_location(location, buf); |
| if (ret < 0) |
| return ret; |
| sprintf(path, "/sys/block/%s/bcache/label", location); |
| fd = open(path, O_WRONLY); |
| if (fd < 0) { |
| fprintf(stderr, |
| "Please register this device first\n"); |
| return 1; |
| } |
| if (dprintf(fd, "%s\n", label) < 0) { |
| fprintf(stderr, "Failed to set label for device %s:%m\n", |
| devname); |
| close(fd); |
| return 1; |
| } |
| close(fd); |
| return 0; |
| } |
| |
| |
| struct cache_sb *to_cache_sb(struct cache_sb *sb, |
| struct cache_sb_disk *sb_disk) |
| { |
| /* Convert common part */ |
| sb->offset = le64_to_cpu(sb_disk->offset); |
| sb->version = le64_to_cpu(sb_disk->version); |
| memcpy(sb->magic, sb_disk->magic, 16); |
| memcpy(sb->uuid, sb_disk->uuid, 16); |
| memcpy(sb->set_uuid, sb_disk->set_uuid, 16); |
| memcpy(sb->label, sb_disk->label, SB_LABEL_SIZE); |
| sb->flags = le64_to_cpu(sb_disk->flags); |
| sb->seq = le64_to_cpu(sb_disk->seq); |
| sb->block_size = le16_to_cpu(sb_disk->block_size); |
| sb->last_mount = le32_to_cpu(sb_disk->last_mount); |
| sb->first_bucket = le16_to_cpu(sb_disk->first_bucket); |
| sb->keys = le16_to_cpu(sb_disk->keys); |
| |
| /* For cache or backing devices*/ |
| |
| if (sb->version > BCACHE_SB_MAX_VERSION) { |
| /* Unsupported version */ |
| fprintf(stderr, "Unsupported super block version: %lld\n", |
| sb->version); |
| } else if (SB_IS_BDEV(sb)) { |
| /* Backing device */ |
| sb->data_offset = le64_to_cpu(sb_disk->data_offset); |
| } else { |
| int i; |
| |
| /* Cache device */ |
| sb->nbuckets = le64_to_cpu(sb_disk->nbuckets); |
| sb->nr_in_set = le16_to_cpu(sb_disk->nr_in_set); |
| sb->nr_this_dev = le16_to_cpu(sb_disk->nr_this_dev); |
| sb->bucket_size = le32_to_cpu(sb_disk->bucket_size); |
| |
| for (i = 0; i < SB_JOURNAL_BUCKETS; i++) |
| sb->d[i]= le64_to_cpu(sb_disk->d[i]); |
| } |
| |
| return sb; |
| } |
| |
| struct cache_sb_disk *to_cache_sb_disk(struct cache_sb_disk *sb_disk, |
| struct cache_sb *sb) |
| { |
| /* Convert common part */ |
| sb_disk->offset = cpu_to_le64(sb->offset); |
| sb_disk->version = cpu_to_le64(sb->version); |
| memcpy(sb_disk->magic, sb->magic, 16); |
| memcpy(sb_disk->uuid, sb->uuid, 16); |
| memcpy(sb_disk->set_uuid, sb->set_uuid, 16); |
| memcpy(sb_disk->label, sb->label, SB_LABEL_SIZE); |
| sb_disk->flags = cpu_to_le64(sb->flags); |
| sb_disk->seq = cpu_to_le64(sb->seq); |
| sb_disk->block_size = cpu_to_le16(sb->block_size); |
| sb_disk->last_mount = cpu_to_le32(sb->last_mount); |
| sb_disk->first_bucket = cpu_to_le16(sb->first_bucket); |
| sb_disk->keys = cpu_to_le16(sb->keys); |
| |
| /* For cache and backing devices */ |
| |
| if (sb->version > BCACHE_SB_MAX_VERSION) { |
| /* Unsupported version */ |
| fprintf(stderr, "Unsupported super block version: %lld\n", |
| sb->version); |
| } else if (SB_IS_BDEV(sb)) { |
| /* Backing device */ |
| sb_disk->data_offset = cpu_to_le64(sb->data_offset); |
| } else { |
| int i; |
| |
| /* Cache device */ |
| sb_disk->nbuckets = cpu_to_le64(sb->nbuckets); |
| sb_disk->nr_in_set = cpu_to_le16(sb->nr_in_set); |
| sb_disk->nr_this_dev = cpu_to_le16(sb->nr_this_dev); |
| sb_disk->bucket_size = cpu_to_le32(sb->bucket_size); |
| |
| for (i = 0; i < SB_JOURNAL_BUCKETS; i++) |
| sb_disk->d[i] = cpu_to_le64(sb->d[i]); |
| } |
| |
| return sb_disk; |
| } |