0001-Pull-in-FreeBSD-sglist.patch

Anonymous, 01/25/2011 06:12 AM

Download (22.6 KB)

View differences:

sys/conf/files
978 978
kern/subr_blist.c	standard
979 979
kern/subr_sbuf.c	standard
980 980
kern/subr_scanf.c	standard
981
kern/subr_sglist.c	standard
981 982
kern/subr_taskqueue.c	standard
982 983
kern/sys_generic.c	standard
983 984
kern/sys_pipe.c		standard
sys/kern/subr_sglist.c
1
/*-
2
 * Copyright (c) 2008 Yahoo!, Inc.
3
 * All rights reserved.
4
 * Written by: John Baldwin <jhb@FreeBSD.org>
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. Neither the name of the author nor the names of any co-contributors
15
 *    may be used to endorse or promote products derived from this software
16
 *    without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 */
30

  
31
#include <sys/cdefs.h>
32

  
33
#include <sys/param.h>
34
#include <sys/kernel.h>
35
#include <sys/malloc.h>
36
#include <sys/mbuf.h>
37
#include <sys/proc.h>
38
#include <sys/sglist.h>
39
#include <sys/uio.h>
40

  
41
#include <vm/vm.h>
42
#include <vm/pmap.h>
43
#include <vm/vm_map.h>
44

  
45
#include <sys/ktr.h>
46

  
47
static MALLOC_DEFINE(M_SGLIST, "sglist", "scatter/gather lists");
48

  
49
/*
50
 * Convenience macros to save the state of an sglist so it can be restored
51
 * if an append attempt fails.  Since sglist's only grow we only need to
52
 * save the current count of segments and the length of the ending segment.
53
 * Earlier segments will not be changed by an append, and the only change
54
 * that can occur to the ending segment is that it can be extended.
55
 */
56
struct sgsave {
57
	u_short sg_nseg;
58
	size_t ss_len;
59
};
60

  
61
#define	SGLIST_SAVE(sg, sgsave) do {					\
62
	(sgsave).sg_nseg = (sg)->sg_nseg;				\
63
	if ((sgsave).sg_nseg > 0)					\
64
		(sgsave).ss_len = (sg)->sg_segs[(sgsave).sg_nseg - 1].ss_len; \
65
	else								\
66
		(sgsave).ss_len = 0;					\
67
} while (0)
68

  
69
#define	SGLIST_RESTORE(sg, sgsave) do {					\
70
	(sg)->sg_nseg = (sgsave).sg_nseg;				\
71
	if ((sgsave).sg_nseg > 0)					\
72
		(sg)->sg_segs[(sgsave).sg_nseg - 1].ss_len = (sgsave).ss_len; \
73
} while (0)
74

  
75
/*
76
 * Append a single (paddr, len) to a sglist.  sg is the list and ss is
77
 * the current segment in the list.  If we run out of segments then
78
 * EFBIG will be returned.
79
 */
80
static __inline int
81
_sglist_append_range(struct sglist *sg, struct sglist_seg **ssp,
82
    vm_paddr_t paddr, size_t len)
83
{
84
	struct sglist_seg *ss;
85

  
86
	ss = *ssp;
87
	if (ss->ss_paddr + ss->ss_len == paddr)
88
		ss->ss_len += len;
89
	else {
90
		if (sg->sg_nseg == sg->sg_maxseg)
91
			return (EFBIG);
92
		ss++;
93
		ss->ss_paddr = paddr;
94
		ss->ss_len = len;
95
		sg->sg_nseg++;
96
		*ssp = ss;
97
	}
98
	return (0);
99
}
100

  
101
/*
102
 * Worker routine to append a virtual address range (either kernel or
103
 * user) to a scatter/gather list.
104
 */
105
static __inline int
106
_sglist_append_buf(struct sglist *sg, void *buf, size_t len, pmap_t pmap,
107
    size_t *donep)
