📄 dasd.c
字号:
count++; tmp = end; };}/* * dasd_parm_string holds a concatenated version of all 'dasd=' parameters * supplied in the parmline, which is later to be split by * dasd_split_parm_string * FIXME: why first concatenate then split ? */static char dasd_parm_string[1024] __initdata = { 0, };/* * function: dasd_setup * is invoked for any single 'dasd=' parameter supplied in the parmline * it merges all the arguments into dasd_parm_string */void __initdasd_setup (char *str, int *ints){ int len = strlen (dasd_parm_string); if (len != 0) { strcat (dasd_parm_string, ","); } strcat (dasd_parm_string, str);}/* * function: dasd_call_setup * is the 2.4 version of dasd_setup and * is invoked for any single 'dasd=' parameter supplied in the parmline */int __initdasd_call_setup (char *str){ int dummy; dasd_setup (str, &dummy); return 1;}int __initdasd_disciplines_setup (char *str){ return 1;}__setup ("dasd=", dasd_call_setup);__setup ("dasd_disciplines=", dasd_disciplines_setup);#endif /* MODULE *//* * function: dasd_strtoul * provides a wrapper to simple_strtoul to strip leading '0x' and * interpret any argument to dasd=[range,...] as hexadecimal */static inline intdasd_strtoul (char *str, char **stra, int* features){ char *temp=str; char *buffer; int val,i,start; buffer=(char*)kmalloc((strlen(str)+1)*sizeof(char),GFP_ATOMIC); if (buffer==NULL) { printk (KERN_WARNING PRINTK_HEADER "can't parse dasd= parameter %s due to low memory\n", str); } /* remove leading '0x' */ if (*temp == '0') { temp++; /* strip leading zero */ if (*temp == 'x') temp++; /* strip leading x */ } /* copy device no to buffer and convert to decimal */ for (i=0; temp[i]!='\0' && temp[i]!='(' && temp[i]!='-' && temp[i]!=' '; i++){ if (isxdigit(temp[i])) { buffer[i]=temp[i]; } else { return -EINVAL; } } buffer[i]='\0'; val = simple_strtoul (buffer, &buffer, 16); /* check for features - e.g. (ro) ; the '\0', ')' and '-' stops check */ *features = DASD_DEFAULT_FEATURES; if (temp[i]=='(') { while (temp[i]!='\0' && temp[i]!=')'&&temp[i]!='-') { start=++i; /* move next feature to buffer */ for (;temp[i]!='\0'&&temp[i]!=':'&&temp[i]!=')'&&temp[i]!='-';i++) buffer[i-start]=temp[i]; buffer[i-start]='\0'; if (strlen(buffer)) { if (!strcmp(buffer,"ro")) { /* handle 'ro' feature */ (*features) |= DASD_FEATURE_READONLY; break; } printk (KERN_WARNING PRINTK_HEADER "unsupported feature: %s, ignoring setting", buffer); } } } *stra = temp+i; return val;}/* * function: dasd_parse * examines the strings given in the string array str and * creates and adds the ranges to the apropriate lists */static intdasd_parse (char **str){ char *temp; int from, to; int features; int rc = 0; if (*str) { /* turn off probeonly mode, if any dasd parameter is present */ dasd_probeonly = 0; dasd_autodetect = 0; } while (*str) { temp = *str; from = 0; to = 0; if (strcmp ("autodetect", *str) == 0) { dasd_autodetect = 1; printk (KERN_INFO "turning to autodetection mode\n"); break; } else if (strcmp ("probeonly", *str) == 0) { dasd_probeonly = 1; printk (KERN_INFO "turning to probeonly mode\n"); break; } else { /* turn off autodetect mode, if any range is present */ dasd_autodetect = 0; from = dasd_strtoul (temp, &temp, &features); to = from; if (*temp == '-') { temp++; to = dasd_strtoul (temp, &temp, &features); } if (from == -EINVAL || to == -EINVAL ) { rc = -EINVAL; break; } else { dasd_add_range (from, to ,features); } } str++; } return rc;}/* SECTION: Dealing with devices registered to multiple major numbers */static spinlock_t dasd_major_lock = SPIN_LOCK_UNLOCKED;static major_info_t dasd_major_info[] = { { list:LIST_HEAD_INIT (dasd_major_info[1].list) }, { list:LIST_HEAD_INIT (dasd_major_info[0].list), gendisk:{ INIT_GENDISK (94, DASD_NAME, DASD_PARTN_BITS, DASD_PER_MAJOR) }, flags:DASD_MAJOR_INFO_IS_STATIC}};static major_info_t *get_new_major_info (void){ major_info_t *major_info = NULL; major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL); if (major_info) { static major_info_t temp_major_info = { gendisk:{ INIT_GENDISK (0, DASD_NAME, DASD_PARTN_BITS, DASD_PER_MAJOR)} }; memcpy (major_info, &temp_major_info, sizeof (major_info_t)); } return major_info;}/* * register major number * is called with the 'static' major_info during init of the driver or 'NULL' to * allocate an additional dynamic major. */static intdasd_register_major (major_info_t * major_info){ int rc = 0; int major; unsigned long flags; /* allocate dynamic major */ if (major_info == NULL) { major_info = get_new_major_info (); if (!major_info) { printk (KERN_WARNING PRINTK_HEADER "Cannot get memory to allocate another major number\n"); return -ENOMEM; } } major = major_info->gendisk.major; /* init devfs array */ major_info->gendisk.de_arr = (devfs_handle_t *) kmalloc (DASD_PER_MAJOR * sizeof (devfs_handle_t), GFP_KERNEL); if(major_info->gendisk.de_arr == NULL) goto out_gd_de_arr; memset (major_info->gendisk.de_arr, 0, DASD_PER_MAJOR * sizeof (devfs_handle_t)); /* init flags */ major_info->gendisk.flags = (char *) kmalloc (DASD_PER_MAJOR * sizeof (char), GFP_KERNEL); if(major_info->gendisk.flags == NULL) goto out_gd_flags; memset (major_info->gendisk.flags, 0, DASD_PER_MAJOR * sizeof (char)); /* register blockdevice */ rc = devfs_register_blkdev (major, DASD_NAME, &dasd_device_operations); if (rc < 0) { printk (KERN_WARNING PRINTK_HEADER "Cannot register to major no %d, rc = %d\n", major, rc); goto out_reg_blkdev; } else { major_info->flags |= DASD_MAJOR_INFO_REGISTERED; } /* Insert the new major info into dasd_major_info if needed (dynamic major) */ if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) { spin_lock_irqsave (&dasd_major_lock, flags); list_add_tail (&major_info->list, &dasd_major_info[0].list); spin_unlock_irqrestore (&dasd_major_lock, flags); } if (major == 0) { major = rc; rc = 0; } /* init array of devices */ major_info->dasd_device = (dasd_device_t **) kmalloc (DASD_PER_MAJOR * sizeof (dasd_device_t *), GFP_ATOMIC); if (!major_info->dasd_device) goto out_devices; memset (major_info->dasd_device, 0, DASD_PER_MAJOR * sizeof (dasd_device_t *)); /* init blk_size */ blk_size[major] = (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC); if (!blk_size[major]) goto out_blk_size; memset (blk_size[major], 0, (1 << MINORBITS) * sizeof (int)); /* init blksize_size */ blksize_size[major] = (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC); if (!blksize_size[major]) goto out_blksize_size; memset (blksize_size[major], 0, (1 << MINORBITS) * sizeof (int)); /* init_hardsect_size */ hardsect_size[major] = (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC); if (!hardsect_size[major]) goto out_hardsect_size; memset (hardsect_size[major], 0, (1 << MINORBITS) * sizeof (int)); /* init max_sectors */ max_sectors[major] = (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC); if (!max_sectors[major]) goto out_max_sectors; memset (max_sectors[major], 0, (1 << MINORBITS) * sizeof (int)); /* finally do the gendisk stuff */ major_info->gendisk.part = kmalloc ((1 << MINORBITS) * sizeof (struct hd_struct), GFP_ATOMIC); if (!major_info->gendisk.part) goto out_gendisk; memset (major_info->gendisk.part, 0, (1 << MINORBITS) * sizeof (struct hd_struct)); INIT_BLK_DEV (major, do_dasd_request, dasd_get_queue, NULL); major_info->gendisk.sizes = blk_size[major]; major_info->gendisk.major = major; add_gendisk (&major_info->gendisk); return major; /* error handling - free the prior allocated memory */ out_gendisk: kfree (max_sectors[major]); max_sectors[major] = NULL; out_max_sectors: kfree (hardsect_size[major]); hardsect_size[major] = NULL; out_hardsect_size: kfree (blksize_size[major]); blksize_size[major] = NULL; out_blksize_size: kfree (blk_size[major]); blk_size[major] = NULL; out_blk_size: kfree (major_info->dasd_device); out_devices: /* Delete the new major info from dasd_major_info list if needed (dynamic) +*/ if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) { spin_lock_irqsave (&dasd_major_lock, flags); list_del (&major_info->list); spin_unlock_irqrestore (&dasd_major_lock, flags); } /* unregister blockdevice */ rc = devfs_unregister_blkdev (major, DASD_NAME); if (rc < 0) { printk (KERN_WARNING PRINTK_HEADER "Unable to unregister from major no %d, rc = %d\n", major, rc); } else { major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED; }out_reg_blkdev: kfree (major_info->gendisk.flags);out_gd_flags: kfree (major_info->gendisk.de_arr);out_gd_de_arr: /* Delete the new major info from dasd_major_info if needed */ if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) { kfree (major_info); } return -ENOMEM;}static intdasd_unregister_major (major_info_t * major_info){ int rc = 0; int major; unsigned long flags; if (major_info == NULL) { return -EINVAL; } major = major_info->gendisk.major; INIT_BLK_DEV (major, NULL, NULL, NULL); del_gendisk (&major_info->gendisk); kfree (major_info->dasd_device); kfree (major_info->gendisk.part); kfree (blk_size[major]); kfree (blksize_size[major]); kfree (hardsect_size[major]); kfree (max_sectors[major]); blk_size[major] = NULL; blksize_size[major] = NULL; hardsect_size[major] = NULL; max_sectors[major] = NULL; rc = devfs_unregister_blkdev (major, DASD_NAME); if (rc < 0) { printk (KERN_WARNING PRINTK_HEADER "Cannot unregister from major no %d, rc = %d\n", major, rc); return rc; } else { major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED; } kfree (major_info->gendisk.flags); kfree (major_info->gendisk.de_arr); /* Delete the new major info from dasd_major_info if needed */ if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) { spin_lock_irqsave (&dasd_major_lock, flags); list_del (&major_info->list); spin_unlock_irqrestore (&dasd_major_lock, flags); kfree (major_info); } return rc;}/* * function: dasd_device_from_kdev * finds the device structure corresponding to the kdev supplied as argument * in the major_info structures and returns it or NULL when not found */dasd_device_t *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -