Bug Summary

File:dir/buffer.c
Location:line 308, column 9
Description:Access to field 'dirty' results in a dereference of a null pointer (loaded from variable 'lp')

Annotated Source Code

1/*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10#include <afsconfig.h>
11#include <afs/param.h>
12
13#include <roken.h>
14
15#include <lock.h>
16
17#include "dir.h"
18
19#ifdef AFS_64BIT_IOPS_ENV1
20#define BUFFER_FID_SIZE(9*sizeof(int) + 2*sizeof(char*)) (9*sizeof(int) + 2*sizeof(char*))
21#else
22#define BUFFER_FID_SIZE(9*sizeof(int) + 2*sizeof(char*)) (6*sizeof(int) + 2*sizeof(char*))
23#endif
24
25struct buffer {
26 /* fid is used for Unique cache key + i/o addressing.
27 * fid size is based on 4 + size of inode and size of pointer
28 */
29 char fid[BUFFER_FID_SIZE(9*sizeof(int) + 2*sizeof(char*))];
30 afs_int32 page;
31 afs_int32 accesstime;
32 struct buffer *hashNext;
33 void *data;
34 char lockers;
35 char dirty;
36 char hashIndex;
37 struct Lock lock;
38};
39
40static_inlinestatic inline dir_file_t
41bufferDir(struct buffer *b)
42{
43 return (dir_file_t) &b->fid;
44}
45
46struct Lock afs_bufferLock;
47
48/* page size */
49#define BUFFER_PAGE_SIZE2048 2048
50/* log page size */
51#define LOGPS11 11
52/* page hash table size */
53#define PHSIZE32 32
54/* The hash table should be somewhat efficient even if there are only
55 * a few partitions (less than 32). So the hash for the fileserver is now
56 * based on the volume id. This means this macro is dependent upon the
57 * layout of DirHandle in viced/viced.h, vol/salvage.h and volser/salvage.h.
58 */
59#define pHash(fid)(((afs_int32 *)fid)[0] & (32 -1)) (((afs_int32 *)fid)[0] & (PHSIZE32-1))
60#define vHash(vid)(vid & (32 -1)) (vid & (PHSIZE32-1))
61
62/* admittedly system dependent, this is the maximum signed 32-bit value */
63#define BUFFER_LONG_MAX2147483647 2147483647
64#ifndef NULL((void *)0)
65#define NULL((void *)0) 0
66#endif
67
68static struct buffer **Buffers;
69
70char *BufferData;
71
72static struct buffer *phTable[PHSIZE32]; /* page hash table */
73static struct buffer *LastBuffer;
74int nbuffers;
75int timecounter;
76static int calls = 0, ios = 0;
77
78struct buffer *newslot(dir_file_t dir, afs_int32 apage,
79 struct buffer *lp);
80
81/* XXX - This sucks. The correct prototypes for these functions are ...
82 *
83 * extern void FidZero(DirHandle *);
84 * extern int FidEq(DirHandle *a, DirHandle *b);
85 * extern int ReallyRead(DirHandle *a, int block, char *data);
86 */
87
88extern void FidZero(dir_file_t);
89extern int FidEq(dir_file_t, dir_file_t);
90extern int ReallyRead(dir_file_t, int block, char *data);
91extern int ReallyWrite(dir_file_t, int block, char *data);
92extern void FidZap(dir_file_t);
93extern int FidVolEq(dir_file_t, afs_int32 vid);
94extern void FidCpy(dir_file_t, dir_file_t fromfile);
95
96extern void Die(char *msg);
97
98int
99DStat(int *abuffers, int *acalls, int *aios)
100{
101 *abuffers = nbuffers;
102 *acalls = calls;
103 *aios = ios;
104 return 0;
105}
106
107/**
108 * initialize the directory package.
109 *
110 * @param[in] abuffers size of directory buffer cache
111 *
112 * @return operation status
113 * @retval 0 success
114 */
115void
116DInit(int abuffers)
117{
118 /* Initialize the venus buffer system. */
119 int i, tsize;
120 struct buffer *tb;
121 char *tp;
122
123 Lock_Init(&afs_bufferLock);
124 /* Align each element of Buffers on a doubleword boundary */
125 tsize = (sizeof(struct buffer) + 7) & ~7;
126 tp = (char *)malloc(abuffers * tsize);
127 Buffers = (struct buffer **)malloc(abuffers * sizeof(struct buffer *));
128 BufferData = (char *)malloc(abuffers * BUFFER_PAGE_SIZE2048);
129 timecounter = 0;
130 LastBuffer = (struct buffer *)tp;
131 nbuffers = abuffers;
132 for (i = 0; i < PHSIZE32; i++)
133 phTable[i] = 0;
134 for (i = 0; i < abuffers; i++) {
135 /* Fill in each buffer with an empty indication. */
136 tb = (struct buffer *)tp;
137 Buffers[i] = tb;
138 tp += tsize;
139 FidZero(bufferDir(tb));
140 tb->accesstime = tb->lockers = 0;
141 tb->data = &BufferData[BUFFER_PAGE_SIZE2048 * i];
142 tb->hashIndex = 0;
143 tb->dirty = 0;
144 Lock_Init(&tb->lock);
145 }
146 return;
147}
148
149/**
150 * read a page out of a directory object.
151 *
152 * @param[in] fid directory object fid
153 * @param[in] page page in hash table to be read
154 *
155 * @return pointer to requested page in directory cache
156 * @retval NULL read failed
157 */
158int
159DRead(dir_file_t fid, int page, struct DirBuffer *entry)
160{
161 /* Read a page from the disk. */
162 struct buffer *tb, *tb2, **bufhead;
163
164 memset(entry, 0, sizeof(struct DirBuffer));
165
166 ObtainWriteLock(&afs_bufferLock)do { ; if (!(&afs_bufferLock)->excl_locked && !
(&afs_bufferLock)->readers_reading) (&afs_bufferLock
) -> excl_locked = 2; else Afs_Lock_Obtain(&afs_bufferLock
, 2); ; } while (0)
;
167 calls++;
168
169#define bufmatch(tb,fid)(tb->page == page && FidEq(bufferDir(tb), fid)) (tb->page == page && FidEq(bufferDir(tb), fid))
170#define buf_Front(head,parent,p){(parent)->hashNext = (p)->hashNext; (p)->hashNext= *
(head);*(head)=(p);}
{(parent)->hashNext = (p)->hashNext; (p)->hashNext= *(head);*(head)=(p);}
171
172 /* this apparently-complicated-looking code is simply an example of
173 * a little bit of loop unrolling, and is a standard linked-list
174 * traversal trick. It saves a few assignments at the the expense
175 * of larger code size. This could be simplified by better use of
176 * macros. With the use of these LRU queues, the old one-cache is
177 * probably obsolete.
178 */
179 if ((tb = phTable[pHash(fid)(((afs_int32 *)fid)[0] & (32 -1))])) { /* ASSMT HERE */
180 if (bufmatch(tb, fid)(tb->page == page && FidEq(bufferDir(tb), fid))) {
181 ObtainWriteLock(&tb->lock)do { ; if (!(&tb->lock)->excl_locked && !(&
tb->lock)->readers_reading) (&tb->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&tb->lock, 2); ; } while (0
)
;
182 tb->lockers++;
183 ReleaseWriteLock(&afs_bufferLock)do { ; (&afs_bufferLock)->excl_locked &= ~2; if ((
&afs_bufferLock)->wait_states) Afs_Lock_ReleaseR(&
afs_bufferLock); ; } while (0)
;
184 tb->accesstime = ++timecounter;
185 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); ; } while (0)
;
186 entry->buffer = tb;
187 entry->data = tb->data;
188 return 0;
189 } else {
190 bufhead = &(phTable[pHash(fid)(((afs_int32 *)fid)[0] & (32 -1))]);
191 while ((tb2 = tb->hashNext)) {
192 if (bufmatch(tb2, fid)(tb2->page == page && FidEq(bufferDir(tb2), fid))) {
193 buf_Front(bufhead, tb, tb2){(tb)->hashNext = (tb2)->hashNext; (tb2)->hashNext= *
(bufhead);*(bufhead)=(tb2);}
;
194 ObtainWriteLock(&tb2->lock)do { ; if (!(&tb2->lock)->excl_locked && !(
&tb2->lock)->readers_reading) (&tb2->lock) ->
excl_locked = 2; else Afs_Lock_Obtain(&tb2->lock, 2);
; } while (0)
;
195 tb2->lockers++;
196 ReleaseWriteLock(&afs_bufferLock)do { ; (&afs_bufferLock)->excl_locked &= ~2; if ((
&afs_bufferLock)->wait_states) Afs_Lock_ReleaseR(&
afs_bufferLock); ; } while (0)
;
197 tb2->accesstime = ++timecounter;
198 ReleaseWriteLock(&tb2->lock)do { ; (&tb2->lock)->excl_locked &= ~2; if ((&
tb2->lock)->wait_states) Afs_Lock_ReleaseR(&tb2->
lock); ; } while (0)
;
199 entry->buffer = tb2;
200 entry->data = tb2->data;
201 return 0;
202 }
203 if ((tb = tb2->hashNext)) { /* ASSIGNMENT HERE! */
204 if (bufmatch(tb, fid)(tb->page == page && FidEq(bufferDir(tb), fid))) {
205 buf_Front(bufhead, tb2, tb){(tb2)->hashNext = (tb)->hashNext; (tb)->hashNext= *
(bufhead);*(bufhead)=(tb);}
;
206 ObtainWriteLock(&tb->lock)do { ; if (!(&tb->lock)->excl_locked && !(&
tb->lock)->readers_reading) (&tb->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&tb->lock, 2); ; } while (0
)
;
207 tb->lockers++;
208 ReleaseWriteLock(&afs_bufferLock)do { ; (&afs_bufferLock)->excl_locked &= ~2; if ((
&afs_bufferLock)->wait_states) Afs_Lock_ReleaseR(&
afs_bufferLock); ; } while (0)
;
209 tb->accesstime = ++timecounter;
210 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); ; } while (0)
;
211 entry->buffer = tb;
212 entry->data = tb->data;
213 return 0;
214 }
215 } else
216 break;
217 }
218 }
219 } else
220 tb2 = NULL((void *)0);
221
222 /* can't find it */
223 /* The last thing we looked at was either tb or tb2 (or nothing). That
224 * is at least the oldest buffer on one particular hash chain, so it's
225 * a pretty good place to start looking for the truly oldest buffer.
226 */
227 tb = newslot(fid, page, (tb ? tb : tb2));
228 ios++;
229 ObtainWriteLock(&tb->lock)do { ; if (!(&tb->lock)->excl_locked && !(&
tb->lock)->readers_reading) (&tb->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&tb->lock, 2); ; } while (0
)
;
230 tb->lockers++;
231 ReleaseWriteLock(&afs_bufferLock)do { ; (&afs_bufferLock)->excl_locked &= ~2; if ((
&afs_bufferLock)->wait_states) Afs_Lock_ReleaseR(&
afs_bufferLock); ; } while (0)
;
232 if (ReallyRead(bufferDir(tb), tb->page, tb->data)) {
233 tb->lockers--;
234 FidZap(bufferDir(tb)); /* disaster */
235 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); ; } while (0)
;
236 return EIO5;
237 }
238 /* Note that findslot sets the page field in the buffer equal to
239 * what it is searching for.
240 */
241 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); ; } while (0)
;
242 entry->buffer = tb;
243 entry->data = tb->data;
244 return 0;
245}
246
247
248static int
249FixupBucket(struct buffer *ap)
250{
251 struct buffer **lp, *tp;
252 int i;
253
254 /* first try to get it out of its current hash bucket, in which it might not be */
255 i = ap->hashIndex;
256 lp = &phTable[i];
257 for (tp = *lp; tp; tp = tp->hashNext) {
258 if (tp == ap) {
259 *lp = tp->hashNext;
260 break;
261 }
262 lp = &tp->hashNext;
263 }
264 /* now figure the new hash bucket */
265 i = pHash(ap)(((afs_int32 *)ap)[0] & (32 -1));
266 ap->hashIndex = i; /* remember where we are for deletion */
267 ap->hashNext = phTable[i]; /* add us to the list */
268 phTable[i] = ap; /* at the front, since it's LRU */
269 return 0;
270}
271
272struct buffer *
273newslot(dir_file_t dir, afs_int32 apage, struct buffer *lp)
274{
275 /* Find a usable buffer slot */
276 afs_int32 i;
277 afs_int32 lt;
278 struct buffer **tbp;
279
280 if (lp && (lp->lockers == 0)) {
1
Taking false branch
281 lt = lp->accesstime;
282 } else {
283 lp = 0;
284 lt = BUFFER_LONG_MAX2147483647;
285 }
286
287 tbp = Buffers;
288 for (i = 0; i < nbuffers; i++, tbp++) {
2
Loop condition is false. Execution continues on line 298
289 if ((*tbp)->lockers == 0) {
290 if ((*tbp)->accesstime < lt) {
291 lp = (*tbp);
292 lt = (*tbp)->accesstime;
293 }
294 }
295 }
296
297 /* There are no unlocked buffers */
298 if (lp == 0) {
3
Taking true branch
299 if (lt < 0)
4
Taking false branch
300 Die("accesstime counter wrapped");
301 else
302 Die("all buffers locked");
303 }
304
305 /* We do not need to lock the buffer here because it has no lockers
306 * and the afs_bufferLock prevents other threads from zapping this
307 * buffer while we are writing it out */
308 if (lp->dirty) {
5
Access to field 'dirty' results in a dereference of a null pointer (loaded from variable 'lp')
309 if (ReallyWrite(bufferDir(lp), lp->page, lp->data))
310 Die("writing bogus buffer");
311 lp->dirty = 0;
312 }
313
314 /* Now fill in the header. */
315 FidZap(bufferDir(lp));
316 FidCpy(bufferDir(lp), dir); /* set this */
317 lp->page = apage;
318 lp->accesstime = ++timecounter;
319
320 FixupBucket(lp); /* move to the right hash bucket */
321
322 return lp;
323}
324
325/* Release a buffer, specifying whether or not the buffer has been modified
326 * by the locker. */
327void
328DRelease(struct DirBuffer *entry, int flag)
329{
330 struct buffer *bp;
331
332 bp = (struct buffer *) entry->buffer;
333 if (bp == NULL((void *)0))
334 return;
335 ObtainWriteLock(&bp->lock)do { ; if (!(&bp->lock)->excl_locked && !(&
bp->lock)->readers_reading) (&bp->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&bp->lock, 2); ; } while (0
)
;
336 bp->lockers--;
337 if (flag)
338 bp->dirty = 1;
339 ReleaseWriteLock(&bp->lock)do { ; (&bp->lock)->excl_locked &= ~2; if ((&
bp->lock)->wait_states) Afs_Lock_ReleaseR(&bp->lock
); ; } while (0)
;
340}
341
342/* Return the byte within a file represented by a buffer pointer. */
343int
344DVOffset(struct DirBuffer *entry)
345{
346 struct buffer *bp;
347
348 bp = entry->buffer;
349 return BUFFER_PAGE_SIZE2048 * bp->page + (char *)entry->data - (char *)bp->data;
350}
351
352void
353DZap(dir_file_t dir)
354{
355 /* Destroy all buffers pertaining to a particular fid. */
356 struct buffer *tb;
357 ObtainReadLock(&afs_bufferLock)do { ; if (!((&afs_bufferLock)->excl_locked & 2) &&
!(&afs_bufferLock)->wait_states) (&afs_bufferLock
) -> readers_reading++; else Afs_Lock_Obtain(&afs_bufferLock
, 1); ; } while (0)
;
358 for (tb = phTable[pHash(dir)(((afs_int32 *)dir)[0] & (32 -1))]; tb; tb = tb->hashNext)
359 if (FidEq(bufferDir(tb), dir)) {
360 ObtainWriteLock(&tb->lock)do { ; if (!(&tb->lock)->excl_locked && !(&
tb->lock)->readers_reading) (&tb->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&tb->lock, 2); ; } while (0
)
;
361 FidZap(bufferDir(tb));
362 tb->dirty = 0;
363 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); ; } while (0)
;
364 }
365 ReleaseReadLock(&afs_bufferLock)do { ; if (!--(&afs_bufferLock)->readers_reading &&
(&afs_bufferLock)->wait_states) Afs_Lock_ReleaseW(&
afs_bufferLock) ; ; } while (0)
;
366}
367
368int
369DFlushVolume(afs_int32 vid)
370{
371 /* Flush all data and release all inode handles for a particular volume */
372 struct buffer *tb;
373 int code, rcode = 0;
374 ObtainReadLock(&afs_bufferLock)do { ; if (!((&afs_bufferLock)->excl_locked & 2) &&
!(&afs_bufferLock)->wait_states) (&afs_bufferLock
) -> readers_reading++; else Afs_Lock_Obtain(&afs_bufferLock
, 1); ; } while (0)
;
375 for (tb = phTable[vHash(vid)(vid & (32 -1))]; tb; tb = tb->hashNext)
376 if (FidVolEq(bufferDir(tb), vid)) {
377 ObtainWriteLock(&tb->lock)do { ; if (!(&tb->lock)->excl_locked && !(&
tb->lock)->readers_reading) (&tb->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&tb->lock, 2); ; } while (0
)
;
378 if (tb->dirty) {
379 code = ReallyWrite(bufferDir(tb), tb->page, tb->data);
380 if (code && !rcode)
381 rcode = code;
382 tb->dirty = 0;
383 }
384 FidZap(bufferDir(tb));
385 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); ; } while (0)
;
386 }
387 ReleaseReadLock(&afs_bufferLock)do { ; if (!--(&afs_bufferLock)->readers_reading &&
(&afs_bufferLock)->wait_states) Afs_Lock_ReleaseW(&
afs_bufferLock) ; ; } while (0)
;
388 return rcode;
389}
390
391int
392DFlushEntry(dir_file_t fid)
393{
394 /* Flush pages modified by one entry. */
395 struct buffer *tb;
396 int code;
397
398 ObtainReadLock(&afs_bufferLock)do { ; if (!((&afs_bufferLock)->excl_locked & 2) &&
!(&afs_bufferLock)->wait_states) (&afs_bufferLock
) -> readers_reading++; else Afs_Lock_Obtain(&afs_bufferLock
, 1); ; } while (0)
;
399 for (tb = phTable[pHash(fid)(((afs_int32 *)fid)[0] & (32 -1))]; tb; tb = tb->hashNext)
400 if (FidEq(bufferDir(tb), fid) && tb->dirty) {
401 ObtainWriteLock(&tb->lock)do { ; if (!(&tb->lock)->excl_locked && !(&
tb->lock)->readers_reading) (&tb->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&tb->lock, 2); ; } while (0
)
;
402 if (tb->dirty) {
403 code = ReallyWrite(bufferDir(tb), tb->page, tb->data);
404 if (code) {
405 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); ; } while (0)
;
406 ReleaseReadLock(&afs_bufferLock)do { ; if (!--(&afs_bufferLock)->readers_reading &&
(&afs_bufferLock)->wait_states) Afs_Lock_ReleaseW(&
afs_bufferLock) ; ; } while (0)
;
407 return code;
408 }
409 tb->dirty = 0;
410 }
411 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); ; } while (0)
;
412 }
413 ReleaseReadLock(&afs_bufferLock)do { ; if (!--(&afs_bufferLock)->readers_reading &&
(&afs_bufferLock)->wait_states) Afs_Lock_ReleaseW(&
afs_bufferLock) ; ; } while (0)
;
414 return 0;
415}
416
417int
418DFlush(void)
419{
420 /* Flush all the modified buffers. */
421 int i;
422 struct buffer **tbp;
423 afs_int32 code, rcode;
424
425 rcode = 0;
426 tbp = Buffers;
427 ObtainReadLock(&afs_bufferLock)do { ; if (!((&afs_bufferLock)->excl_locked & 2) &&
!(&afs_bufferLock)->wait_states) (&afs_bufferLock
) -> readers_reading++; else Afs_Lock_Obtain(&afs_bufferLock
, 1); ; } while (0)
;
428 for (i = 0; i < nbuffers; i++, tbp++) {
429 if ((*tbp)->dirty) {
430 ObtainWriteLock(&(*tbp)->lock)do { ; if (!(&(*tbp)->lock)->excl_locked &&
!(&(*tbp)->lock)->readers_reading) (&(*tbp)->
lock) -> excl_locked = 2; else Afs_Lock_Obtain(&(*tbp)
->lock, 2); ; } while (0)
;
431 (*tbp)->lockers++;
432 ReleaseReadLock(&afs_bufferLock)do { ; if (!--(&afs_bufferLock)->readers_reading &&
(&afs_bufferLock)->wait_states) Afs_Lock_ReleaseW(&
afs_bufferLock) ; ; } while (0)
;
433 if ((*tbp)->dirty) {
434 code = ReallyWrite(bufferDir(*tbp), (*tbp)->page, (*tbp)->data);
435 if (!code)
436 (*tbp)->dirty = 0; /* Clear the dirty flag */
437 if (code && !rcode) {
438 rcode = code;
439 }
440 }
441 (*tbp)->lockers--;
442 ReleaseWriteLock(&(*tbp)->lock)do { ; (&(*tbp)->lock)->excl_locked &= ~2; if (
(&(*tbp)->lock)->wait_states) Afs_Lock_ReleaseR(&
(*tbp)->lock); ; } while (0)
;
443 ObtainReadLock(&afs_bufferLock)do { ; if (!((&afs_bufferLock)->excl_locked & 2) &&
!(&afs_bufferLock)->wait_states) (&afs_bufferLock
) -> readers_reading++; else Afs_Lock_Obtain(&afs_bufferLock
, 1); ; } while (0)
;
444 }
445 }
446 ReleaseReadLock(&afs_bufferLock)do { ; if (!--(&afs_bufferLock)->readers_reading &&
(&afs_bufferLock)->wait_states) Afs_Lock_ReleaseW(&
afs_bufferLock) ; ; } while (0)
;
447 return rcode;
448}
449
450/* Same as read, only do *not* even try to read the page,
451 * since it probably doesn't exist.
452 */
453int
454DNew(dir_file_t dir, int page, struct DirBuffer *entry)
455{
456 struct buffer *tb;
457
458 memset(entry,0, sizeof(struct DirBuffer));
459
460 ObtainWriteLock(&afs_bufferLock)do { ; if (!(&afs_bufferLock)->excl_locked && !
(&afs_bufferLock)->readers_reading) (&afs_bufferLock
) -> excl_locked = 2; else Afs_Lock_Obtain(&afs_bufferLock
, 2); ; } while (0)
;
461 if ((tb = newslot(dir, page, 0)) == 0) {
462 ReleaseWriteLock(&afs_bufferLock)do { ; (&afs_bufferLock)->excl_locked &= ~2; if ((
&afs_bufferLock)->wait_states) Afs_Lock_ReleaseR(&
afs_bufferLock); ; } while (0)
;
463 return EIO5;
464 }
465 ObtainWriteLock(&tb->lock)do { ; if (!(&tb->lock)->excl_locked && !(&
tb->lock)->readers_reading) (&tb->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&tb->lock, 2); ; } while (0
)
;
466 tb->lockers++;
467 ReleaseWriteLock(&afs_bufferLock)do { ; (&afs_bufferLock)->excl_locked &= ~2; if ((
&afs_bufferLock)->wait_states) Afs_Lock_ReleaseR(&
afs_bufferLock); ; } while (0)
;
468 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); ; } while (0)
;
469
470 entry->buffer = tb;
471 entry->data = tb->data;
472
473 return 0;
474}