108
{
109
	struct sglist_seg *ss;
110
	vm_offset_t vaddr, offset;
111
	vm_paddr_t paddr;
112
	size_t seglen;
113
	int error;
114

  
115
	if (donep)
116
		*donep = 0;
117
	if (len == 0)
118
		return (0);
119

  
120
	/* Do the first page.  It may have an offset. */
121
	vaddr = (vm_offset_t)buf;
122
	offset = vaddr & PAGE_MASK;
123
	if (pmap != NULL)
124
		paddr = pmap_extract(pmap, vaddr);
125
	else
126
		paddr = pmap_kextract(vaddr);
127
	seglen = MIN(len, PAGE_SIZE - offset);
128
	if (sg->sg_nseg == 0) {
129
		ss = sg->sg_segs;
130
		ss->ss_paddr = paddr;
131
		ss->ss_len = seglen;
132
		sg->sg_nseg = 1;
133
	} else {
134
		ss = &sg->sg_segs[sg->sg_nseg - 1];
135
		error = _sglist_append_range(sg, &ss, paddr, seglen);
136
		if (error)
137
			return (error);
138
	}
139
	vaddr += seglen;
140
	len -= seglen;
141
	if (donep)
142
		*donep += seglen;
143

  
144
	while (len > 0) {
145
		seglen = MIN(len, PAGE_SIZE);
146
		if (pmap != NULL)
147
			paddr = pmap_extract(pmap, vaddr);
148
		else
149
			paddr = pmap_kextract(vaddr);
150
		error = _sglist_append_range(sg, &ss, paddr, seglen);
151
		if (error)
152
			return (error);
153
		vaddr += seglen;
154
		len -= seglen;
155
		if (donep)
156
			*donep += seglen;
157
	}
158

  
159
	return (0);
160
}
161

  
162
/*
163
 * Determine the number of scatter/gather list elements needed to
164
 * describe a kernel virtual address range.
165
 */
166
int
167
sglist_count(void *buf, size_t len)
168
{
169
	vm_offset_t vaddr, vendaddr;
170
	vm_paddr_t lastaddr, paddr;
171
	int nsegs;
172

  
173
	if (len == 0)
174
		return (0);
175

  
176
	vaddr = trunc_page((vm_offset_t)buf);
177
	vendaddr = (vm_offset_t)buf + len;
178
	nsegs = 1;
179
	lastaddr = pmap_kextract(vaddr);
180
	vaddr += PAGE_SIZE;
181
	while (vaddr < vendaddr) {
182
		paddr = pmap_kextract(vaddr);
183
		if (lastaddr + PAGE_SIZE != paddr)
184
			nsegs++;
185
		lastaddr = paddr;
186
		vaddr += PAGE_SIZE;
187
	}
188
	return (nsegs);
189
}
190

  
191
/*
192
 * Allocate a scatter/gather list along with 'nsegs' segments.  The
193
 * 'mflags' parameters are the same as passed to malloc(9).  The caller
194
 * should use sglist_free() to free this list.
195
 */
196
struct sglist *
197
sglist_alloc(int nsegs, int mflags)
198
{
199
	struct sglist *sg;
200

  
201
	sg = kmalloc(sizeof(struct sglist) + nsegs * sizeof(struct sglist_seg),
202
	    M_SGLIST, mflags);
203
	if (sg == NULL)
204
		return (NULL);
205
	sglist_init(sg, nsegs, (struct sglist_seg *)(sg + 1));
206
	return (sg);
207
}
208

  
209
/*
210
 * Free a scatter/gather list allocated via sglist_allc().
211
 */
212
void
213
sglist_free(struct sglist *sg)
214
{
215

  
216
	if (refcount_release(&sg->sg_refs))
217
		kfree(sg, M_SGLIST);
218
}
219

  
220
/*
221
 * Append the segments to describe a single kernel virtual address
222
 * range to a scatter/gather list.  If there are insufficient
223
 * segments, then this fails with EFBIG.
224
 */
