Lines Matching +full:multi +full:- +full:attr

1 // SPDX-License-Identifier: GPL-2.0
3 * dcssblk.c -- the S/390 block driver for dcss memory
94 static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * b…
96 static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char …
117 list_for_each_entry_safe(entry, temp, &dev_info->seg_list, lh) { in dcssblk_release_segment()
118 list_del(&entry->lh); in dcssblk_release_segment()
138 return -EINVAL; in dcssblk_assign_free_minor()
143 if (minor == entry->gd->first_minor) in dcssblk_assign_free_minor()
148 return -EBUSY; in dcssblk_assign_free_minor()
149 dev_info->gd->first_minor = minor; in dcssblk_assign_free_minor()
164 if (!strcmp(name, entry->segment_name)) { in dcssblk_get_device_by_name()
183 list_for_each_entry(entry, &dev_info->seg_list, lh) { in dcssblk_get_segment_by_name()
184 if (!strcmp(name, entry->segment_name)) in dcssblk_get_segment_by_name()
192 * get the highest address of the multi-segment block.
201 list_for_each_entry(entry, &dev_info->seg_list, lh) { in dcssblk_find_highest_addr()
202 if (highest_addr < entry->end) in dcssblk_find_highest_addr()
203 highest_addr = entry->end; in dcssblk_find_highest_addr()
209 * get the lowest address of the multi-segment block.
220 list_for_each_entry(entry, &dev_info->seg_list, lh) { in dcssblk_find_lowest_addr()
222 lowest_addr = entry->start; in dcssblk_find_lowest_addr()
225 if (lowest_addr > entry->start) in dcssblk_find_lowest_addr()
226 lowest_addr = entry->start; in dcssblk_find_lowest_addr()
241 if (dev_info->num_of_segments <= 1) in dcssblk_is_continuous()
244 sort_list = kcalloc(dev_info->num_of_segments, in dcssblk_is_continuous()
248 return -ENOMEM; in dcssblk_is_continuous()
250 list_for_each_entry(entry, &dev_info->seg_list, lh) { in dcssblk_is_continuous()
256 for (i = 0; i < dev_info->num_of_segments; i++) in dcssblk_is_continuous()
257 for (j = 0; j < dev_info->num_of_segments; j++) in dcssblk_is_continuous()
268 for (i = 0; i < dev_info->num_of_segments - 1; i++) { in dcssblk_is_continuous()
273 rc = -EINVAL; in dcssblk_is_continuous()
287 rc = -EINVAL; in dcssblk_is_continuous()
311 return -EEXIST; in dcssblk_load_segment()
316 return -ENOMEM; in dcssblk_load_segment()
318 strscpy((*seg_info)->segment_name, name); in dcssblk_load_segment()
322 &(*seg_info)->start, &(*seg_info)->end); in dcssblk_load_segment()
324 segment_warning(rc, (*seg_info)->segment_name); in dcssblk_load_segment()
327 INIT_LIST_HEAD(&(*seg_info)->lh); in dcssblk_load_segment()
328 (*seg_info)->segment_type = rc; in dcssblk_load_segment()
338 dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf) in dcssblk_shared_show() argument
343 return sysfs_emit(buf, dev_info->is_shared ? "1\n" : "0\n"); in dcssblk_shared_show()
347 dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t c… in dcssblk_shared_store() argument
354 return -EINVAL; in dcssblk_shared_store()
357 if (atomic_read(&dev_info->use_count)) { in dcssblk_shared_store()
358 rc = -EBUSY; in dcssblk_shared_store()
363 list_for_each_entry(entry, &dev_info->seg_list, lh) { in dcssblk_shared_store()
364 rc = segment_modify_shared(entry->segment_name, in dcssblk_shared_store()
367 BUG_ON(rc == -EINVAL); in dcssblk_shared_store()
368 if (rc != -EAGAIN) in dcssblk_shared_store()
372 dev_info->is_shared = 1; in dcssblk_shared_store()
373 switch (dev_info->segment_type) { in dcssblk_shared_store()
377 set_disk_ro(dev_info->gd, 1); in dcssblk_shared_store()
381 if (dev_info->segment_type == SEG_TYPE_SC) { in dcssblk_shared_store()
383 "loaded as exclusive-writable\n", in dcssblk_shared_store()
384 dev_info->segment_name); in dcssblk_shared_store()
385 rc = -EINVAL; in dcssblk_shared_store()
388 list_for_each_entry(entry, &dev_info->seg_list, lh) { in dcssblk_shared_store()
389 rc = segment_modify_shared(entry->segment_name, in dcssblk_shared_store()
392 BUG_ON(rc == -EINVAL); in dcssblk_shared_store()
393 if (rc != -EAGAIN) in dcssblk_shared_store()
397 dev_info->is_shared = 0; in dcssblk_shared_store()
398 set_disk_ro(dev_info->gd, 0); in dcssblk_shared_store()
400 rc = -EINVAL; in dcssblk_shared_store()
408 "change\n", dev_info->segment_name); in dcssblk_shared_store()
410 list_for_each_entry(entry, &dev_info->seg_list, lh) { in dcssblk_shared_store()
412 segment_unload(entry->segment_name); in dcssblk_shared_store()
414 list_del(&dev_info->lh); in dcssblk_shared_store()
417 dax_remove_host(dev_info->gd); in dcssblk_shared_store()
418 kill_dax(dev_info->dax_dev); in dcssblk_shared_store()
419 put_dax(dev_info->dax_dev); in dcssblk_shared_store()
420 if (dev_info->pgmap_addr) in dcssblk_shared_store()
421 devm_memunmap_pages(&dev_info->dev, &dev_info->pgmap); in dcssblk_shared_store()
422 del_gendisk(dev_info->gd); in dcssblk_shared_store()
423 put_disk(dev_info->gd); in dcssblk_shared_store()
425 if (device_remove_file_self(dev, attr)) { in dcssblk_shared_store()
441 * undone by storing a non-true value to this entry.
445 dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf) in dcssblk_save_show() argument
450 return sysfs_emit(buf, dev_info->save_pending ? "1\n" : "0\n"); in dcssblk_save_show()
454 dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t cou… in dcssblk_save_store() argument
460 return -EINVAL; in dcssblk_save_store()
465 if (atomic_read(&dev_info->use_count) == 0) { in dcssblk_save_store()
468 "saved\n", dev_info->segment_name); in dcssblk_save_store()
469 list_for_each_entry(entry, &dev_info->seg_list, lh) { in dcssblk_save_store()
470 if (entry->segment_type == SEG_TYPE_EN || in dcssblk_save_store()
471 entry->segment_type == SEG_TYPE_SN) in dcssblk_save_store()
474 entry->segment_name); in dcssblk_save_store()
476 segment_save(entry->segment_name); in dcssblk_save_store()
483 dev_info->segment_name); in dcssblk_save_store()
484 dev_info->save_pending = 1; in dcssblk_save_store()
487 if (dev_info->save_pending) { in dcssblk_save_store()
490 dev_info->save_pending = 0; in dcssblk_save_store()
493 dev_info->segment_name); in dcssblk_save_store()
497 return -EINVAL; in dcssblk_save_store()
509 dcssblk_seglist_show(struct device *dev, struct device_attribute *attr, in dcssblk_seglist_show() argument
519 list_for_each_entry(entry, &dev_info->seg_list, lh) in dcssblk_seglist_show()
520 i += sysfs_emit_at(buf, i, "%s\n", entry->segment_name); in dcssblk_seglist_show()
527 &dev_attr_shared.attr,
528 &dev_attr_save.attr,
529 &dev_attr_seglist.attr,
548 dev_info->dax_dev = dax_dev; in dcssblk_setup_dax()
549 return dax_add_host(dev_info->dax_dev, dev_info->gd); in dcssblk_setup_dax()
556 dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) in dcssblk_add_store() argument
572 rc = -EINVAL; in dcssblk_add_store()
576 rc = -ENAMETOOLONG; in dcssblk_add_store()
582 rc = -ENOMEM; in dcssblk_add_store()
595 local_buf[j-i] = toupper(buf[j]); in dcssblk_add_store()
597 local_buf[j-i] = '\0'; in dcssblk_add_store()
598 if (((j - i) == 0) || ((j - i) > 8)) { in dcssblk_add_store()
599 rc = -ENAMETOOLONG; in dcssblk_add_store()
613 rc = -ENOMEM; in dcssblk_add_store()
616 strscpy(dev_info->segment_name, local_buf); in dcssblk_add_store()
617 dev_info->segment_type = seg_info->segment_type; in dcssblk_add_store()
618 INIT_LIST_HEAD(&dev_info->seg_list); in dcssblk_add_store()
620 list_add_tail(&seg_info->lh, &dev_info->seg_list); in dcssblk_add_store()
629 if ((i > 0) && (buf[i-1] == ':')) { in dcssblk_add_store()
630 rc = -ENAMETOOLONG; in dcssblk_add_store()
634 dev_info->num_of_segments = num_of_segments; in dcssblk_add_store()
639 dev_info->start = dcssblk_find_lowest_addr(dev_info); in dcssblk_add_store()
640 dev_info->end = dcssblk_find_highest_addr(dev_info); in dcssblk_add_store()
642 dev_set_name(&dev_info->dev, "%s", dev_info->segment_name); in dcssblk_add_store()
643 dev_info->dev.release = dcssblk_release_segment; in dcssblk_add_store()
644 dev_info->dev.groups = dcssblk_dev_attr_groups; in dcssblk_add_store()
645 INIT_LIST_HEAD(&dev_info->lh); in dcssblk_add_store()
646 dev_info->gd = blk_alloc_disk(&lim, NUMA_NO_NODE); in dcssblk_add_store()
647 if (IS_ERR(dev_info->gd)) { in dcssblk_add_store()
648 rc = PTR_ERR(dev_info->gd); in dcssblk_add_store()
651 dev_info->gd->major = dcssblk_major; in dcssblk_add_store()
652 dev_info->gd->minors = DCSSBLK_MINORS_PER_DISK; in dcssblk_add_store()
653 dev_info->gd->fops = &dcssblk_devops; in dcssblk_add_store()
654 dev_info->gd->private_data = dev_info; in dcssblk_add_store()
655 dev_info->gd->flags |= GENHD_FL_NO_PART; in dcssblk_add_store()
657 seg_byte_size = (dev_info->end - dev_info->start + 1); in dcssblk_add_store()
658 set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors in dcssblk_add_store()
662 dev_info->save_pending = 0; in dcssblk_add_store()
663 dev_info->is_shared = 1; in dcssblk_add_store()
664 dev_info->dev.parent = dcssblk_root_dev; in dcssblk_add_store()
671 rc = -EEXIST; in dcssblk_add_store()
677 sprintf(dev_info->gd->disk_name, "dcssblk%d", in dcssblk_add_store()
678 dev_info->gd->first_minor); in dcssblk_add_store()
679 list_add_tail(&dev_info->lh, &dcssblk_devices); in dcssblk_add_store()
682 rc = -ENODEV; in dcssblk_add_store()
688 rc = device_register(&dev_info->dev); in dcssblk_add_store()
692 if (!IS_ALIGNED(dev_info->start, SUBSECTION_SIZE) || in dcssblk_add_store()
693 !IS_ALIGNED(dev_info->end + 1, SUBSECTION_SIZE)) { in dcssblk_add_store()
697 dev_info->pgmap.type = MEMORY_DEVICE_FS_DAX; in dcssblk_add_store()
698 dev_info->pgmap.range.start = dev_info->start; in dcssblk_add_store()
699 dev_info->pgmap.range.end = dev_info->end; in dcssblk_add_store()
700 dev_info->pgmap.nr_range = 1; in dcssblk_add_store()
701 addr = devm_memremap_pages(&dev_info->dev, &dev_info->pgmap); in dcssblk_add_store()
706 dev_info->pgmap_addr = addr; in dcssblk_add_store()
713 get_device(&dev_info->dev); in dcssblk_add_store()
714 rc = device_add_disk(&dev_info->dev, dev_info->gd, NULL); in dcssblk_add_store()
718 switch (dev_info->segment_type) { in dcssblk_add_store()
722 set_disk_ro(dev_info->gd,1); in dcssblk_add_store()
725 set_disk_ro(dev_info->gd,0); in dcssblk_add_store()
733 put_device(&dev_info->dev); in dcssblk_add_store()
734 dax_remove_host(dev_info->gd); in dcssblk_add_store()
736 kill_dax(dev_info->dax_dev); in dcssblk_add_store()
737 put_dax(dev_info->dax_dev); in dcssblk_add_store()
738 if (dev_info->pgmap_addr) in dcssblk_add_store()
739 devm_memunmap_pages(&dev_info->dev, &dev_info->pgmap); in dcssblk_add_store()
741 list_del(&dev_info->lh); in dcssblk_add_store()
742 put_disk(dev_info->gd); in dcssblk_add_store()
743 list_for_each_entry(seg_info, &dev_info->seg_list, lh) { in dcssblk_add_store()
744 segment_unload(seg_info->segment_name); in dcssblk_add_store()
746 put_device(&dev_info->dev); in dcssblk_add_store()
750 list_del(&dev_info->lh); in dcssblk_add_store()
752 put_disk(dev_info->gd); in dcssblk_add_store()
757 list_for_each_entry_safe(seg_info, temp, &dev_info->seg_list, lh) { in dcssblk_add_store()
758 list_del(&seg_info->lh); in dcssblk_add_store()
759 segment_unload(seg_info->segment_name); in dcssblk_add_store()
773 dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t cou… in dcssblk_remove_store() argument
781 return -EINVAL; in dcssblk_remove_store()
785 return -ENOMEM; in dcssblk_remove_store()
795 rc = -ENAMETOOLONG; in dcssblk_remove_store()
805 rc = -ENODEV; in dcssblk_remove_store()
808 if (atomic_read(&dev_info->use_count) != 0) { in dcssblk_remove_store()
812 rc = -EBUSY; in dcssblk_remove_store()
816 list_del(&dev_info->lh); in dcssblk_remove_store()
818 list_for_each_entry(entry, &dev_info->seg_list, lh) in dcssblk_remove_store()
819 segment_unload(entry->segment_name); in dcssblk_remove_store()
822 dax_remove_host(dev_info->gd); in dcssblk_remove_store()
823 kill_dax(dev_info->dax_dev); in dcssblk_remove_store()
824 put_dax(dev_info->dax_dev); in dcssblk_remove_store()
825 if (dev_info->pgmap_addr) in dcssblk_remove_store()
826 devm_memunmap_pages(&dev_info->dev, &dev_info->pgmap); in dcssblk_remove_store()
827 del_gendisk(dev_info->gd); in dcssblk_remove_store()
828 put_disk(dev_info->gd); in dcssblk_remove_store()
830 device_unregister(&dev_info->dev); in dcssblk_remove_store()
831 put_device(&dev_info->dev); in dcssblk_remove_store()
842 struct dcssblk_dev_info *dev_info = disk->private_data; in dcssblk_open()
846 rc = -ENODEV; in dcssblk_open()
849 atomic_inc(&dev_info->use_count); in dcssblk_open()
858 struct dcssblk_dev_info *dev_info = disk->private_data; in dcssblk_release()
866 if (atomic_dec_and_test(&dev_info->use_count) in dcssblk_release()
867 && (dev_info->save_pending)) { in dcssblk_release()
869 "now\n", dev_info->segment_name); in dcssblk_release()
870 list_for_each_entry(entry, &dev_info->seg_list, lh) { in dcssblk_release()
871 if (entry->segment_type == SEG_TYPE_EN || in dcssblk_release()
872 entry->segment_type == SEG_TYPE_SN) in dcssblk_release()
874 " be saved\n", entry->segment_name); in dcssblk_release()
876 segment_save(entry->segment_name); in dcssblk_release()
878 dev_info->save_pending = 0; in dcssblk_release()
895 dev_info = bio->bi_bdev->bd_disk->private_data; in dcssblk_submit_bio()
898 if (!IS_ALIGNED(bio->bi_iter.bi_sector, 8) || in dcssblk_submit_bio()
899 !IS_ALIGNED(bio->bi_iter.bi_size, PAGE_SIZE)) in dcssblk_submit_bio()
900 /* Request is not page-aligned. */ in dcssblk_submit_bio()
903 if (dev_info->is_shared) { in dcssblk_submit_bio()
904 switch (dev_info->segment_type) { in dcssblk_submit_bio()
910 pr_warn("Writing to %s failed because it is a read-only device\n", in dcssblk_submit_bio()
911 dev_name(&dev_info->dev)); in dcssblk_submit_bio()
917 index = (bio->bi_iter.bi_sector >> 3); in dcssblk_submit_bio()
920 source_addr = dev_info->start + (index<<12) + bytes_done; in dcssblk_submit_bio()
944 dev_sz = dev_info->end - dev_info->start + 1; in __dcssblk_direct_access()
946 *kaddr = __va(dev_info->start + offset); in __dcssblk_direct_access()
948 *pfn = PFN_DOWN(dev_info->start + offset); in __dcssblk_direct_access()
950 return (dev_sz - offset) / PAGE_SIZE; in __dcssblk_direct_access()
977 buf[j-i] = dcssblk_segments[j]; in dcssblk_check_params()
979 buf[j-i] = '\0'; in dcssblk_check_params()
980 rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i); in dcssblk_check_params()
990 dcssblk_shared_store(&dev_info->dev, in dcssblk_check_params()
1049 "comma-separated list, names in each set separated "
1054 "the contiguous segments - \n"