⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sg.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (mx_sc_elems < 0)	    return mx_sc_elems; /* most likely -ENOMEM */	mem_src_arr = schp->buffer +		      (mx_sc_elems * sizeof(struct scatterlist));	for (k = 0, sclp = schp->buffer, rem_sz = blk_size;	     (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems);             ++k, rem_sz -= ret_sz, ++sclp) {	    if (first)                first = 0;            else {                num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz;                mem_src = SG_HEAP_PAGE;                p = sg_malloc(sfp, num, &ret_sz, &mem_src);                if (! p)                    break;            }            sclp->address = p;            sclp->length = ret_sz;	    mem_src_arr[k] = mem_src;	    SCSI_LOG_TIMEOUT(5,		printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n",                k, sclp->address, ret_sz, mem_src));        } /* end of for loop */	schp->k_use_sg = k;	SCSI_LOG_TIMEOUT(5,	    printk("sg_build_indi: k_use_sg=%d, rem_sz=%d\n", k, rem_sz));        schp->bufflen = blk_size;        if (rem_sz > 0)   /* must have failed */            return -ENOMEM;    }    return 0;}static int sg_write_xfer(Sg_request * srp){    sg_io_hdr_t * hp = &srp->header;    Sg_scatter_hold * schp = &srp->data;    int num_xfer = 0;    int j, k, onum, usglen, ksglen, res, ok;    int iovec_count = (int)hp->iovec_count;    int dxfer_dir = hp->dxfer_direction;    unsigned char * p;    unsigned char * up;    int new_interface = ('\0' == hp->interface_id) ? 0 : 1;    if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_TO_DEV == dxfer_dir) ||	(SG_DXFER_TO_FROM_DEV == dxfer_dir)) {	num_xfer = (int)(new_interface ?  hp->dxfer_len : hp->flags);	if (schp->bufflen < num_xfer)	    num_xfer = schp->bufflen;    }    if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags)))	return 0;    SCSI_LOG_TIMEOUT(4,	 printk("sg_write_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n",		num_xfer, iovec_count, schp->k_use_sg));    if (iovec_count) {	onum = iovec_count;	if ((k = verify_area(VERIFY_READ, hp->dxferp,			     size_sg_iovec * onum)))	    return k;    }    else	onum = 1;    if (0 == schp->k_use_sg) {  /* kernel has single buffer */	if (SG_USER_MEM != schp->buffer_mem_src) { /* else nothing to do */	    for (j = 0, p = schp->buffer; j < onum; ++j) {		res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);		if (res) return res;		usglen = (num_xfer > usglen) ? usglen : num_xfer;		__copy_from_user(p, up, usglen);		p += usglen;		num_xfer -= usglen;		if (num_xfer <= 0)		    return 0;            }	}    }    else {      /* kernel using scatter gather list */	struct scatterlist * sclp = (struct scatterlist *)schp->buffer;	char * mem_src_arr = sg_get_sgat_msa(schp);	ksglen = (int)sclp->length;	p = sclp->address;	for (j = 0, k = 0; j < onum; ++j) {	    res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);	    if (res) return res;	    for (; (k < schp->k_use_sg) && p;		 ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) {		ok = (SG_USER_MEM != mem_src_arr[k]);		if (usglen <= 0)		    break;		if (ksglen > usglen) {		    if (usglen >= num_xfer) {			if (ok) __copy_from_user(p, up, num_xfer);			return 0;		    }		    if (ok) __copy_from_user(p, up, usglen);		    p += usglen;		    ksglen -= usglen;                    break;		}		else {		    if (ksglen >= num_xfer) {			if (ok) __copy_from_user(p, up, num_xfer);			return 0;		    }		    if (ok) __copy_from_user(p, up, ksglen);		    up += ksglen;		    usglen -= ksglen;		}            }        }    }    return 0;}static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,		      int wr_xf, int * countp, unsigned char ** up){    int num_xfer = (int)hp->dxfer_len;    unsigned char * p;    int count, k;    sg_iovec_t u_iovec;    if (0 == sg_num) {	p = (unsigned char *)hp->dxferp;	if (wr_xf && ('\0' == hp->interface_id))	    count = (int)hp->flags; /* holds "old" input_size */	else	    count = num_xfer;    }    else {	__copy_from_user(&u_iovec,			 (unsigned char *)hp->dxferp + (ind * size_sg_iovec),			 size_sg_iovec);	p = (unsigned char *)u_iovec.iov_base;	count = (int)u_iovec.iov_len;    }    if ((k = verify_area(wr_xf ? VERIFY_READ : VERIFY_WRITE, p, count)))	return k;    if (up) *up = p;    if (countp) *countp = count;    return 0;}static char * sg_get_sgat_msa(Sg_scatter_hold * schp){    int elem_sz = sizeof(struct scatterlist) + sizeof(char);    int mx_sc_elems = (schp->sglist_len / elem_sz) - 1;    return schp->buffer + (sizeof(struct scatterlist) * mx_sc_elems);}static void sg_remove_scat(Sg_scatter_hold * schp){    SCSI_LOG_TIMEOUT(4, printk("sg_remove_scat: k_use_sg=%d\n",			       schp->k_use_sg));    if (schp->buffer && schp->sglist_len) {        int k, mem_src;        struct scatterlist * sclp = (struct scatterlist *)schp->buffer;	char * mem_src_arr = sg_get_sgat_msa(schp);	for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) {	    mem_src = mem_src_arr[k];	    SCSI_LOG_TIMEOUT(5,		printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n",                       k, sclp->address, sclp->length, mem_src));            sg_free(sclp->address, sclp->length, mem_src);            sclp->address = NULL;            sclp->length = 0;        }	sg_free(schp->buffer, schp->sglist_len, schp->buffer_mem_src);    }    else if (schp->buffer)	sg_free(schp->buffer, schp->b_malloc_len, schp->buffer_mem_src);    memset(schp, 0, sizeof(*schp));}static int sg_read_xfer(Sg_request * srp){    sg_io_hdr_t * hp = &srp->header;    Sg_scatter_hold * schp = &srp->data;    int num_xfer = 0;    int j, k, onum, usglen, ksglen, res, ok;    int iovec_count = (int)hp->iovec_count;    int dxfer_dir = hp->dxfer_direction;    unsigned char * p;    unsigned char * up;    int new_interface = ('\0' == hp->interface_id) ? 0 : 1;    if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_FROM_DEV == dxfer_dir) ||	(SG_DXFER_TO_FROM_DEV == dxfer_dir)) {	num_xfer =  hp->dxfer_len;	if (schp->bufflen < num_xfer)	    num_xfer = schp->bufflen;    }    if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags)))	return 0;    SCSI_LOG_TIMEOUT(4,	 printk("sg_read_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n",		num_xfer, iovec_count, schp->k_use_sg));    if (iovec_count) {	onum = iovec_count;	if ((k = verify_area(VERIFY_READ, hp->dxferp,			     size_sg_iovec * onum)))	    return k;    }    else	onum = 1;    if (0 == schp->k_use_sg) {  /* kernel has single buffer */	if (SG_USER_MEM != schp->buffer_mem_src) { /* else nothing to do */	    for (j = 0, p = schp->buffer; j < onum; ++j) {		res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);		if (res) return res;		usglen = (num_xfer > usglen) ? usglen : num_xfer;		__copy_to_user(up, p, usglen);		p += usglen;		num_xfer -= usglen;		if (num_xfer <= 0)		    return 0;	    }	}    }    else {      /* kernel using scatter gather list */	struct scatterlist * sclp = (struct scatterlist *)schp->buffer;	char * mem_src_arr = sg_get_sgat_msa(schp);	ksglen = (int)sclp->length;	p = sclp->address;	for (j = 0, k = 0; j < onum; ++j) {	    res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);	    if (res) return res;	    for (; (k < schp->k_use_sg) && p;		 ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) {		ok = (SG_USER_MEM != mem_src_arr[k]);		if (usglen <= 0)		    break;		if (ksglen > usglen) {		    if (usglen >= num_xfer) {			if (ok) __copy_to_user(up, p, num_xfer);			return 0;		    }		    if (ok) __copy_to_user(up, p, usglen);		    p += usglen;		    ksglen -= usglen;		    break;		}		else {		    if (ksglen >= num_xfer) {			if (ok) __copy_to_user(up, p, num_xfer);			return 0;		    }		    if (ok) __copy_to_user(up, p, ksglen);		    up += ksglen;		    usglen -= ksglen;		}	    }	}    }    return 0;}static void sg_read_oxfer(Sg_request * srp, char * outp, int num_read_xfer){    Sg_scatter_hold * schp = &srp->data;    SCSI_LOG_TIMEOUT(4, printk("sg_read_oxfer: num_read_xfer=%d\n",			       num_read_xfer));    if ((! outp) || (num_read_xfer <= 0))        return;    if(schp->k_use_sg > 0) {        int k, num;        struct scatterlist * sclp = (struct scatterlist *)schp->buffer;	for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) {            num = (int)sclp->length;            if (num > num_read_xfer) {                __copy_to_user(outp, sclp->address, num_read_xfer);                break;            }            else {                __copy_to_user(outp, sclp->address, num);                num_read_xfer -= num;                if (num_read_xfer <= 0)                    break;                outp += num;            }        }    }    else        __copy_to_user(outp, schp->buffer, num_read_xfer);}static void sg_build_reserve(Sg_fd * sfp, int req_size){    Sg_scatter_hold * schp = &sfp->reserve;    SCSI_LOG_TIMEOUT(4, printk("sg_build_reserve: req_size=%d\n", req_size));    do {        if (req_size < PAGE_SIZE)            req_size = PAGE_SIZE;	if (0 == sg_build_indi(schp, sfp, req_size))            return;        else            sg_remove_scat(schp);        req_size >>= 1; /* divide by 2 */    } while (req_size >  (PAGE_SIZE / 2));}static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size){    Sg_scatter_hold * req_schp = &srp->data;    Sg_scatter_hold * rsv_schp = &sfp->reserve;    srp->res_used = 1;    SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size));    size = (size + 1) & (~1);    /* round to even for aha1542 */    if (rsv_schp->k_use_sg > 0) {        int k, num;        int rem = size;        struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer;	for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) {            num = (int)sclp->length;            if (rem <= num) {		if (0 == k) {		    req_schp->k_use_sg = 0;		    req_schp->buffer = sclp->address;		}		else {    		    sfp->save_scat_len = num;    		    sclp->length = (unsigned)rem;    		    req_schp->k_use_sg = k + 1;    		    req_schp->sglist_len = rsv_schp->sglist_len;    		    req_schp->buffer = rsv_schp->buffer;		}		req_schp->bufflen = size;		req_schp->buffer_mem_src = rsv_schp->buffer_mem_src;		req_schp->b_malloc_len = rsv_schp->b_malloc_len;		break;            }            else                rem -= num;        }	if (k >= rsv_schp->k_use_sg)	    SCSI_LOG_TIMEOUT(1, printk("sg_link_reserve: BAD size\n"));    }    else {	req_schp->k_use_sg = 0;        req_schp->bufflen = size;        req_schp->buffer = rsv_schp->buffer;	req_schp->buffer_mem_src = rsv_schp->buffer_mem_src;        req_schp->b_malloc_len = rsv_schp->b_malloc_len;    }}static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp){    Sg_scatter_hold * req_schp = &srp->data;    Sg_scatter_hold * rsv_schp = &sfp->reserve;    SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->k_use_sg=%d\n",			       (int)req_schp->k_use_sg));    if ((rsv_schp->k_use_sg > 0) && (req_schp->k_use_sg > 0)) {        struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer;	if (sfp->save_scat_len > 0)	    (sclp + (req_schp->k_use_sg - 1))->length =                                        (unsigned)sfp->save_scat_len;        else            SCSI_LOG_TIMEOUT(1, printk(			"sg_unlink_reserve: BAD save_scat_len\n"));    }    req_schp->k_use_sg = 0;    req_schp->bufflen = 0;    req_schp->buffer = NULL;    req_schp->sglist_len = 0;    sfp->save_sca

⌨️ 快捷键说明

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