225
int
226
sglist_append(struct sglist *sg, void *buf, size_t len)
227
{
228
	struct sgsave save;
229
	int error;
230

  
231
	if (sg->sg_maxseg == 0)
232
		return (EINVAL);
233
	SGLIST_SAVE(sg, save);
234
	error = _sglist_append_buf(sg, buf, len, NULL, NULL);
235
	if (error)
236
		SGLIST_RESTORE(sg, save);
237
	return (error);
238
}
239

  
240
/*
241
 * Append a single physical address range to a scatter/gather list.
242
 * If there are insufficient segments, then this fails with EFBIG.
243
 */
244
int
245
sglist_append_phys(struct sglist *sg, vm_paddr_t paddr, size_t len)
246
{
247
	struct sglist_seg *ss;
248
	struct sgsave save;
249
	int error;
250

  
251
	if (sg->sg_maxseg == 0)
252
		return (EINVAL);
253
	if (len == 0)
254
		return (0);
255

  
256
	if (sg->sg_nseg == 0) {
257
		sg->sg_segs[0].ss_paddr = paddr;
258
		sg->sg_segs[0].ss_len = len;
259
		sg->sg_nseg = 1;
260
		return (0);
261
	}
262
	ss = &sg->sg_segs[sg->sg_nseg - 1];
263
	SGLIST_SAVE(sg, save);
264
	error = _sglist_append_range(sg, &ss, paddr, len);
265
	if (error)
266
		SGLIST_RESTORE(sg, save);
267
	return (error);
268
}
269

  
270
/*
271
 * Append the segments that describe a single mbuf chain to a
272
 * scatter/gather list.  If there are insufficient segments, then this
273
 * fails with EFBIG.
274
 */
275
int
276
sglist_append_mbuf(struct sglist *sg, struct mbuf *m0)
277
{
278
	struct sgsave save;
279
	struct mbuf *m;
280
	int error;
281

  
282
	if (sg->sg_maxseg == 0)
283
		return (EINVAL);
284

  
285
	error = 0;
286
	SGLIST_SAVE(sg, save);
287
	for (m = m0; m != NULL; m = m->m_next) {
288
		if (m->m_len > 0) {
289
			error = sglist_append(sg, m->m_data, m->m_len);
290
			if (error) {
291
				SGLIST_RESTORE(sg, save);
292
				return (error);
293
			}
294
		}
295
	}
296
	return (0);
297
}
298

  
299
/*
300
 * Append the segments that describe a single user address range to a
301
 * scatter/gather list.  If there are insufficient segments, then this
302
 * fails with EFBIG.
303
 */
304
int
305
sglist_append_user(struct sglist *sg, void *buf, size_t len, struct thread *td)
306
{
307
	struct sgsave save;
308
	int error;
309

  
310
	if (sg->sg_maxseg == 0)
311
		return (EINVAL);
312
	SGLIST_SAVE(sg, save);
313
	error = _sglist_append_buf(sg, buf, len,
314
	    vmspace_pmap(td->td_proc->p_vmspace), NULL);
315
	if (error)
316
		SGLIST_RESTORE(sg, save);
317
	return (error);
318
}
319

  
320
/*
321
 * Append the segments that describe a single uio to a scatter/gather
322
 * list.  If there are insufficient segments, then this fails with
323
 * EFBIG.
324
 */
325
int
326
sglist_append_uio(struct sglist *sg, struct uio *uio)
327
{
328
	struct iovec *iov;
329
	struct sgsave save;
330
	size_t resid, minlen;
331
	pmap_t pmap;
332
	int error, i;
333

  
334
	if (sg->sg_maxseg == 0)
335
		return (EINVAL);
336

  
337
	resid = uio->uio_resid;
338
	iov = uio->uio_iov;
339

  
340
	if (uio->uio_segflg == UIO_USERSPACE) {
341
		KASSERT(uio->uio_td != NULL,
342
		    ("sglist_append_uio: USERSPACE but no thread"));
343
		pmap = vmspace_pmap(uio->uio_td->td_proc->p_vmspace);
344
	} else
345
		pmap = NULL;
346

  
347
	error = 0;
348
	SGLIST_SAVE(sg, save);
349
	for (i = 0; i < uio->uio_iovcnt && resid != 0; i++) {
350
		/*
351
		 * Now at the first iovec to load.  Load each iovec
352
		 * until we have exhausted the residual count.
353
		 */
354
		minlen = MIN(resid, iov[i].iov_len);
355
		if (minlen > 0) {
356
			error = _sglist_append_buf(sg, iov[i].iov_base, minlen,
357
			    pmap, NULL);
358
			if (error) {
359
				SGLIST_RESTORE(sg, save);
360
				return (error);
361
			}
362
			resid -= minlen;
363
		}
364
	}
365
	return (0);
366
}
367

  
368
/*
369
 * Append the segments that describe at most 'resid' bytes from a
370
 * single uio to a scatter/gather list.  If there are insufficient
371
 * segments, then only the amount that fits is appended.
372
 */
