^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * dcssblk.c -- the S/390 block driver for dcss memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Authors: Carsten Otte, Stefan Weinhuber, Gerald Schaefer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #define KMSG_COMPONENT "dcssblk"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/blkdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/completion.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/pfn_t.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/uio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/dax.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <asm/extmem.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define DCSSBLK_NAME "dcssblk"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define DCSSBLK_MINORS_PER_DISK 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define DCSSBLK_PARM_LEN 400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define DCSS_BUS_ID_SIZE 20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static int dcssblk_open(struct block_device *bdev, fmode_t mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static void dcssblk_release(struct gendisk *disk, fmode_t mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static blk_qc_t dcssblk_submit_bio(struct bio *bio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static long dcssblk_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) long nr_pages, void **kaddr, pfn_t *pfn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static int dcssblk_major;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static const struct block_device_operations dcssblk_devops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) .submit_bio = dcssblk_submit_bio,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) .open = dcssblk_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) .release = dcssblk_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static size_t dcssblk_dax_copy_from_iter(struct dax_device *dax_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return copy_from_iter(addr, bytes, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static size_t dcssblk_dax_copy_to_iter(struct dax_device *dax_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return copy_to_iter(addr, bytes, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static int dcssblk_dax_zero_page_range(struct dax_device *dax_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) pgoff_t pgoff, size_t nr_pages)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) long rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) void *kaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) rc = dax_direct_access(dax_dev, pgoff, nr_pages, &kaddr, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) memset(kaddr, 0, nr_pages << PAGE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) dax_flush(dax_dev, kaddr, nr_pages << PAGE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static const struct dax_operations dcssblk_dax_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) .direct_access = dcssblk_dax_direct_access,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) .dax_supported = generic_fsdax_supported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) .copy_from_iter = dcssblk_dax_copy_from_iter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .copy_to_iter = dcssblk_dax_copy_to_iter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) .zero_page_range = dcssblk_dax_zero_page_range,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct dcssblk_dev_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct list_head lh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct device dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) char segment_name[DCSS_BUS_ID_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) atomic_t use_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct gendisk *gd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) unsigned long start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) unsigned long end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) int segment_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) unsigned char save_pending;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) unsigned char is_shared;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct request_queue *dcssblk_queue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) int num_of_segments;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct list_head seg_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) struct dax_device *dax_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) struct segment_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct list_head lh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) char segment_name[DCSS_BUS_ID_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) unsigned long start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) unsigned long end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) int segment_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) size_t count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) size_t count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static struct device *dcssblk_root_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static LIST_HEAD(dcssblk_devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static struct rw_semaphore dcssblk_devices_sem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * release function for segment device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) dcssblk_release_segment(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct dcssblk_dev_info *dev_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) struct segment_info *entry, *temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) dev_info = container_of(dev, struct dcssblk_dev_info, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) list_for_each_entry_safe(entry, temp, &dev_info->seg_list, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) list_del(&entry->lh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) kfree(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) kfree(dev_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) module_put(THIS_MODULE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * get a minor number. needs to be called with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * down_write(&dcssblk_devices_sem) and the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * device needs to be enqueued before the semaphore is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * freed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) int minor, found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) struct dcssblk_dev_info *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (dev_info == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) for (minor = 0; minor < (1<<MINORBITS); minor++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) found = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) // test if minor available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) list_for_each_entry(entry, &dcssblk_devices, lh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (minor == entry->gd->first_minor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) found++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (!found) break; // got unused minor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (found)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) dev_info->gd->first_minor = minor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * get the struct dcssblk_dev_info from dcssblk_devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * for the given name.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * down_read(&dcssblk_devices_sem) must be held.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static struct dcssblk_dev_info *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) dcssblk_get_device_by_name(char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) struct dcssblk_dev_info *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) list_for_each_entry(entry, &dcssblk_devices, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (!strcmp(name, entry->segment_name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) return entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * get the struct segment_info from seg_list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * for the given name.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * down_read(&dcssblk_devices_sem) must be held.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) static struct segment_info *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) dcssblk_get_segment_by_name(char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct dcssblk_dev_info *dev_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) struct segment_info *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) list_for_each_entry(dev_info, &dcssblk_devices, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) list_for_each_entry(entry, &dev_info->seg_list, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (!strcmp(name, entry->segment_name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * get the highest address of the multi-segment block.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) static unsigned long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) dcssblk_find_highest_addr(struct dcssblk_dev_info *dev_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) unsigned long highest_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) struct segment_info *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) highest_addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) list_for_each_entry(entry, &dev_info->seg_list, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if (highest_addr < entry->end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) highest_addr = entry->end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) return highest_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) * get the lowest address of the multi-segment block.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) static unsigned long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) dcssblk_find_lowest_addr(struct dcssblk_dev_info *dev_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) int set_first;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) unsigned long lowest_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) struct segment_info *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) set_first = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) lowest_addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) list_for_each_entry(entry, &dev_info->seg_list, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (set_first == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) lowest_addr = entry->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) set_first = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (lowest_addr > entry->start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) lowest_addr = entry->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return lowest_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) * Check continuity of segments.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) dcssblk_is_continuous(struct dcssblk_dev_info *dev_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) int i, j, rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) struct segment_info *sort_list, *entry, temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (dev_info->num_of_segments <= 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) sort_list = kcalloc(dev_info->num_of_segments,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) sizeof(struct segment_info),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (sort_list == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) list_for_each_entry(entry, &dev_info->seg_list, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) memcpy(&sort_list[i], entry, sizeof(struct segment_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) /* sort segments */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) for (i = 0; i < dev_info->num_of_segments; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) for (j = 0; j < dev_info->num_of_segments; j++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (sort_list[j].start > sort_list[i].start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) memcpy(&temp, &sort_list[i],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) sizeof(struct segment_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) memcpy(&sort_list[i], &sort_list[j],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) sizeof(struct segment_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) memcpy(&sort_list[j], &temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) sizeof(struct segment_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) /* check continuity */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) for (i = 0; i < dev_info->num_of_segments - 1; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if ((sort_list[i].end + 1) != sort_list[i+1].start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) pr_err("Adjacent DCSSs %s and %s are not "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) "contiguous\n", sort_list[i].segment_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) sort_list[i+1].segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /* EN and EW are allowed in a block device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (sort_list[i].segment_type != sort_list[i+1].segment_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) if (!(sort_list[i].segment_type & SEGMENT_EXCLUSIVE) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) (sort_list[i].segment_type == SEG_TYPE_ER) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) !(sort_list[i+1].segment_type &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) SEGMENT_EXCLUSIVE) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) (sort_list[i+1].segment_type == SEG_TYPE_ER)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) pr_err("DCSS %s and DCSS %s have "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) "incompatible types\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) sort_list[i].segment_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) sort_list[i+1].segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) kfree(sort_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) * Load a segment
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) dcssblk_load_segment(char *name, struct segment_info **seg_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) /* already loaded? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) down_read(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) *seg_info = dcssblk_get_segment_by_name(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) up_read(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) if (*seg_info != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) /* get a struct segment_info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) *seg_info = kzalloc(sizeof(struct segment_info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (*seg_info == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) strcpy((*seg_info)->segment_name, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) /* load the segment */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) rc = segment_load(name, SEGMENT_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) &(*seg_info)->start, &(*seg_info)->end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) segment_warning(rc, (*seg_info)->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) kfree(*seg_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) INIT_LIST_HEAD(&(*seg_info)->lh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) (*seg_info)->segment_type = rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) * device attribute for switching shared/nonshared (exclusive)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) * operation (show + store)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) struct dcssblk_dev_info *dev_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) dev_info = container_of(dev, struct dcssblk_dev_info, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) return sprintf(buf, dev_info->is_shared ? "1\n" : "0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) struct dcssblk_dev_info *dev_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) struct segment_info *entry, *temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) down_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) dev_info = container_of(dev, struct dcssblk_dev_info, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (atomic_read(&dev_info->use_count)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) rc = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) if (inbuf[0] == '1') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) /* reload segments in shared mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) list_for_each_entry(entry, &dev_info->seg_list, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) rc = segment_modify_shared(entry->segment_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) SEGMENT_SHARED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) BUG_ON(rc == -EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) if (rc != -EAGAIN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) goto removeseg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) dev_info->is_shared = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) switch (dev_info->segment_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) case SEG_TYPE_SR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) case SEG_TYPE_ER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) case SEG_TYPE_SC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) set_disk_ro(dev_info->gd, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) } else if (inbuf[0] == '0') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) /* reload segments in exclusive mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (dev_info->segment_type == SEG_TYPE_SC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) pr_err("DCSS %s is of type SC and cannot be "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) "loaded as exclusive-writable\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) dev_info->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) list_for_each_entry(entry, &dev_info->seg_list, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) rc = segment_modify_shared(entry->segment_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) SEGMENT_EXCLUSIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) BUG_ON(rc == -EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) if (rc != -EAGAIN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) goto removeseg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) dev_info->is_shared = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) set_disk_ro(dev_info->gd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) rc = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) removeseg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) pr_err("DCSS device %s is removed after a failed access mode "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) "change\n", dev_info->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) temp = entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) list_for_each_entry(entry, &dev_info->seg_list, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (entry != temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) segment_unload(entry->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) list_del(&dev_info->lh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) kill_dax(dev_info->dax_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) put_dax(dev_info->dax_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) del_gendisk(dev_info->gd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) blk_cleanup_queue(dev_info->dcssblk_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) dev_info->gd->queue = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) put_disk(dev_info->gd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) up_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) if (device_remove_file_self(dev, attr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) device_unregister(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) put_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) up_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) dcssblk_shared_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) * device attribute for save operation on current copy
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) * of the segment. If the segment is busy, saving will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * become pending until it gets released, which can be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) * undone by storing a non-true value to this entry.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) * (show + store)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) struct dcssblk_dev_info *dev_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) dev_info = container_of(dev, struct dcssblk_dev_info, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) return sprintf(buf, dev_info->save_pending ? "1\n" : "0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) struct dcssblk_dev_info *dev_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) struct segment_info *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) dev_info = container_of(dev, struct dcssblk_dev_info, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) down_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) if (inbuf[0] == '1') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) if (atomic_read(&dev_info->use_count) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) // device is idle => we save immediately
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) pr_info("All DCSSs that map to device %s are "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) "saved\n", dev_info->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) list_for_each_entry(entry, &dev_info->seg_list, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) if (entry->segment_type == SEG_TYPE_EN ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) entry->segment_type == SEG_TYPE_SN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) pr_warn("DCSS %s is of type SN or EN"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) " and cannot be saved\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) entry->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) segment_save(entry->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) // device is busy => we save it when it becomes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) // idle in dcssblk_release
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) pr_info("Device %s is in use, its DCSSs will be "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) "saved when it becomes idle\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) dev_info->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) dev_info->save_pending = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) } else if (inbuf[0] == '0') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (dev_info->save_pending) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) // device is busy & the user wants to undo his save
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) // request
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) dev_info->save_pending = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) pr_info("A pending save request for device %s "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) "has been canceled\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) dev_info->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) up_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) up_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) dcssblk_save_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) * device attribute for showing all segments in a device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) dcssblk_seglist_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) struct dcssblk_dev_info *dev_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) struct segment_info *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) down_read(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) dev_info = container_of(dev, struct dcssblk_dev_info, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) buf[0] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) list_for_each_entry(entry, &dev_info->seg_list, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) strcpy(&buf[i], entry->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) i += strlen(entry->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) buf[i] = '\n';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) up_read(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) static struct attribute *dcssblk_dev_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) &dev_attr_shared.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) &dev_attr_save.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) &dev_attr_seglist.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) static struct attribute_group dcssblk_dev_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) .attrs = dcssblk_dev_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) static const struct attribute_group *dcssblk_dev_attr_groups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) &dcssblk_dev_attr_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) * device attribute for adding devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) int rc, i, j, num_of_segments;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) struct dcssblk_dev_info *dev_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) struct segment_info *seg_info, *temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) char *local_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) unsigned long seg_byte_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) dev_info = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) seg_info = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) if (dev != dcssblk_root_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) goto out_nobuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if ((count < 1) || (buf[0] == '\0') || (buf[0] == '\n')) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) rc = -ENAMETOOLONG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) goto out_nobuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) local_buf = kmalloc(count + 1, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) if (local_buf == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) goto out_nobuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) * parse input
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) num_of_segments = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) for (i = 0; (i < count && (buf[i] != '\0') && (buf[i] != '\n')); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) for (j = i; j < count &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) (buf[j] != ':') &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) (buf[j] != '\0') &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) (buf[j] != '\n'); j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) local_buf[j-i] = toupper(buf[j]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) local_buf[j-i] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) if (((j - i) == 0) || ((j - i) > 8)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) rc = -ENAMETOOLONG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) goto seg_list_del;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) rc = dcssblk_load_segment(local_buf, &seg_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) goto seg_list_del;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) * get a struct dcssblk_dev_info
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) if (num_of_segments == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) dev_info = kzalloc(sizeof(struct dcssblk_dev_info),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) if (dev_info == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) strcpy(dev_info->segment_name, local_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) dev_info->segment_type = seg_info->segment_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) INIT_LIST_HEAD(&dev_info->seg_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) list_add_tail(&seg_info->lh, &dev_info->seg_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) num_of_segments++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) i = j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) if ((buf[j] == '\0') || (buf[j] == '\n'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) /* no trailing colon at the end of the input */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) if ((i > 0) && (buf[i-1] == ':')) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) rc = -ENAMETOOLONG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) goto seg_list_del;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) strlcpy(local_buf, buf, i + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) dev_info->num_of_segments = num_of_segments;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) rc = dcssblk_is_continuous(dev_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) goto seg_list_del;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) dev_info->start = dcssblk_find_lowest_addr(dev_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) dev_info->end = dcssblk_find_highest_addr(dev_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) dev_set_name(&dev_info->dev, "%s", dev_info->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) dev_info->dev.release = dcssblk_release_segment;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) dev_info->dev.groups = dcssblk_dev_attr_groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) INIT_LIST_HEAD(&dev_info->lh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) if (dev_info->gd == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) goto seg_list_del;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) dev_info->gd->major = dcssblk_major;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) dev_info->gd->fops = &dcssblk_devops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) dev_info->dcssblk_queue = blk_alloc_queue(NUMA_NO_NODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) dev_info->gd->queue = dev_info->dcssblk_queue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) dev_info->gd->private_data = dev_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) blk_queue_logical_block_size(dev_info->dcssblk_queue, 4096);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) blk_queue_flag_set(QUEUE_FLAG_DAX, dev_info->dcssblk_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) seg_byte_size = (dev_info->end - dev_info->start + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) pr_info("Loaded %s with total size %lu bytes and capacity %lu "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) "sectors\n", local_buf, seg_byte_size, seg_byte_size >> 9);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) dev_info->save_pending = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) dev_info->is_shared = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) dev_info->dev.parent = dcssblk_root_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) *get minor, add to list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) down_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) if (dcssblk_get_segment_by_name(local_buf)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) rc = -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) goto release_gd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) rc = dcssblk_assign_free_minor(dev_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) goto release_gd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) sprintf(dev_info->gd->disk_name, "dcssblk%d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) dev_info->gd->first_minor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) list_add_tail(&dev_info->lh, &dcssblk_devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) if (!try_module_get(THIS_MODULE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) rc = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) goto dev_list_del;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) * register the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) rc = device_register(&dev_info->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) goto put_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) dev_info->dax_dev = alloc_dax(dev_info, dev_info->gd->disk_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) &dcssblk_dax_ops, DAXDEV_F_SYNC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) if (IS_ERR(dev_info->dax_dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) rc = PTR_ERR(dev_info->dax_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) dev_info->dax_dev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) goto put_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) get_device(&dev_info->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) device_add_disk(&dev_info->dev, dev_info->gd, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) switch (dev_info->segment_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) case SEG_TYPE_SR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) case SEG_TYPE_ER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) case SEG_TYPE_SC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) set_disk_ro(dev_info->gd,1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) set_disk_ro(dev_info->gd,0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) up_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) rc = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) put_dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) list_del(&dev_info->lh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) blk_cleanup_queue(dev_info->dcssblk_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) dev_info->gd->queue = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) put_disk(dev_info->gd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) list_for_each_entry(seg_info, &dev_info->seg_list, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) segment_unload(seg_info->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) put_device(&dev_info->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) up_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) dev_list_del:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) list_del(&dev_info->lh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) release_gd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) blk_cleanup_queue(dev_info->dcssblk_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) dev_info->gd->queue = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) put_disk(dev_info->gd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) up_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) seg_list_del:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) if (dev_info == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) list_for_each_entry_safe(seg_info, temp, &dev_info->seg_list, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) list_del(&seg_info->lh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) segment_unload(seg_info->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) kfree(seg_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) kfree(dev_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) kfree(local_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) out_nobuf:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) * device attribute for removing devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) struct dcssblk_dev_info *dev_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) struct segment_info *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) int rc, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) char *local_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) if (dev != dcssblk_root_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) local_buf = kmalloc(count + 1, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) if (local_buf == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) * parse input
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) for (i = 0; (i < count && (*(buf+i)!='\0') && (*(buf+i)!='\n')); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) local_buf[i] = toupper(buf[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) local_buf[i] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) if ((i == 0) || (i > 8)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) rc = -ENAMETOOLONG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) goto out_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) down_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) dev_info = dcssblk_get_device_by_name(local_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) if (dev_info == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) up_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) pr_warn("Device %s cannot be removed because it is not a known device\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) local_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) rc = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) goto out_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) if (atomic_read(&dev_info->use_count) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) up_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) pr_warn("Device %s cannot be removed while it is in use\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) local_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) rc = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) goto out_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) list_del(&dev_info->lh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) kill_dax(dev_info->dax_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) put_dax(dev_info->dax_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) del_gendisk(dev_info->gd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) blk_cleanup_queue(dev_info->dcssblk_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) dev_info->gd->queue = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) put_disk(dev_info->gd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) /* unload all related segments */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) list_for_each_entry(entry, &dev_info->seg_list, lh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) segment_unload(entry->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) up_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) device_unregister(&dev_info->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) put_device(&dev_info->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) rc = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) out_buf:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) kfree(local_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) dcssblk_open(struct block_device *bdev, fmode_t mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) struct dcssblk_dev_info *dev_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) dev_info = bdev->bd_disk->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) if (NULL == dev_info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) rc = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) atomic_inc(&dev_info->use_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) dcssblk_release(struct gendisk *disk, fmode_t mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) struct dcssblk_dev_info *dev_info = disk->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) struct segment_info *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) if (!dev_info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) WARN_ON(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) down_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) if (atomic_dec_and_test(&dev_info->use_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) && (dev_info->save_pending)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) pr_info("Device %s has become idle and is being saved "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) "now\n", dev_info->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) list_for_each_entry(entry, &dev_info->seg_list, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) if (entry->segment_type == SEG_TYPE_EN ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) entry->segment_type == SEG_TYPE_SN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) pr_warn("DCSS %s is of type SN or EN and cannot"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) " be saved\n", entry->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) segment_save(entry->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) dev_info->save_pending = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) up_write(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) static blk_qc_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) dcssblk_submit_bio(struct bio *bio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) struct dcssblk_dev_info *dev_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) struct bio_vec bvec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) struct bvec_iter iter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) unsigned long index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) unsigned long page_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) unsigned long source_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) unsigned long bytes_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) blk_queue_split(&bio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) bytes_done = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) dev_info = bio->bi_disk->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) if (dev_info == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) if ((bio->bi_iter.bi_sector & 7) != 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) (bio->bi_iter.bi_size & 4095) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) /* Request is not page-aligned. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) if (bio_end_sector(bio) > get_capacity(bio->bi_disk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) /* Request beyond end of DCSS segment. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) /* verify data transfer direction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) if (dev_info->is_shared) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) switch (dev_info->segment_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) case SEG_TYPE_SR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) case SEG_TYPE_ER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) case SEG_TYPE_SC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) /* cannot write to these segments */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) if (bio_data_dir(bio) == WRITE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) pr_warn("Writing to %s failed because it is a read-only device\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) dev_name(&dev_info->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) index = (bio->bi_iter.bi_sector >> 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) bio_for_each_segment(bvec, bio, iter) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) page_addr = (unsigned long)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) page_address(bvec.bv_page) + bvec.bv_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) source_addr = dev_info->start + (index<<12) + bytes_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) if (unlikely((page_addr & 4095) != 0) || (bvec.bv_len & 4095) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) // More paranoia.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) if (bio_data_dir(bio) == READ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) memcpy((void*)page_addr, (void*)source_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) bvec.bv_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) memcpy((void*)source_addr, (void*)page_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) bvec.bv_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) bytes_done += bvec.bv_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) bio_endio(bio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) return BLK_QC_T_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) bio_io_error(bio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) return BLK_QC_T_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) static long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) __dcssblk_direct_access(struct dcssblk_dev_info *dev_info, pgoff_t pgoff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) long nr_pages, void **kaddr, pfn_t *pfn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) resource_size_t offset = pgoff * PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) unsigned long dev_sz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) dev_sz = dev_info->end - dev_info->start + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) if (kaddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) *kaddr = (void *) dev_info->start + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) if (pfn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) PFN_DEV|PFN_SPECIAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) return (dev_sz - offset) / PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) static long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) dcssblk_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) long nr_pages, void **kaddr, pfn_t *pfn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) struct dcssblk_dev_info *dev_info = dax_get_private(dax_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) return __dcssblk_direct_access(dev_info, pgoff, nr_pages, kaddr, pfn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) dcssblk_check_params(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) int rc, i, j, k;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) char buf[DCSSBLK_PARM_LEN + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) struct dcssblk_dev_info *dev_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) for (j = i; (j < DCSSBLK_PARM_LEN) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) (dcssblk_segments[j] != ',') &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) (dcssblk_segments[j] != '\0') &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) (dcssblk_segments[j] != '('); j++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) buf[j-i] = dcssblk_segments[j];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) buf[j-i] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) if ((rc >= 0) && (dcssblk_segments[j] == '(')) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) for (k = 0; (buf[k] != ':') && (buf[k] != '\0'); k++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) buf[k] = toupper(buf[k]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) buf[k] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) if (!strncmp(&dcssblk_segments[j], "(local)", 7)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) down_read(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) dev_info = dcssblk_get_device_by_name(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) up_read(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) if (dev_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) dcssblk_shared_store(&dev_info->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) NULL, "0\n", 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) while ((dcssblk_segments[j] != ',') &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) (dcssblk_segments[j] != '\0'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) j++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) if (dcssblk_segments[j] == '\0')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) i = j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) * Suspend / Resume
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) static int dcssblk_freeze(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) struct dcssblk_dev_info *dev_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) int rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) list_for_each_entry(dev_info, &dcssblk_devices, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) switch (dev_info->segment_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) case SEG_TYPE_SR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) case SEG_TYPE_ER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) case SEG_TYPE_SC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) if (!dev_info->is_shared)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) pr_err("Suspending the system failed because DCSS device %s "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) "is writable\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) dev_info->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) static int dcssblk_restore(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) struct dcssblk_dev_info *dev_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) struct segment_info *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) unsigned long start, end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) int rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) list_for_each_entry(dev_info, &dcssblk_devices, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) list_for_each_entry(entry, &dev_info->seg_list, lh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) segment_unload(entry->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) rc = segment_load(entry->segment_name, SEGMENT_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) &start, &end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) // TODO in_use check ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) segment_warning(rc, entry->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) goto out_panic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) if (start != entry->start || end != entry->end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) pr_err("The address range of DCSS %s changed "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) "while the system was suspended\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) entry->segment_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) goto out_panic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) out_panic:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) panic("fatal dcssblk resume error\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) static int dcssblk_thaw(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) static const struct dev_pm_ops dcssblk_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) .freeze = dcssblk_freeze,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) .thaw = dcssblk_thaw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) .restore = dcssblk_restore,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) static struct platform_driver dcssblk_pdrv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) .name = "dcssblk",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) .pm = &dcssblk_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) static struct platform_device *dcssblk_pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) * The init/exit functions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) static void __exit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) dcssblk_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) platform_device_unregister(dcssblk_pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) platform_driver_unregister(&dcssblk_pdrv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) root_device_unregister(dcssblk_root_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) unregister_blkdev(dcssblk_major, DCSSBLK_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) static int __init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) dcssblk_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) rc = platform_driver_register(&dcssblk_pdrv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) dcssblk_pdev = platform_device_register_simple("dcssblk", -1, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) if (IS_ERR(dcssblk_pdev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) rc = PTR_ERR(dcssblk_pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) goto out_pdrv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) dcssblk_root_dev = root_device_register("dcssblk");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) if (IS_ERR(dcssblk_root_dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) rc = PTR_ERR(dcssblk_root_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) goto out_pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) rc = device_create_file(dcssblk_root_dev, &dev_attr_add);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) goto out_root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) rc = device_create_file(dcssblk_root_dev, &dev_attr_remove);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) goto out_root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) rc = register_blkdev(0, DCSSBLK_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) goto out_root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) dcssblk_major = rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) init_rwsem(&dcssblk_devices_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) dcssblk_check_params();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) out_root:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) root_device_unregister(dcssblk_root_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) out_pdev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) platform_device_unregister(dcssblk_pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) out_pdrv:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) platform_driver_unregister(&dcssblk_pdrv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) module_init(dcssblk_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) module_exit(dcssblk_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) "comma-separated list, names in each set separated "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) "by commas are separated by colons, each set contains "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) "names of contiguous segments and each name max. 8 chars.\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) "Adding \"(local)\" to the end of each set equals echoing 0 "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) "to /sys/devices/dcssblk/<device name>/shared after loading "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) "the contiguous segments - \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) "e.g. segments=\"mydcss1,mydcss2:mydcss3,mydcss4(local)\"");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) MODULE_LICENSE("GPL");