dasd.c

来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 2,133 行 · 第 1/5 页

C
2,133
字号
		MESSAGE (KERN_WARNING,                         "Unable to unregister from major no %d, rc = %d",                          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) {		MESSAGE (KERN_WARNING,                         "Cannot unregister from major no %d, rc = %d",                         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 *dasd_device_from_kdev (kdev_t kdev){	major_info_t *major_info;        dasd_device_t *device;	struct list_head *l;	unsigned long flags;        device = NULL;	spin_lock_irqsave (&dasd_major_lock, flags);	list_for_each (l, &dasd_major_info) {		major_info = list_entry (l, major_info_t, list);		if (major_info->gendisk.major == MAJOR (kdev)) {                        device = major_info->dasd_device[MINOR (kdev) >>                                                         DASD_PARTN_BITS];			break;                }	}	spin_unlock_irqrestore (&dasd_major_lock, flags);        return device;}/* * function: dasd_device_from_devno * finds the address of the device structure corresponding to the devno * supplied as argument in the major_info structures and returns * it or NULL when not found */static inline dasd_device_t **dasd_device_from_devno (int devno){	major_info_t *major_info;        dasd_device_t **device;	struct list_head *l;	int devindex;	unsigned long flags;	spin_lock_irqsave (&dasd_major_lock, flags);        devindex = dasd_devindex_from_devno (devno);        if (devindex < 0) {                spin_unlock_irqrestore (&dasd_major_lock, flags);                return NULL;        }        device = NULL;	list_for_each (l, &dasd_major_info) {		major_info = list_entry (l, major_info_t, list);		if (devindex < DASD_PER_MAJOR) {                        device = &major_info->dasd_device[devindex];                        break;		}		devindex -= DASD_PER_MAJOR;	}	spin_unlock_irqrestore (&dasd_major_lock, flags);	return device;}/* * function: dasd_features_from_devno * finds the device range corresponding to the devno * supplied as argument in the major_info structures and returns * the features set for it */static intdasd_features_from_devno (int devno){	dasd_range_t *temp;	int devindex = 0;	unsigned long flags;	struct list_head *l;	spin_lock_irqsave (&range_lock, flags);	list_for_each (l, &dasd_range_head.list) {		temp = list_entry (l, dasd_range_t, list);		if (devno >= temp->from && devno <= temp->to) {			spin_unlock_irqrestore (&range_lock, flags);			return temp->features;		}		devindex += temp->to - temp->from + 1;	}	spin_unlock_irqrestore (&range_lock, flags);	return -ENODEV;}/* * function: dasd_check_bp_block * checks the blocksize and returns 0 if valid. */static intdasd_check_bp_block (dasd_device_t *device){        int rc;        switch (device->sizes.bp_block) {        case 512:        case 1024:        case 2048:        case 4096:                rc = 0;                break;        default:                rc = -EMEDIUMTYPE;        }                return rc;}/******************************************************************************** * SECTION: managing dasd disciplines  ********************************************************************************//* anchor and spinlock for list of disciplines */static struct list_head dasd_disc_head = LIST_HEAD_INIT(dasd_disc_head);static spinlock_t discipline_lock = SPIN_LOCK_UNLOCKED;/* * function dasd_discipline_enq * chains the discpline given as argument to the tail of disiplines. * Exception: DIAG is always queued to the head, to ensure that CMS RESERVED * minidisks are invariably accessed using DIAG. */static inline voiddasd_discipline_enq (dasd_discipline_t *discipline){        if (strncmp (discipline->name, "DIAG", 4) == 0) {                list_add (&discipline->list, &dasd_disc_head);        } else {                list_add_tail (&discipline->list, &dasd_disc_head);        }}/* * function dasd_discipline_deq * removes the discipline given as argument from the list of disciplines */static inline voiddasd_discipline_deq (dasd_discipline_t * discipline){        if (&discipline->list) {                list_del (&discipline->list);        }}voiddasd_discipline_add (dasd_discipline_t * discipline){        unsigned long flags;        MOD_INC_USE_COUNT;	spin_lock_irqsave (&discipline_lock,flags);        dasd_discipline_enq (discipline);	spin_unlock_irqrestore (&discipline_lock,flags);        dasd_enable_ranges (&dasd_range_head,                             discipline,                             DASD_STATE_ONLINE);}void dasd_discipline_del (dasd_discipline_t * discipline){        unsigned long flags;        dasd_disable_ranges(&dasd_range_head,                            discipline,                             DASD_STATE_DEL,                             1);	spin_lock_irqsave (&discipline_lock,flags);        dasd_discipline_deq (discipline);	spin_unlock_irqrestore (&discipline_lock,flags);        MOD_DEC_USE_COUNT;}/* * function dasd_find_disc * checks the list of disciplines for the first one able to access the device */static inline dasd_discipline_t *dasd_find_disc (dasd_device_t * device, dasd_discipline_t *discipline){        dasd_discipline_t *t;        struct list_head *l = discipline ?                               &discipline->list : dasd_disc_head.next;        do {                t = list_entry(l,dasd_discipline_t,list);                if ( ( t->id_check == NULL ||                       t->id_check (&device->devinfo) == 0 ) &&                     ( t->check_characteristics == NULL ||                       t->check_characteristics (device) == 0 ) )                        break;                l = l->next;                if ( discipline ||                      l == &dasd_disc_head ) {                        t = NULL;                        break;                }         } while ( 1 );	return t;}/******************************************************************************** * SECTION: profiling stuff  ********************************************************************************/#ifdef CONFIG_PROC_FSstatic dasd_profile_info_t dasd_global_profile;#endif  /* CONFIG_PROC_FS */#ifdef DASD_PROFILE#define DASD_PROFILE_ON  1#define DASD_PROFILE_OFF 0static unsigned int dasd_profile_level = DASD_PROFILE_OFF;/* * macro: dasd_profile_add_counter * increments counter in global and local profiling structures * according to the value */#define dasd_profile_add_counter( value, counter, device ) \{ \        int ind; \        long help; \	for (ind = 0, help = value >> 2; \             ind < 31 && help; \             help = help >> 1, ind++) {} \	dasd_global_profile.counter[ind]++; \        device->profile.counter[ind]++; \}/* * function dasd_profile_add * adds the profiling information from the cqr given as argument to the * global and device specific profiling information */voiddasd_profile_add (ccw_req_t * cqr){	long strtime, irqtime, endtime, tottime; /* in microsecnds*/	long tottimeps, sectors;	dasd_device_t *device = cqr->device;	if (!cqr->req)		/* safeguard against abnormal cqrs */		return;        if ((!cqr->buildclk) ||            (!cqr->startclk) ||            (!cqr->stopclk ) ||            (!cqr->endclk  ) ||            (!(sectors = ((struct request *) (cqr->req))->nr_sectors)))                return;	strtime = ((cqr->startclk - cqr->buildclk) >> 12);	irqtime = ((cqr->stopclk - cqr->startclk) >> 12);	endtime = ((cqr->endclk - cqr->stopclk) >> 12);	tottime = ((cqr->endclk - cqr->buildclk) >> 12);	tottimeps = tottime / sectors;	if (!dasd_global_profile.dasd_io_reqs) {		memset (&dasd_global_profile, 0, sizeof (dasd_profile_info_t));	};	if (!device->profile.dasd_io_reqs) {		memset (&device->profile, 0, sizeof (dasd_profile_info_t));	};	dasd_global_profile.dasd_io_reqs++;	device->profile.dasd_io_reqs++;	dasd_global_profile.dasd_io_sects+=sectors;	device->profile.dasd_io_sects+=sectors;	dasd_profile_add_counter (sectors, dasd_io_secs, device);	dasd_profile_add_counter (tottime, dasd_io_times, device);	dasd_profile_add_counter (tottimeps, dasd_io_timps, device);	dasd_profile_add_counter (strtime, dasd_io_time1, device);	dasd_profile_add_counter (irqtime, dasd_io_time2, device);	dasd_profile_add_counter (irqtime / sectors, dasd_io_time2ps, device);	dasd_profile_add_counter (endtime, dasd_io_time3, device);}#endif /* DASD_PROFILE *//******************************************************************************** * SECTION: All the gendisk stuff  ********************************************************************************//******************************************************************************** * SECTION: Managing wrappers for ccwcache  ********************************************************************************//* * function dasd_alloc_request * tries to return space for a channel program of length cplength with * additional data of size datasize. * If the ccwcache cannot fulfill the request it tries the lowmem requests * before giving up finally. * FIXME: initialization of ccw_req_t should be done by function of ccwcache */ccw_req_t *dasd_alloc_request (char *magic, int cplength, int datasize,                     dasd_device_t *device){	ccw_req_t *cqr;        unsigned long size_needed;	unsigned long data_offset, ccw_offset;        dasd_lowmem_t *lowmem;         if ((cqr = ccw_alloc_request (magic, cplength, datasize)) != NULL) {                return cqr;        }	/* Sanity checks */	if (magic == NULL || datasize > PAGE_SIZE ||            cplength == 0 || (cplength * sizeof(ccw1_t)) > PAGE_SIZE)		BUG();        /* use lowmem page only for ERP or */        /* if there are less than 2 requests on queue */        if (device->queue.head != NULL &&            device->queue.head->next != NULL &&            device->queue.head->status != CQR_STATUS_ERROR) {                return NULL;        }	/* We try to keep things together in memory */	size_needed = (sizeof (ccw_req_t) + 7) & (~7L);	data_offset = ccw_offset = 0;	if (size_needed + datasize <= PAGE_SIZE) {		/* Keep data with the request */		data_offset = size_needed;		size_needed += (datasize + 7) & (~7L);	}	if (size_needed + cplength*sizeof(ccw1_t) <= PAGE_SIZE) {		/* Keep CCWs with request */		ccw_offset = size_needed;		size_needed += (cplength*sizeof(ccw1_t)) & (~7L);	}                /* take page from lowmem_pool for request */        list_for_each_entry (lowmem, &device->lowmem_pool, list) {                list_del (&lowmem->list);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?