373
int
374
sglist_consume_uio(struct sglist *sg, struct uio *uio, size_t resid)
375
{
376
	struct iovec *iov;
377
	size_t done;
378
	pmap_t pmap;
379
	int error, len;
380

  
381
	if (sg->sg_maxseg == 0)
382
		return (EINVAL);
383

  
384
	if (uio->uio_segflg == UIO_USERSPACE) {
385
		KASSERT(uio->uio_td != NULL,
386
		    ("sglist_consume_uio: USERSPACE but no thread"));
387
		pmap = vmspace_pmap(uio->uio_td->td_proc->p_vmspace);
388
	} else
389
		pmap = NULL;
390

  
391
	error = 0;
392
	while (resid > 0 && uio->uio_resid) {
393
		iov = uio->uio_iov;
394
		len = iov->iov_len;
395
		if (len == 0) {
396
			uio->uio_iov++;
397
			uio->uio_iovcnt--;
398
			continue;
399
		}
400
		if (len > resid)
401
			len = resid;
402

  
403
		/*
404
		 * Try to append this iovec.  If we run out of room,
405
		 * then break out of the loop.
406
		 */
407
		error = _sglist_append_buf(sg, iov->iov_base, len, pmap, &done);
408
		iov->iov_base = (char *)iov->iov_base + done;
409
		iov->iov_len -= done;
410
		uio->uio_resid -= done;
411
		uio->uio_offset += done;
412
		resid -= done;
413
		if (error)
414
			break;
415
	}
416
	return (0);
417
}
418

  
419
/*
420
 * Allocate and populate a scatter/gather list to describe a single
421
 * kernel virtual address range.
422
 */
423
struct sglist *
424
sglist_build(void *buf, size_t len, int mflags)
425
{
426
	struct sglist *sg;
427
	int nsegs;
428

  
429
	if (len == 0)
430
		return (NULL);
431

  
432
	nsegs = sglist_count(buf, len);
433
	sg = sglist_alloc(nsegs, mflags);
434
	if (sg == NULL)
435
		return (NULL);
436
	if (sglist_append(sg, buf, len) != 0) {
437
		sglist_free(sg);
438
		return (NULL);
439
	}
440
	return (sg);
441
}
442

  
443
/*
444
 * Clone a new copy of a scatter/gather list.
445
 */
446
struct sglist *
447
sglist_clone(struct sglist *sg, int mflags)
448
{
449
	struct sglist *new;
450

  
451
	if (sg == NULL)
452
		return (NULL);
453
	new = sglist_alloc(sg->sg_maxseg, mflags);
454
	if (new == NULL)
455
		return (NULL);
456
	new->sg_nseg = sg->sg_nseg;
457
	bcopy(sg->sg_segs, new->sg_segs, sizeof(struct sglist_seg) *
458
	    sg->sg_nseg);
459
	return (new);
460
}
461

  
462
/*
463
 * Calculate the total length of the segments described in a
464
 * scatter/gather list.
465
 */
