aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorHongjie Yang <hongjie@us.ibm.com>2008-10-10 15:33:21 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2008-10-10 15:33:57 -0400
commitb2300b9efe1b8174833e17f37e975c9da00c388a (patch)
treeb3413247d703aee9bd769ff09a782b679aba32cc /drivers/s390
parent753c4dd6a2fa2af81f5d809d610d29f2d9dd9bc1 (diff)
[S390] dcssblk: add >2G DCSSs support and stacked contiguous DCSSs support.
The DCSS block device driver is modified to add >2G DCSSs support and allow a DCSS block device to map to a set of contiguous DCSSs. The extmem code is also modified to use new Diagnose x'64' subcodes for >2G DCSSs. Signed-off-by: Hongjie Yang <hongjie@us.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dcssblk.c515
1 files changed, 384 insertions, 131 deletions
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index ea4272c8c677..a7ff167d5b81 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -31,7 +31,6 @@
31#define PRINT_WARN(x...) printk(KERN_WARNING DCSSBLK_NAME " warning: " x) 31#define PRINT_WARN(x...) printk(KERN_WARNING DCSSBLK_NAME " warning: " x)
32#define PRINT_ERR(x...) printk(KERN_ERR DCSSBLK_NAME " error: " x) 32#define PRINT_ERR(x...) printk(KERN_ERR DCSSBLK_NAME " error: " x)
33 33
34
35static int dcssblk_open(struct inode *inode, struct file *filp); 34static int dcssblk_open(struct inode *inode, struct file *filp);
36static int dcssblk_release(struct inode *inode, struct file *filp); 35static int dcssblk_release(struct inode *inode, struct file *filp);
37static int dcssblk_make_request(struct request_queue *q, struct bio *bio); 36static int dcssblk_make_request(struct request_queue *q, struct bio *bio);
@@ -48,6 +47,30 @@ static struct block_device_operations dcssblk_devops = {
48 .direct_access = dcssblk_direct_access, 47 .direct_access = dcssblk_direct_access,
49}; 48};
50 49
50struct dcssblk_dev_info {
51 struct list_head lh;
52 struct device dev;
53 char segment_name[BUS_ID_SIZE];
54 atomic_t use_count;
55 struct gendisk *gd;
56 unsigned long start;
57 unsigned long end;
58 int segment_type;
59 unsigned char save_pending;
60 unsigned char is_shared;
61 struct request_queue *dcssblk_queue;
62 int num_of_segments;
63 struct list_head seg_list;
64};
65
66struct segment_info {
67 struct list_head lh;
68 char segment_name[BUS_ID_SIZE];
69 unsigned long start;
70 unsigned long end;
71 int segment_type;
72};
73
51static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf, 74static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf,
52 size_t count); 75 size_t count);
53static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf, 76static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf,
@@ -58,30 +81,20 @@ static ssize_t dcssblk_save_show(struct device *dev, struct device_attribute *at
58static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf, 81static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf,
59 size_t count); 82 size_t count);
60static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf); 83static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf);
84static ssize_t dcssblk_seglist_show(struct device *dev,
85 struct device_attribute *attr,
86 char *buf);
61 87
62static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store); 88static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store);
63static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store); 89static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store);
64static DEVICE_ATTR(save, S_IWUSR | S_IRUGO, dcssblk_save_show, 90static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show,
65 dcssblk_save_store); 91 dcssblk_save_store);
66static DEVICE_ATTR(shared, S_IWUSR | S_IRUGO, dcssblk_shared_show, 92static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show,
67 dcssblk_shared_store); 93 dcssblk_shared_store);
94static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL);
68 95
69static struct device *dcssblk_root_dev; 96static struct device *dcssblk_root_dev;
70 97
71struct dcssblk_dev_info {
72 struct list_head lh;
73 struct device dev;
74 char segment_name[BUS_ID_SIZE];
75 atomic_t use_count;
76 struct gendisk *gd;
77 unsigned long start;
78 unsigned long end;
79 int segment_type;
80 unsigned char save_pending;
81 unsigned char is_shared;
82 struct request_queue *dcssblk_queue;
83};
84
85static LIST_HEAD(dcssblk_devices); 98static LIST_HEAD(dcssblk_devices);
86static struct rw_semaphore dcssblk_devices_sem; 99static struct rw_semaphore dcssblk_devices_sem;
87 100
@@ -91,8 +104,15 @@ static struct rw_semaphore dcssblk_devices_sem;
91static void 104static void
92dcssblk_release_segment(struct device *dev) 105dcssblk_release_segment(struct device *dev)
93{ 106{
94 PRINT_DEBUG("segment release fn called for %s\n", dev_name(dev)); 107 struct dcssblk_dev_info *dev_info;
95 kfree(container_of(dev, struct dcssblk_dev_info, dev)); 108 struct segment_info *entry, *temp;
109
110 dev_info = container_of(dev, struct dcssblk_dev_info, dev);
111 list_for_each_entry_safe(entry, temp, &dev_info->seg_list, lh) {
112 list_del(&entry->lh);
113 kfree(entry);
114 }
115 kfree(dev_info);
96 module_put(THIS_MODULE); 116 module_put(THIS_MODULE);
97} 117}
98 118
@@ -142,6 +162,169 @@ dcssblk_get_device_by_name(char *name)
142 return NULL; 162 return NULL;
143} 163}
144 164
165/*
166 * get the struct segment_info from seg_list
167 * for the given name.
168 * down_read(&dcssblk_devices_sem) must be held.
169 */
170static struct segment_info *
171dcssblk_get_segment_by_name(char *name)
172{
173 struct dcssblk_dev_info *dev_info;
174 struct segment_info *entry;
175
176 list_for_each_entry(dev_info, &dcssblk_devices, lh) {
177 list_for_each_entry(entry, &dev_info->seg_list, lh) {
178 if (!strcmp(name, entry->segment_name))
179 return entry;
180 }
181 }
182 return NULL;
183}
184
185/*
186 * get the highest address of the multi-segment block.
187 */
188static unsigned long
189dcssblk_find_highest_addr(struct dcssblk_dev_info *dev_info)
190{
191 unsigned long highest_addr;
192 struct segment_info *entry;
193
194 highest_addr = 0;
195 list_for_each_entry(entry, &dev_info->seg_list, lh) {
196 if (highest_addr < entry->end)
197 highest_addr = entry->end;
198 }
199 return highest_addr;
200}
201
202/*
203 * get the lowest address of the multi-segment block.
204 */
205static unsigned long
206dcssblk_find_lowest_addr(struct dcssblk_dev_info *dev_info)
207{
208 int set_first;
209 unsigned long lowest_addr;
210 struct segment_info *entry;
211
212 set_first = 0;
213 lowest_addr = 0;
214 list_for_each_entry(entry, &dev_info->seg_list, lh) {
215 if (set_first == 0) {
216 lowest_addr = entry->start;
217 set_first = 1;
218 } else {
219 if (lowest_addr > entry->start)
220 lowest_addr = entry->start;
221 }
222 }
223 return lowest_addr;
224}
225
226/*
227 * Check continuity of segments.
228 */
229static int
230dcssblk_is_continuous(struct dcssblk_dev_info *dev_info)
231{
232 int i, j, rc;
233 struct segment_info *sort_list, *entry, temp;
234
235 if (dev_info->num_of_segments <= 1)
236 return 0;
237
238 sort_list = kzalloc(
239 sizeof(struct segment_info) * dev_info->num_of_segments,
240 GFP_KERNEL);
241 if (sort_list == NULL)
242 return -ENOMEM;
243 i = 0;
244 list_for_each_entry(entry, &dev_info->seg_list, lh) {
245 memcpy(&sort_list[i], entry, sizeof(struct segment_info));
246 i++;
247 }
248
249 /* sort segments */
250 for (i = 0; i < dev_info->num_of_segments; i++)
251 for (j = 0; j < dev_info->num_of_segments; j++)
252 if (sort_list[j].start > sort_list[i].start) {
253 memcpy(&temp, &sort_list[i],
254 sizeof(struct segment_info));
255 memcpy(&sort_list[i], &sort_list[j],
256 sizeof(struct segment_info));
257 memcpy(&sort_list[j], &temp,
258 sizeof(struct segment_info));
259 }
260
261 /* check continuity */
262 for (i = 0; i < dev_info->num_of_segments - 1; i++) {
263 if ((sort_list[i].end + 1) != sort_list[i+1].start) {
264 PRINT_ERR("Segment %s is not contiguous with "
265 "segment %s\n",
266 sort_list[i].segment_name,
267 sort_list[i+1].segment_name);
268 rc = -EINVAL;
269 goto out;
270 }
271 /* EN and EW are allowed in a block device */
272 if (sort_list[i].segment_type != sort_list[i+1].segment_type) {
273 if (!(sort_list[i].segment_type & SEGMENT_EXCLUSIVE) ||
274 (sort_list[i].segment_type == SEG_TYPE_ER) ||
275 !(sort_list[i+1].segment_type &
276 SEGMENT_EXCLUSIVE) ||
277 (sort_list[i+1].segment_type == SEG_TYPE_ER)) {
278 PRINT_ERR("Segment %s has different type from "
279 "segment %s\n",
280 sort_list[i].segment_name,
281 sort_list[i+1].segment_name);
282 rc = -EINVAL;
283 goto out;
284 }
285 }
286 }
287 rc = 0;
288out:
289 kfree(sort_list);
290 return rc;
291}
292
293/*
294 * Load a segment
295 */
296static int
297dcssblk_load_segment(char *name, struct segment_info **seg_info)
298{
299 int rc;
300
301 /* already loaded? */
302 down_read(&dcssblk_devices_sem);
303 *seg_info = dcssblk_get_segment_by_name(name);
304 up_read(&dcssblk_devices_sem);
305 if (*seg_info != NULL)
306 return -EEXIST;
307
308 /* get a struct segment_info */
309 *seg_info = kzalloc(sizeof(struct segment_info), GFP_KERNEL);
310 if (*seg_info == NULL)
311 return -ENOMEM;
312
313 strcpy((*seg_info)->segment_name, name);
314
315 /* load the segment */
316 rc = segment_load(name, SEGMENT_SHARED,
317 &(*seg_info)->start, &(*seg_info)->end);
318 if (rc < 0) {
319 segment_warning(rc, (*seg_info)->segment_name);
320 kfree(*seg_info);
321 } else {
322 INIT_LIST_HEAD(&(*seg_info)->lh);
323 (*seg_info)->segment_type = rc;
324 }
325 return rc;
326}
327
145static void dcssblk_unregister_callback(struct device *dev) 328static void dcssblk_unregister_callback(struct device *dev)
146{ 329{
147 device_unregister(dev); 330 device_unregister(dev);
@@ -165,6 +348,7 @@ static ssize_t
165dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count) 348dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count)
166{ 349{
167 struct dcssblk_dev_info *dev_info; 350 struct dcssblk_dev_info *dev_info;
351 struct segment_info *entry, *temp;
168 int rc; 352 int rc;
169 353
170 if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) 354 if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
@@ -172,46 +356,46 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
172 down_write(&dcssblk_devices_sem); 356 down_write(&dcssblk_devices_sem);
173 dev_info = container_of(dev, struct dcssblk_dev_info, dev); 357 dev_info = container_of(dev, struct dcssblk_dev_info, dev);
174 if (atomic_read(&dev_info->use_count)) { 358 if (atomic_read(&dev_info->use_count)) {
175 PRINT_ERR("share: segment %s is busy!\n",
176 dev_info->segment_name);
177 rc = -EBUSY; 359 rc = -EBUSY;
178 goto out; 360 goto out;
179 } 361 }
180 if (inbuf[0] == '1') { 362 if (inbuf[0] == '1') {
181 // reload segment in shared mode 363 /* reload segments in shared mode */
182 rc = segment_modify_shared(dev_info->segment_name, 364 list_for_each_entry(entry, &dev_info->seg_list, lh) {
183 SEGMENT_SHARED); 365 rc = segment_modify_shared(entry->segment_name,
184 if (rc < 0) { 366 SEGMENT_SHARED);
185 BUG_ON(rc == -EINVAL); 367 if (rc < 0) {
186 if (rc != -EAGAIN) 368 BUG_ON(rc == -EINVAL);
187 goto removeseg; 369 if (rc != -EAGAIN)
188 } else { 370 goto removeseg;
189 dev_info->is_shared = 1;
190 switch (dev_info->segment_type) {
191 case SEG_TYPE_SR:
192 case SEG_TYPE_ER:
193 case SEG_TYPE_SC:
194 set_disk_ro(dev_info->gd,1);
195 } 371 }
196 } 372 }
373 dev_info->is_shared = 1;
374 switch (dev_info->segment_type) {
375 case SEG_TYPE_SR:
376 case SEG_TYPE_ER:
377 case SEG_TYPE_SC:
378 set_disk_ro(dev_info->gd, 1);
379 }
197 } else if (inbuf[0] == '0') { 380 } else if (inbuf[0] == '0') {
198 // reload segment in exclusive mode 381 /* reload segments in exclusive mode */
199 if (dev_info->segment_type == SEG_TYPE_SC) { 382 if (dev_info->segment_type == SEG_TYPE_SC) {
200 PRINT_ERR("Segment type SC (%s) cannot be loaded in " 383 PRINT_ERR("Segment type SC (%s) cannot be loaded in "
201 "non-shared mode\n", dev_info->segment_name); 384 "non-shared mode\n", dev_info->segment_name);
202 rc = -EINVAL; 385 rc = -EINVAL;
203 goto out; 386 goto out;
204 } 387 }
205 rc = segment_modify_shared(dev_info->segment_name, 388 list_for_each_entry(entry, &dev_info->seg_list, lh) {
206 SEGMENT_EXCLUSIVE); 389 rc = segment_modify_shared(entry->segment_name,
207 if (rc < 0) { 390 SEGMENT_EXCLUSIVE);
208 BUG_ON(rc == -EINVAL); 391 if (rc < 0) {
209 if (rc != -EAGAIN) 392 BUG_ON(rc == -EINVAL);
210 goto removeseg; 393 if (rc != -EAGAIN)
211 } else { 394 goto removeseg;
212 dev_info->is_shared = 0; 395 }
213 set_disk_ro(dev_info->gd, 0);
214 } 396 }
397 dev_info->is_shared = 0;
398 set_disk_ro(dev_info->gd, 0);
215 } else { 399 } else {
216 rc = -EINVAL; 400 rc = -EINVAL;
217 goto out; 401 goto out;
@@ -220,8 +404,14 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
220 goto out; 404 goto out;
221 405
222removeseg: 406removeseg:
223 PRINT_ERR("Could not reload segment %s, removing it now!\n", 407 PRINT_ERR("Could not reload segment(s) of the device %s, removing "
224 dev_info->segment_name); 408 "segment(s) now!\n",
409 dev_info->segment_name);
410 temp = entry;
411 list_for_each_entry(entry, &dev_info->seg_list, lh) {
412 if (entry != temp)
413 segment_unload(entry->segment_name);
414 }
225 list_del(&dev_info->lh); 415 list_del(&dev_info->lh);
226 416
227 del_gendisk(dev_info->gd); 417 del_gendisk(dev_info->gd);
@@ -254,6 +444,7 @@ static ssize_t
254dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count) 444dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count)
255{ 445{
256 struct dcssblk_dev_info *dev_info; 446 struct dcssblk_dev_info *dev_info;
447 struct segment_info *entry;
257 448
258 if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) 449 if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
259 return -EINVAL; 450 return -EINVAL;
@@ -263,14 +454,16 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char
263 if (inbuf[0] == '1') { 454 if (inbuf[0] == '1') {
264 if (atomic_read(&dev_info->use_count) == 0) { 455 if (atomic_read(&dev_info->use_count) == 0) {
265 // device is idle => we save immediately 456 // device is idle => we save immediately
266 PRINT_INFO("Saving segment %s\n", 457 PRINT_INFO("Saving segment(s) of the device %s\n",
267 dev_info->segment_name); 458 dev_info->segment_name);
268 segment_save(dev_info->segment_name); 459 list_for_each_entry(entry, &dev_info->seg_list, lh) {
460 segment_save(entry->segment_name);
461 }
269 } else { 462 } else {
270 // device is busy => we save it when it becomes 463 // device is busy => we save it when it becomes
271 // idle in dcssblk_release 464 // idle in dcssblk_release
272 PRINT_INFO("Segment %s is currently busy, it will " 465 PRINT_INFO("Device %s is currently busy, segment(s) "
273 "be saved when it becomes idle...\n", 466 "will be saved when it becomes idle...\n",
274 dev_info->segment_name); 467 dev_info->segment_name);
275 dev_info->save_pending = 1; 468 dev_info->save_pending = 1;
276 } 469 }
@@ -279,7 +472,8 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char
279 // device is busy & the user wants to undo his save 472 // device is busy & the user wants to undo his save
280 // request 473 // request
281 dev_info->save_pending = 0; 474 dev_info->save_pending = 0;
282 PRINT_INFO("Pending save for segment %s deactivated\n", 475 PRINT_INFO("Pending save for segment(s) of the device "
476 "%s deactivated\n",
283 dev_info->segment_name); 477 dev_info->segment_name);
284 } 478 }
285 } else { 479 } else {
@@ -291,66 +485,123 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char
291} 485}
292 486
293/* 487/*
488 * device attribute for showing all segments in a device
489 */
490static ssize_t
491dcssblk_seglist_show(struct device *dev, struct device_attribute *attr,
492 char *buf)
493{
494 int i;
495
496 struct dcssblk_dev_info *dev_info;
497 struct segment_info *entry;
498
499 down_read(&dcssblk_devices_sem);
500 dev_info = container_of(dev, struct dcssblk_dev_info, dev);
501 i = 0;
502 buf[0] = '\0';
503 list_for_each_entry(entry, &dev_info->seg_list, lh) {
504 strcpy(&buf[i], entry->segment_name);
505 i += strlen(entry->segment_name);
506 buf[i] = '\n';
507 i++;
508 }
509 up_read(&dcssblk_devices_sem);
510 return i;
511}
512
513/*
294 * device attribute for adding devices 514 * device attribute for adding devices
295 */ 515 */
296static ssize_t 516static ssize_t
297dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 517dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
298{ 518{
299 int rc, i; 519 int rc, i, j, num_of_segments;
300 struct dcssblk_dev_info *dev_info; 520 struct dcssblk_dev_info *dev_info;
521 struct segment_info *seg_info, *temp;
301 char *local_buf; 522 char *local_buf;
302 unsigned long seg_byte_size; 523 unsigned long seg_byte_size;
303 524
304 dev_info = NULL; 525 dev_info = NULL;
526 seg_info = NULL;
305 if (dev != dcssblk_root_dev) { 527 if (dev != dcssblk_root_dev) {
306 rc = -EINVAL; 528 rc = -EINVAL;
307 goto out_nobuf; 529 goto out_nobuf;
308 } 530 }
531 if ((count < 1) || (buf[0] == '\0') || (buf[0] == '\n')) {
532 rc = -ENAMETOOLONG;
533 goto out_nobuf;
534 }
535
309 local_buf = kmalloc(count + 1, GFP_KERNEL); 536 local_buf = kmalloc(count + 1, GFP_KERNEL);
310 if (local_buf == NULL) { 537 if (local_buf == NULL) {
311 rc = -ENOMEM; 538 rc = -ENOMEM;
312 goto out_nobuf; 539 goto out_nobuf;
313 } 540 }
541
314 /* 542 /*
315 * parse input 543 * parse input
316 */ 544 */
545 num_of_segments = 0;
317 for (i = 0; ((buf[i] != '\0') && (buf[i] != '\n') && i < count); i++) { 546 for (i = 0; ((buf[i] != '\0') && (buf[i] != '\n') && i < count); i++) {
318 local_buf[i] = toupper(buf[i]); 547 for (j = i; (buf[j] != ':') &&
548 (buf[j] != '\0') &&
549 (buf[j] != '\n') &&
550 j < count; j++) {
551 local_buf[j-i] = toupper(buf[j]);
552 }
553 local_buf[j-i] = '\0';
554 if (((j - i) == 0) || ((j - i) > 8)) {
555 rc = -ENAMETOOLONG;
556 goto seg_list_del;
557 }
558
559 rc = dcssblk_load_segment(local_buf, &seg_info);
560 if (rc < 0)
561 goto seg_list_del;
562 /*
563 * get a struct dcssblk_dev_info
564 */
565 if (num_of_segments == 0) {
566 dev_info = kzalloc(sizeof(struct dcssblk_dev_info),
567 GFP_KERNEL);
568 if (dev_info == NULL) {
569 rc = -ENOMEM;
570 goto out;
571 }
572 strcpy(dev_info->segment_name, local_buf);
573 dev_info->segment_type = seg_info->segment_type;
574 INIT_LIST_HEAD(&dev_info->seg_list);
575 }
576 list_add_tail(&seg_info->lh, &dev_info->seg_list);
577 num_of_segments++;
578 i = j;
579
580 if ((buf[j] == '\0') || (buf[j] == '\n'))
581 break;
319 } 582 }
320 local_buf[i] = '\0'; 583
321 if ((i == 0) || (i > 8)) { 584 /* no trailing colon at the end of the input */
585 if ((i > 0) && (buf[i-1] == ':')) {
322 rc = -ENAMETOOLONG; 586 rc = -ENAMETOOLONG;
323 goto out; 587 goto seg_list_del;
324 }
325 /*
326 * already loaded?
327 */
328 down_read(&dcssblk_devices_sem);
329 dev_info = dcssblk_get_device_by_name(local_buf);
330 up_read(&dcssblk_devices_sem);
331 if (dev_info != NULL) {
332 PRINT_WARN("Segment %s already loaded!\n", local_buf);
333 rc = -EEXIST;
334 goto out;
335 }
336 /*
337 * get a struct dcssblk_dev_info
338 */
339 dev_info = kzalloc(sizeof(struct dcssblk_dev_info), GFP_KERNEL);
340 if (dev_info == NULL) {
341 rc = -ENOMEM;
342 goto out;
343 } 588 }
589 strlcpy(local_buf, buf, i + 1);
590 dev_info->num_of_segments = num_of_segments;
591 rc = dcssblk_is_continuous(dev_info);
592 if (rc < 0)
593 goto seg_list_del;
594
595 dev_info->start = dcssblk_find_lowest_addr(dev_info);
596 dev_info->end = dcssblk_find_highest_addr(dev_info);
344 597
345 strcpy(dev_info->segment_name, local_buf); 598 dev_set_name(&dev_info->dev, dev_info->segment_name);
346 dev_set_name(&dev_info->dev, local_buf);
347 dev_info->dev.release = dcssblk_release_segment; 599 dev_info->dev.release = dcssblk_release_segment;
348 INIT_LIST_HEAD(&dev_info->lh); 600 INIT_LIST_HEAD(&dev_info->lh);
349
350 dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK); 601 dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK);
351 if (dev_info->gd == NULL) { 602 if (dev_info->gd == NULL) {
352 rc = -ENOMEM; 603 rc = -ENOMEM;
353 goto free_dev_info; 604 goto seg_list_del;
354 } 605 }
355 dev_info->gd->major = dcssblk_major; 606 dev_info->gd->major = dcssblk_major;
356 dev_info->gd->fops = &dcssblk_devops; 607 dev_info->gd->fops = &dcssblk_devops;
@@ -360,59 +611,43 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
360 dev_info->gd->driverfs_dev = &dev_info->dev; 611 dev_info->gd->driverfs_dev = &dev_info->dev;
361 blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); 612 blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request);
362 blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); 613 blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);
363 /* 614
364 * load the segment
365 */
366 rc = segment_load(local_buf, SEGMENT_SHARED,
367 &dev_info->start, &dev_info->end);
368 if (rc < 0) {
369 segment_warning(rc, dev_info->segment_name);
370 goto dealloc_gendisk;
371 }
372 seg_byte_size = (dev_info->end - dev_info->start + 1); 615 seg_byte_size = (dev_info->end - dev_info->start + 1);
373 set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors 616 set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors
374 PRINT_INFO("Loaded segment %s, size = %lu Byte, " 617 PRINT_INFO("Loaded segment(s) %s, size = %lu Byte, "
375 "capacity = %lu (512 Byte) sectors\n", local_buf, 618 "capacity = %lu (512 Byte) sectors\n", local_buf,
376 seg_byte_size, seg_byte_size >> 9); 619 seg_byte_size, seg_byte_size >> 9);
377 620
378 dev_info->segment_type = rc;
379 dev_info->save_pending = 0; 621 dev_info->save_pending = 0;
380 dev_info->is_shared = 1; 622 dev_info->is_shared = 1;
381 dev_info->dev.parent = dcssblk_root_dev; 623 dev_info->dev.parent = dcssblk_root_dev;
382 624
383 /* 625 /*
384 * get minor, add to list 626 *get minor, add to list
385 */ 627 */
386 down_write(&dcssblk_devices_sem); 628 down_write(&dcssblk_devices_sem);
387 if (dcssblk_get_device_by_name(local_buf)) { 629 if (dcssblk_get_segment_by_name(local_buf)) {
388 up_write(&dcssblk_devices_sem);
389 rc = -EEXIST; 630 rc = -EEXIST;
390 goto unload_seg; 631 goto release_gd;
391 } 632 }
392 rc = dcssblk_assign_free_minor(dev_info); 633 rc = dcssblk_assign_free_minor(dev_info);
393 if (rc) { 634 if (rc)
394 up_write(&dcssblk_devices_sem); 635 goto release_gd;
395 PRINT_ERR("No free minor number available! "
396 "Unloading segment...\n");
397 goto unload_seg;
398 }
399 sprintf(dev_info->gd->disk_name, "dcssblk%d", 636 sprintf(dev_info->gd->disk_name, "dcssblk%d",
400 MINOR(disk_devt(dev_info->gd))); 637 MINOR(disk_devt(dev_info->gd)));
401 list_add_tail(&dev_info->lh, &dcssblk_devices); 638 list_add_tail(&dev_info->lh, &dcssblk_devices);
402 639
403 if (!try_module_get(THIS_MODULE)) { 640 if (!try_module_get(THIS_MODULE)) {
404 rc = -ENODEV; 641 rc = -ENODEV;
405 goto list_del; 642 goto dev_list_del;
406 } 643 }
407 /* 644 /*
408 * register the device 645 * register the device
409 */ 646 */
410 rc = device_register(&dev_info->dev); 647 rc = device_register(&dev_info->dev);
411 if (rc) { 648 if (rc) {
412 PRINT_ERR("Segment %s could not be registered RC=%d\n",
413 local_buf, rc);
414 module_put(THIS_MODULE); 649 module_put(THIS_MODULE);
415 goto list_del; 650 goto dev_list_del;
416 } 651 }
417 get_device(&dev_info->dev); 652 get_device(&dev_info->dev);
418 rc = device_create_file(&dev_info->dev, &dev_attr_shared); 653 rc = device_create_file(&dev_info->dev, &dev_attr_shared);
@@ -421,6 +656,9 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
421 rc = device_create_file(&dev_info->dev, &dev_attr_save); 656 rc = device_create_file(&dev_info->dev, &dev_attr_save);
422 if (rc) 657 if (rc)
423 goto unregister_dev; 658 goto unregister_dev;
659 rc = device_create_file(&dev_info->dev, &dev_attr_seglist);
660 if (rc)
661 goto unregister_dev;
424 662
425 add_disk(dev_info->gd); 663 add_disk(dev_info->gd);
426 664
@@ -434,7 +672,6 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
434 set_disk_ro(dev_info->gd,0); 672 set_disk_ro(dev_info->gd,0);
435 break; 673 break;
436 } 674 }
437 PRINT_DEBUG("Segment %s loaded successfully\n", local_buf);
438 up_write(&dcssblk_devices_sem); 675 up_write(&dcssblk_devices_sem);
439 rc = count; 676 rc = count;
440 goto out; 677 goto out;
@@ -445,20 +682,27 @@ unregister_dev:
445 dev_info->gd->queue = NULL; 682 dev_info->gd->queue = NULL;
446 put_disk(dev_info->gd); 683 put_disk(dev_info->gd);
447 device_unregister(&dev_info->dev); 684 device_unregister(&dev_info->dev);
448 segment_unload(dev_info->segment_name); 685 list_for_each_entry(seg_info, &dev_info->seg_list, lh) {
686 segment_unload(seg_info->segment_name);
687 }
449 put_device(&dev_info->dev); 688 put_device(&dev_info->dev);
450 up_write(&dcssblk_devices_sem); 689 up_write(&dcssblk_devices_sem);
451 goto out; 690 goto out;
452list_del: 691dev_list_del:
453 list_del(&dev_info->lh); 692 list_del(&dev_info->lh);
454 up_write(&dcssblk_devices_sem); 693release_gd:
455unload_seg:
456 segment_unload(local_buf);
457dealloc_gendisk:
458 blk_cleanup_queue(dev_info->dcssblk_queue); 694 blk_cleanup_queue(dev_info->dcssblk_queue);
459 dev_info->gd->queue = NULL; 695 dev_info->gd->queue = NULL;
460 put_disk(dev_info->gd); 696 put_disk(dev_info->gd);
461free_dev_info: 697 up_write(&dcssblk_devices_sem);
698seg_list_del:
699 if (dev_info == NULL)
700 goto out;
701 list_for_each_entry_safe(seg_info, temp, &dev_info->seg_list, lh) {
702 list_del(&seg_info->lh);
703 segment_unload(seg_info->segment_name);
704 kfree(seg_info);
705 }
462 kfree(dev_info); 706 kfree(dev_info);
463out: 707out:
464 kfree(local_buf); 708 kfree(local_buf);
@@ -473,6 +717,7 @@ static ssize_t
473dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 717dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
474{ 718{
475 struct dcssblk_dev_info *dev_info; 719 struct dcssblk_dev_info *dev_info;
720 struct segment_info *entry;
476 int rc, i; 721 int rc, i;
477 char *local_buf; 722 char *local_buf;
478 723
@@ -499,26 +744,28 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch
499 dev_info = dcssblk_get_device_by_name(local_buf); 744 dev_info = dcssblk_get_device_by_name(local_buf);
500 if (dev_info == NULL) { 745 if (dev_info == NULL) {
501 up_write(&dcssblk_devices_sem); 746 up_write(&dcssblk_devices_sem);
502 PRINT_WARN("Segment %s is not loaded!\n", local_buf); 747 PRINT_WARN("Device %s is not loaded!\n", local_buf);
503 rc = -ENODEV; 748 rc = -ENODEV;
504 goto out_buf; 749 goto out_buf;
505 } 750 }
506 if (atomic_read(&dev_info->use_count) != 0) { 751 if (atomic_read(&dev_info->use_count) != 0) {
507 up_write(&dcssblk_devices_sem); 752 up_write(&dcssblk_devices_sem);
508 PRINT_WARN("Segment %s is in use!\n", local_buf); 753 PRINT_WARN("Device %s is in use!\n", local_buf);
509 rc = -EBUSY; 754 rc = -EBUSY;
510 goto out_buf; 755 goto out_buf;
511 } 756 }
512 list_del(&dev_info->lh);
513 757
758 list_del(&dev_info->lh);
514 del_gendisk(dev_info->gd); 759 del_gendisk(dev_info->gd);
515 blk_cleanup_queue(dev_info->dcssblk_queue); 760 blk_cleanup_queue(dev_info->dcssblk_queue);
516 dev_info->gd->queue = NULL; 761 dev_info->gd->queue = NULL;
517 put_disk(dev_info->gd); 762 put_disk(dev_info->gd);
518 device_unregister(&dev_info->dev); 763 device_unregister(&dev_info->dev);
519 segment_unload(dev_info->segment_name); 764
520 PRINT_DEBUG("Segment %s unloaded successfully\n", 765 /* unload all related segments */
521 dev_info->segment_name); 766 list_for_each_entry(entry, &dev_info->seg_list, lh)
767 segment_unload(entry->segment_name);
768
522 put_device(&dev_info->dev); 769 put_device(&dev_info->dev);
523 up_write(&dcssblk_devices_sem); 770 up_write(&dcssblk_devices_sem);
524 771
@@ -550,6 +797,7 @@ static int
550dcssblk_release(struct inode *inode, struct file *filp) 797dcssblk_release(struct inode *inode, struct file *filp)
551{ 798{
552 struct dcssblk_dev_info *dev_info; 799 struct dcssblk_dev_info *dev_info;
800 struct segment_info *entry;
553 int rc; 801 int rc;
554 802
555 dev_info = inode->i_bdev->bd_disk->private_data; 803 dev_info = inode->i_bdev->bd_disk->private_data;
@@ -560,9 +808,11 @@ dcssblk_release(struct inode *inode, struct file *filp)
560 down_write(&dcssblk_devices_sem); 808 down_write(&dcssblk_devices_sem);
561 if (atomic_dec_and_test(&dev_info->use_count) 809 if (atomic_dec_and_test(&dev_info->use_count)
562 && (dev_info->save_pending)) { 810 && (dev_info->save_pending)) {
563 PRINT_INFO("Segment %s became idle and is being saved now\n", 811 PRINT_INFO("Device %s became idle and is being saved now\n",
564 dev_info->segment_name); 812 dev_info->segment_name);
565 segment_save(dev_info->segment_name); 813 list_for_each_entry(entry, &dev_info->seg_list, lh) {
814 segment_save(entry->segment_name);
815 }
566 dev_info->save_pending = 0; 816 dev_info->save_pending = 0;
567 } 817 }
568 up_write(&dcssblk_devices_sem); 818 up_write(&dcssblk_devices_sem);
@@ -602,7 +852,7 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio)
602 case SEG_TYPE_SC: 852 case SEG_TYPE_SC:
603 /* cannot write to these segments */ 853 /* cannot write to these segments */
604 if (bio_data_dir(bio) == WRITE) { 854 if (bio_data_dir(bio) == WRITE) {
605 PRINT_WARN("rejecting write to ro segment %s\n", 855 PRINT_WARN("rejecting write to ro device %s\n",
606 dev_name(&dev_info->dev)); 856 dev_name(&dev_info->dev));
607 goto fail; 857 goto fail;
608 } 858 }
@@ -658,7 +908,7 @@ static void
658dcssblk_check_params(void) 908dcssblk_check_params(void)
659{ 909{
660 int rc, i, j, k; 910 int rc, i, j, k;
661 char buf[9]; 911 char buf[DCSSBLK_PARM_LEN + 1];
662 struct dcssblk_dev_info *dev_info; 912 struct dcssblk_dev_info *dev_info;
663 913
664 for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0'); 914 for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0');
@@ -666,15 +916,16 @@ dcssblk_check_params(void)
666 for (j = i; (dcssblk_segments[j] != ',') && 916 for (j = i; (dcssblk_segments[j] != ',') &&
667 (dcssblk_segments[j] != '\0') && 917 (dcssblk_segments[j] != '\0') &&
668 (dcssblk_segments[j] != '(') && 918 (dcssblk_segments[j] != '(') &&
669 (j - i) < 8; j++) 919 (j < DCSSBLK_PARM_LEN); j++)
670 { 920 {
671 buf[j-i] = dcssblk_segments[j]; 921 buf[j-i] = dcssblk_segments[j];
672 } 922 }
673 buf[j-i] = '\0'; 923 buf[j-i] = '\0';
674 rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i); 924 rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i);
675 if ((rc >= 0) && (dcssblk_segments[j] == '(')) { 925 if ((rc >= 0) && (dcssblk_segments[j] == '(')) {
676 for (k = 0; buf[k] != '\0'; k++) 926 for (k = 0; (buf[k] != ':') && (buf[k] != '\0'); k++)
677 buf[k] = toupper(buf[k]); 927 buf[k] = toupper(buf[k]);
928 buf[k] = '\0';
678 if (!strncmp(&dcssblk_segments[j], "(local)", 7)) { 929 if (!strncmp(&dcssblk_segments[j], "(local)", 7)) {
679 down_read(&dcssblk_devices_sem); 930 down_read(&dcssblk_devices_sem);
680 dev_info = dcssblk_get_device_by_name(buf); 931 dev_info = dcssblk_get_device_by_name(buf);
@@ -741,10 +992,12 @@ module_exit(dcssblk_exit);
741 992
742module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444); 993module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444);
743MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, " 994MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, "
744 "comma-separated list, each name max. 8 chars.\n" 995 "comma-separated list, names in each set separated "
745 "Adding \"(local)\" to segment name equals echoing 0 to " 996 "by commas are separated by colons, each set contains "
746 "/sys/devices/dcssblk/<segment name>/shared after loading " 997 "names of contiguous segments and each name max. 8 chars.\n"
747 "the segment - \n" 998 "Adding \"(local)\" to the end of each set equals echoing 0 "
748 "e.g. segments=\"mydcss1,mydcss2,mydcss3(local)\""); 999 "to /sys/devices/dcssblk/<device name>/shared after loading "
1000 "the contiguous segments - \n"
1001 "e.g. segments=\"mydcss1,mydcss2:mydcss3,mydcss4(local)\"");
749 1002
750MODULE_LICENSE("GPL"); 1003MODULE_LICENSE("GPL");