1 /* BLURB lgpl
2
3 Coda File System
4 Release 5
5
6 Copyright (c) 1987-2010 Carnegie Mellon University
7 Additional copyrights listed below
8
9 This code is distributed "AS IS" without warranty of any kind under
10 the terms of the GNU Library General Public Licence Version 2, as
11 shown in the file LICENSE. The technical and financial contributors to
12 Coda are listed in the file CREDITS.
13
14 Additional copyrights
15 none currently
16
17 #*/
18
19
20 #include <stdio.h>
21 #include "rds_private.h"
22
23 /************** NOTE: ***************/
24 /* we create our own transactions in the following routines, even
25 * though there is a tid in the interface. This might result in unreferenced
26 * objects if the thread which malloc'ed the object decides to abort. These
27 * routines have no way of knowing if such an event happens. Also, if the user
28 * free's then aborts, could have pointers into the free list objects.
29 *
30 * Interface has been changed so that if a user feels confident that his
31 * transactions are serialized, (the above problem won't arise), he can pass
32 * in a non-null tid ptr and it will be used. So if you aren't sure, make the
33 * tidptr is zero!
34 */
35
36 /* Preallocate nblocks of size bytes. Used to fill free lists with blocks
37 * of appropriate size so splits won't happen during rds_malloc().
38 */
39
40 int
rds_prealloc(size,nblocks,tid,err)41 rds_prealloc(size, nblocks, tid, err)
42 unsigned long size, nblocks;
43 rvm_tid_t *tid;
44 int *err;
45 {
46 free_block_t *bp;
47 rvm_tid_t *atid;
48 int i;
49 rvm_return_t rvmerr;
50
51 if (!HEAP_INIT) { /* Make sure the heap is initialized */
52 (*err) = EHEAP_INIT;
53 return -1;
54 }
55
56 /* Reserve bytes to hold the block's size and 2 guards, hidden from user */
57 /* Calculate the chunk size which holds that many bytes. */
58 size = ((size + RDS_BLOCK_HDR_SIZE) / RDS_CHUNK_SIZE) + 1;
59
60 /*
61 * if size == maxlist, then preallocing is pointless. The new object
62 * is placed on the beginning of the list, then every split after that
63 * will return that same block, and put_block will put it back at the head.
64 */
65 if (size == RDS_MAXLIST) {
66 *err = SUCCESS;
67 return -1;
68 }
69
70 if (tid == NULL) { /* Use input tid if non-null */
71 atid = rvm_malloc_tid();
72 rvmerr = rvm_begin_transaction(atid, restore);
73 if (rvmerr != RVM_SUCCESS) {
74 (*err) = (int) rvmerr;
75 rvm_free_tid(atid);
76 return -1;
77 }
78 } else
79 atid = tid;
80
81 /* Update statistics */
82 rvmerr = rvm_set_range(atid, &RDS_STATS, sizeof(rds_stats_t));
83 if ((rvmerr != RVM_SUCCESS) && (tid == NULL)) {
84 rvm_abort_transaction(atid);
85 (*err) = (int)rvmerr;
86 rvm_free_tid(atid);
87 return -1;
88 }
89 RDS_STATS.prealloc++; /* Update statistics. */
90
91 *err = SUCCESS; /* Initialize the error value */
92
93 /*
94 * Here I put the critical section within the loop. I don't think prealloc
95 * needs to be streamlined and it allows slightly more parallelization.
96 */
97
98 for (i = 0; i < nblocks; i++) {
99 START_CRITICAL;
100 {
101 /* Get a block */
102 bp = split(size, atid, err);
103 if (bp != NULL) {
104 /* Add the block to the appropriate list. */
105 put_block(bp, atid, err);
106 }
107 }
108 END_CRITICAL;
109
110 if (*err != SUCCESS) {
111 if (tid == NULL) {
112 rvm_abort_transaction(atid);
113 rvm_free_tid(atid);
114 }
115 return -1;
116 }
117 }
118
119 if (tid == NULL) {
120 rvmerr = rvm_end_transaction(atid, no_flush);
121 if (rvmerr != RVM_SUCCESS) {
122 (*err) = (int) rvmerr;
123 rvm_free_tid(atid);
124 return -1;
125 }
126
127 rvm_free_tid(atid);
128 }
129
130 *err = SUCCESS;
131 return 0;
132 }
133
134
135
136