466
size_t
467
sglist_length(struct sglist *sg)
468
{
469
	size_t space;
470
	int i;
471

  
472
	space = 0;
473
	for (i = 0; i < sg->sg_nseg; i++)
474
		space += sg->sg_segs[i].ss_len;
475
	return (space);
476
}
477

  
478
/*
479
 * Split a scatter/gather list into two lists.  The scatter/gather
480
 * entries for the first 'length' bytes of the 'original' list are
481
 * stored in the '*head' list and are removed from 'original'.
482
 *
483
 * If '*head' is NULL, then a new list will be allocated using
484
 * 'mflags'.  If M_NOWAIT is specified and the allocation fails,
485
 * ENOMEM will be returned.
486
 *
487
 * If '*head' is not NULL, it should point to an empty sglist.  If it
488
 * does not have enough room for the remaining space, then EFBIG will
489
 * be returned.  If '*head' is not empty, then EINVAL will be
490
 * returned.
491
 *
492
 * If 'original' is shared (refcount > 1), then EDOOFUS will be
493
 * returned.
494
 */
495
int
496
sglist_split(struct sglist *original, struct sglist **head, size_t length,
497
    int mflags)
498
{
499
	struct sglist *sg;
500
	size_t space, split;
501
	int count, i;
502

  
503
	if (original->sg_refs > 1)
504
		return (EDOOFUS);
505

  
506
	/* Figure out how big of a sglist '*head' has to hold. */
507
	count = 0;
508
	space = 0;
509
	split = 0;
510
	for (i = 0; i < original->sg_nseg; i++) {
511
		space += original->sg_segs[i].ss_len;
512
		count++;
513
		if (space >= length) {
514
			/*
515
			 * If 'length' falls in the middle of a
516
			 * scatter/gather list entry, then 'split'
517
			 * holds how much of that entry will remain in
518
			 * 'original'.
519
			 */
520
			split = space - length;
521
			break;
522
		}
523
	}
524

  
525
	/* Nothing to do, so leave head empty. */
526
	if (count == 0)
527
		return (0);
528

  
529
	if (*head == NULL) {
530
		sg = sglist_alloc(count, mflags);
531
		if (sg == NULL)
532
			return (ENOMEM);
533
		*head = sg;
534
	} else {
535
		sg = *head;
536
		if (sg->sg_maxseg < count)
537
			return (EFBIG);
538
		if (sg->sg_nseg != 0)
539
			return (EINVAL);
540
	}
541

  
542
	/* Copy 'count' entries to 'sg' from 'original'. */
543
	bcopy(original->sg_segs, sg->sg_segs, count *
544
	    sizeof(struct sglist_seg));
545
	sg->sg_nseg = count;
546

  
547
	/*
548
	 * If we had to split a list entry, fixup the last entry in
549
	 * 'sg' and the new first entry in 'original'.  We also
550
	 * decrement 'count' by 1 since we will only be removing
551
	 * 'count - 1' segments from 'original' now.
552
	 */
553
	if (split != 0) {
554
		count--;
555
		sg->sg_segs[count].ss_len -= split;
556
		original->sg_segs[count].ss_paddr =
557
		    sg->sg_segs[count].ss_paddr + split;
558
		original->sg_segs[count].ss_len = split;
559
	}
560

  
561
	/* Trim 'count' entries from the front of 'original'. */
562
	original->sg_nseg -= count;
563
	bcopy(original->sg_segs + count, original->sg_segs, count *
564
	    sizeof(struct sglist_seg));
565
	return (0);
566
}
567

  
568
/*
569
 * Append the scatter/gather list elements in 'second' to the
570
 * scatter/gather list 'first'.  If there is not enough space in
571
 * 'first', EFBIG is returned.
572
 */
573
int
574
sglist_join(struct sglist *first, struct sglist *second)
575
{
576
	struct sglist_seg *flast, *sfirst;
577
	int append;
578

  
579
	/* If 'second' is empty, there is nothing to do. */
580
	if (second->sg_nseg == 0)
581
		return (0);
582

  
583
	/*
584
	 * If the first entry in 'second' can be appended to the last entry
585
	 * in 'first' then set append to '1'.
586
	 */
587
	append = 0;
588
	flast = &first->sg_segs[first->sg_nseg - 1];
589
	sfirst = &second->sg_segs[0];
590
	if (first->sg_nseg != 0 &&
591
	    flast->ss_paddr + flast->ss_len == sfirst->ss_paddr)
592
		append = 1;
593

  
594
	/* Make sure 'first' has enough room. */
595
	if (first->sg_nseg + second->sg_nseg - append > first->sg_maxseg)
596
		return (EFBIG);
597

  
598
	/* Merge last in 'first' and first in 'second' if needed. */
599
	if (append)
600
		flast->ss_len += sfirst->ss_len;
601

  
602
	/* Append new segments from 'second' to 'first'. */
603
	bcopy(first->sg_segs + first->sg_nseg, second->sg_segs + append,
604
	    (second->sg_nseg - append) * sizeof(struct sglist_seg));
605
	first->sg_nseg += second->sg_nseg - append;
606
	sglist_reset(second);
607
	return (0);
608
}
609

  
610
/*
611
 * Generate a new scatter/gather list from a range of an existing
612
 * scatter/gather list.  The 'offset' and 'length' parameters specify
613
 * the logical range of the 'original' list to extract.  If that range
614
 * is not a subset of the length of 'original', then EINVAL is
615
 * returned.  The new scatter/gather list is stored in '*slice'.
616
 *
617
 * If '*slice' is NULL, then a new list will be allocated using
618
 * 'mflags'.  If M_NOWAIT is specified and the allocation fails,
619
 * ENOMEM will be returned.
620
 *
621
 * If '*slice' is not NULL, it should point to an empty sglist.  If it
622
 * does not have enough room for the remaining space, then EFBIG will
623
 * be returned.  If '*slice' is not empty, then EINVAL will be
624
 * returned.
625
 */
626
int
627
sglist_slice(struct sglist *original, struct sglist **slice, size_t offset,
628
    size_t length, int mflags)
629
{
630
	struct sglist *sg;
631
	size_t space, end, foffs, loffs;
632
	int count, i, fseg;
633

  
634
	/* Nothing to do. */
635
	if (length == 0)
636
		return (0);
637

  
638
	/* Figure out how many segments '*slice' needs to have. */
639
	end = offset + length;
640
	space = 0;
641
	count = 0;
642
	fseg = 0;
643
	foffs = loffs = 0;
644
	for (i = 0; i < original->sg_nseg; i++) {
645
		space += original->sg_segs[i].ss_len;
646
		if (space > offset) {
647
			/*
648
			 * When we hit the first segment, store its index
649
			 * in 'fseg' and the offset into the first segment
650
			 * of 'offset' in 'foffs'.
651
			 */
652
			if (count == 0) {
653
				fseg = i;
654
				foffs = offset - (space -
655
				    original->sg_segs[i].ss_len);
656
				//CTR1(KTR_DEV, "sglist_slice: foffs = %08lx", foffs);
657
			}
658
			count++;
659

  
660
			/*
661
			 * When we hit the last segment, break out of
662
			 * the loop.  Store the amount of extra space
663
			 * at the end of this segment in 'loffs'.
664
			 */
665
			if (space >= end) {
666
				loffs = space - end;
667
				//CTR1(KTR_DEV, "sglist_slice: loffs = %08lx", loffs);
668
				break;
669
			}
670
		}
671
	}
672

  
673
	/* If we never hit 'end', then 'length' ran off the end, so fail. */
674
	if (space < end)
675
		return (EINVAL);
676

  
677
	if (*slice == NULL) {
678
		sg = sglist_alloc(count, mflags);
679
		if (sg == NULL)
680
			return (ENOMEM);
681
		*slice = sg;
682
	} else {
683
		sg = *slice;
684
		if (sg->sg_maxseg < count)
685
			return (EFBIG);
686
		if (sg->sg_nseg != 0)
687
			return (EINVAL);
688
	}
689

  
690
	/*
691
	 * Copy over 'count' segments from 'original' starting at
692
	 * 'fseg' to 'sg'.
693
	 */
694
	bcopy(original->sg_segs + fseg, sg->sg_segs,
695
	    count * sizeof(struct sglist_seg));
696
	sg->sg_nseg = count;
697

  
698
	/* Fixup first and last segments if needed. */
699
	if (foffs != 0) {
700
		sg->sg_segs[0].ss_paddr += foffs;
701
		sg->sg_segs[0].ss_len -= foffs;
702
		//CTR2(KTR_DEV, "sglist_slice seg[0]: %08lx:%08lx",
703
		 //   (long)sg->sg_segs[0].ss_paddr, sg->sg_segs[0].ss_len);
704
	}
705
	if (loffs != 0) {
706
		sg->sg_segs[count - 1].ss_len -= loffs;
707
		//CTR2(KTR_DEV, "sglist_slice seg[%d]: len %08x", count - 1,
708
		 //   sg->sg_segs[count - 1].ss_len);
709
	}
710
	return (0);
711
}
sys/sys/sglist.h
1
/*-
2
 * Copyright (c) 2008 Yahoo!, Inc.
3
 * All rights reserved.
4
 * Written by: John Baldwin <jhb@FreeBSD.org>
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. Neither the name of the author nor the names of any co-contributors
15
 *    may be used to endorse or promote products derived from this software
16
 *    without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 *
30
 * $FreeBSD: src/sys/sys/sglist.h,v 1.1.2.2.4.1 2010/06/14 02:09:06 kensmith Exp $
31
 */
32

  
33
/*
34
 * A scatter/gather list describes a group of physical address ranges.
35
 * Each physical address range consists of a starting address and a
36
 * length.
37
 */
38

  
39
#ifndef __SGLIST_H__
40
#define	__SGLIST_H__
41

  
42
#include <sys/refcount.h>
43

  
44
struct sglist_seg {
45
	vm_paddr_t	ss_paddr;
46
	size_t		ss_len;
47
};
48

  
49
struct sglist {
50
	struct sglist_seg *sg_segs;
51
	int		sg_refs;
52
	u_short		sg_nseg;
53
	u_short		sg_maxseg;
54
};
55

  
56
struct mbuf;
57
struct uio;
58

  
59
static __inline void
60
sglist_init(struct sglist *sg, u_short maxsegs, struct sglist_seg *segs)
61
{
62

  
63
	sg->sg_segs = segs;
64
	sg->sg_nseg = 0;
65
	sg->sg_maxseg = maxsegs;
66
	refcount_init(&sg->sg_refs, 1);
67
}
68

  
69
static __inline void
70
sglist_reset(struct sglist *sg)
71
{
72

  
73
	sg->sg_nseg = 0;
74
}
75

  
76
static __inline struct sglist *
77
sglist_hold(struct sglist *sg)
78
{
79

  
80
	refcount_acquire(&sg->sg_refs);
81
	return (sg);
82
}
83

  
84
struct sglist *sglist_alloc(int nsegs, int mflags);
85
int	sglist_append(struct sglist *sg, void *buf, size_t len);
86
int	sglist_append_mbuf(struct sglist *sg, struct mbuf *m0);
87
int	sglist_append_phys(struct sglist *sg, vm_paddr_t paddr,
88
	    size_t len);
89
int	sglist_append_uio(struct sglist *sg, struct uio *uio);
90
int	sglist_append_user(struct sglist *sg, void *buf, size_t len,
91
	    struct thread *td);
92
struct sglist *sglist_build(void *buf, size_t len, int mflags);
93
struct sglist *sglist_clone(struct sglist *sg, int mflags);
94
int	sglist_consume_uio(struct sglist *sg, struct uio *uio, size_t resid);
95
int	sglist_count(void *buf, size_t len);
96
void	sglist_free(struct sglist *sg);
97
int	sglist_join(struct sglist *first, struct sglist *second);
98
size_t	sglist_length(struct sglist *sg);
99
int	sglist_slice(struct sglist *original, struct sglist **slice,
100
	    size_t offset, size_t length, int mflags);
101
int	sglist_split(struct sglist *original, struct sglist **head,
102
	    size_t length, int mflags);
103

  
104
#endif	/* !__SGLIST_H__ */
0
-