Bug Summary

File:afs/afs_buffer.c
Location:line 400, column 5
Description:Assigned value is always the same as the existing value

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
14#include "afs/sysincludes.h"
15#include "afsincludes.h"
16#if !defined(UKERNEL)
17#include "h/param.h"
18#include "h/types.h"
19#include "h/time.h"
20#if defined(AFS_AIX31_ENV)
21#include "h/limits.h"
22#endif
23#if !defined(AFS_AIX_ENV) && !defined(AFS_SUN5_ENV) && !defined(AFS_SGI_ENV) && !defined(AFS_LINUX20_ENV)
24#include "h/kernel.h" /* Doesn't needed, so it should go */
25#endif
26#endif /* !defined(UKERNEL) */
27
28#include "afs/afs_osi.h"
29#include "afsint.h"
30#include "afs/lock.h"
31
32#if !defined(UKERNEL) && !defined(AFS_LINUX20_ENV)
33#include "h/buf.h"
34#endif /* !defined(UKERNEL) */
35
36#include "afs/stds.h"
37#include "afs/volerrors.h"
38#include "afs/exporter.h"
39#include "afs/prs_fs.h"
40#include "afs/afs_chunkops.h"
41#include "afs/dir.h"
42
43#include "afs/afs_stats.h"
44#include "afs/afs.h"
45
46#ifndef BUF_TIME_MAX0x7fffffff
47#define BUF_TIME_MAX0x7fffffff 0x7fffffff
48#endif
49#define NPB8 8 /* must be a pwer of 2 */
50static int afs_max_buffers; /* should be an integral multiple of NPB */
51
52/* page size */
53#define AFS_BUFFER_PAGESIZE2048 2048
54/* log page size */
55#define LOGPS11 11
56/* If you change any of this PH stuff, make sure you don't break DZap() */
57/* use last two bits for page */
58#define PHPAGEMASK3 3
59/* use next five bits for fid */
60#define PHFIDMASK124 124
61/* page hash table size - this is pretty intertwined with pHash */
62#define PHSIZE(3 + 124 + 1) (PHPAGEMASK3 + PHFIDMASK124 + 1)
63/* the pHash macro */
64#define pHash(fid,page)((((afs_int32)(fid)) & 124) | (page & 3)) ((((afs_int32)(fid)) & PHFIDMASK124) \
65 | (page & PHPAGEMASK3))
66
67#ifdef dirty
68#undef dirty /* XXX */
69#endif
70
71static struct buffer *Buffers = 0;
72static char *BufferData;
73
74#ifdef AFS_AIX_ENV
75extern struct buf *geteblk();
76#endif
77#ifdef AFS_FBSD_ENV1
78#define timecounterafs_timecounter afs_timecounter
79#endif
80
81/* A note on locking in 'struct buffer'
82 *
83 * afs_bufferLock protects the hash chain, and the 'lockers' field where that
84 * has a zero value. It must be held whenever lockers is incremented from zero.
85 *
86 * The individual buffer lock protects the contents of the structure, including
87 * the lockers field.
88 *
89 * For safety: afs_bufferLock and the individual buffer lock must be held
90 * when obtaining a reference on a structure. Only the individual buffer lock
91 * need be held when releasing a reference.
92 *
93 * The locking hierarchy is afs_bufferLock-> buffer.lock
94 *
95 */
96
97static afs_lock_t afs_bufferLock;
98static struct buffer *phTable[PHSIZE(3 + 124 + 1)]; /* page hash table */
99static int nbuffers;
100static afs_int32 timecounterafs_timecounter;
101
102/* Prototypes for static routines */
103static struct buffer *afs_newslot(struct dcache *adc, afs_int32 apage,
104 struct buffer *lp);
105
106static int dinit_flag = 0;
107void
108DInit(int abuffers)
109{
110 /* Initialize the venus buffer system. */
111 int i;
112 struct buffer *tb;
113
114 AFS_STATCNT(DInit)((afs_cmstats.callInfo.C_DInit)++);
115 if (dinit_flag)
116 return;
117 dinit_flag = 1;
118 /* round up to next multiple of NPB, since we allocate multiple pages per chunk */
119 abuffers = ((abuffers - 1) | (NPB8 - 1)) + 1;
120 afs_max_buffers = abuffers << 2; /* possibly grow up to 4 times as big */
121 LOCK_INIT(&afs_bufferLock, "afs_bufferLock")Lock_Init(&afs_bufferLock);
122 Buffers = afs_osi_Alloc(afs_max_buffers * sizeof(struct buffer));
123 osi_Assert(Buffers != NULL)(void)((Buffers != ((void *)0)) || (osi_AssertFailK( "Buffers != NULL"
, "/home/wollman/openafs/src/afs/afs_buffer.c", 123), 0))
;
124 timecounterafs_timecounter = 1;
125 afs_stats_cmperf.bufAlloced = nbuffers = abuffers;
126 for (i = 0; i < PHSIZE(3 + 124 + 1); i++)
127 phTable[i] = 0;
128 for (i = 0; i < abuffers; i++) {
129 if ((i & (NPB8 - 1)) == 0) {
130 /* time to allocate a fresh buffer */
131 BufferData = afs_osi_Alloc(AFS_BUFFER_PAGESIZE2048 * NPB8);
132 osi_Assert(BufferData != NULL)(void)((BufferData != ((void *)0)) || (osi_AssertFailK( "BufferData != NULL"
, "/home/wollman/openafs/src/afs/afs_buffer.c", 132), 0))
;
133 }
134 /* Fill in each buffer with an empty indication. */
135 tb = &Buffers[i];
136 tb->fid = NULLIDX(-1);
137 afs_reset_inode(&tb->inode);
138 tb->accesstime = 0;
139 tb->lockers = 0;
140 tb->data = &BufferData[AFS_BUFFER_PAGESIZE2048 * (i & (NPB8 - 1))];
141 tb->hashIndex = 0;
142 tb->dirty = 0;
143 AFS_RWLOCK_INIT(&tb->lock, "buffer lock")Lock_Init(&tb->lock);
144 }
145 return;
146}
147
148int
149DRead(struct dcache *adc, int page, struct DirBuffer *entry)
150{
151 /* Read a page from the disk. */
152 struct buffer *tb, *tb2;
153 struct osi_file *tfile;
154 int code;
155
156 AFS_STATCNT(DRead)((afs_cmstats.callInfo.C_DRead)++);
157
158 memset(entry, 0, sizeof(struct DirBuffer));
159
160 ObtainWriteLock(&afs_bufferLock, 256)do { ; if (!(&afs_bufferLock)->excl_locked && !
(&afs_bufferLock)->readers_reading) (&afs_bufferLock
) -> excl_locked = 2; else Afs_Lock_Obtain(&afs_bufferLock
, 2); (&afs_bufferLock)->pid_writer = (((__curthread()
)->td_proc)->p_pid ); (&afs_bufferLock)->src_indicator
= 256; } while (0)
;
161
162#define bufmatch(tb)(tb->page == page && tb->fid == adc->index) (tb->page == page && tb->fid == adc->index)
163#define buf_Front(head,parent,p){(parent)->hashNext = (p)->hashNext; (p)->hashNext= *
(head);*(head)=(p);}
{(parent)->hashNext = (p)->hashNext; (p)->hashNext= *(head);*(head)=(p);}
164
165 /* this apparently-complicated-looking code is simply an example of
166 * a little bit of loop unrolling, and is a standard linked-list
167 * traversal trick. It saves a few assignments at the the expense
168 * of larger code size. This could be simplified by better use of
169 * macros.
170 */
171 if ((tb = phTable[pHash(adc->index, page)((((afs_int32)(adc->index)) & 124) | (page & 3))])) {
172 if (bufmatch(tb)(tb->page == page && tb->fid == adc->index)) {
173 ObtainWriteLock(&tb->lock, 257)do { ; if (!(&tb->lock)->excl_locked && !(&
tb->lock)->readers_reading) (&tb->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&tb->lock, 2); (&tb->
lock)->pid_writer = (((__curthread())->td_proc)->p_pid
); (&tb->lock)->src_indicator = 257; } while (0)
;
174 tb->lockers++;
175 ReleaseWriteLock(&afs_bufferLock)do { ; (&afs_bufferLock)->excl_locked &= ~2; if ((
&afs_bufferLock)->wait_states) Afs_Lock_ReleaseR(&
afs_bufferLock); (&afs_bufferLock)->pid_writer=0; } while
(0)
;
176 tb->accesstime = timecounterafs_timecounter++;
177 AFS_STATS(afs_stats_cmperf.bufHits++)afs_stats_cmperf.bufHits++;
178 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); (&tb->lock)->pid_writer=0; } while (0)
;
179 entry->buffer = tb;
180 entry->data = tb->data;
181 return 0;
182 } else {
183 struct buffer **bufhead;
184 bufhead = &(phTable[pHash(adc->index, page)((((afs_int32)(adc->index)) & 124) | (page & 3))]);
185 while ((tb2 = tb->hashNext)) {
186 if (bufmatch(tb2)(tb2->page == page && tb2->fid == adc->index
)
) {
187 buf_Front(bufhead, tb, tb2){(tb)->hashNext = (tb2)->hashNext; (tb2)->hashNext= *
(bufhead);*(bufhead)=(tb2);}
;
188 ObtainWriteLock(&tb2->lock, 258)do { ; if (!(&tb2->lock)->excl_locked && !(
&tb2->lock)->readers_reading) (&tb2->lock) ->
excl_locked = 2; else Afs_Lock_Obtain(&tb2->lock, 2);
(&tb2->lock)->pid_writer = (((__curthread())->td_proc
)->p_pid ); (&tb2->lock)->src_indicator = 258; }
while (0)
;
189 tb2->lockers++;
190 ReleaseWriteLock(&afs_bufferLock)do { ; (&afs_bufferLock)->excl_locked &= ~2; if ((
&afs_bufferLock)->wait_states) Afs_Lock_ReleaseR(&
afs_bufferLock); (&afs_bufferLock)->pid_writer=0; } while
(0)
;
191 tb2->accesstime = timecounterafs_timecounter++;
192 AFS_STATS(afs_stats_cmperf.bufHits++)afs_stats_cmperf.bufHits++;
193 ReleaseWriteLock(&tb2->lock)do { ; (&tb2->lock)->excl_locked &= ~2; if ((&
tb2->lock)->wait_states) Afs_Lock_ReleaseR(&tb2->
lock); (&tb2->lock)->pid_writer=0; } while (0)
;
194 entry->buffer = tb2;
195 entry->data = tb2->data;
196 return 0;
197 }
198 if ((tb = tb2->hashNext)) {
199 if (bufmatch(tb)(tb->page == page && tb->fid == adc->index)) {
200 buf_Front(bufhead, tb2, tb){(tb2)->hashNext = (tb)->hashNext; (tb)->hashNext= *
(bufhead);*(bufhead)=(tb);}
;
201 ObtainWriteLock(&tb->lock, 259)do { ; if (!(&tb->lock)->excl_locked && !(&
tb->lock)->readers_reading) (&tb->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&tb->lock, 2); (&tb->
lock)->pid_writer = (((__curthread())->td_proc)->p_pid
); (&tb->lock)->src_indicator = 259; } while (0)
;
202 tb->lockers++;
203 ReleaseWriteLock(&afs_bufferLock)do { ; (&afs_bufferLock)->excl_locked &= ~2; if ((
&afs_bufferLock)->wait_states) Afs_Lock_ReleaseR(&
afs_bufferLock); (&afs_bufferLock)->pid_writer=0; } while
(0)
;
204 tb->accesstime = timecounterafs_timecounter++;
205 AFS_STATS(afs_stats_cmperf.bufHits++)afs_stats_cmperf.bufHits++;
206 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); (&tb->lock)->pid_writer=0; } while (0)
;
207 entry->buffer = tb;
208 entry->data = tb->data;
209 }
210 } else
211 break;
212 }
213 }
214 } else
215 tb2 = NULL((void *)0);
216
217 AFS_STATS(afs_stats_cmperf.bufMisses++)afs_stats_cmperf.bufMisses++;
218 /* can't find it */
219 /* The last thing we looked at was either tb or tb2 (or nothing). That
220 * is at least the oldest buffer on one particular hash chain, so it's
221 * a pretty good place to start looking for the truly oldest buffer.
222 */
223 tb = afs_newslot(adc, page, (tb ? tb : tb2));
224 if (!tb) {
225 ReleaseWriteLock(&afs_bufferLock)do { ; (&afs_bufferLock)->excl_locked &= ~2; if ((
&afs_bufferLock)->wait_states) Afs_Lock_ReleaseR(&
afs_bufferLock); (&afs_bufferLock)->pid_writer=0; } while
(0)
;
226 return EIO5;
227 }
228 ObtainWriteLock(&tb->lock, 260)do { ; if (!(&tb->lock)->excl_locked && !(&
tb->lock)->readers_reading) (&tb->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&tb->lock, 2); (&tb->
lock)->pid_writer = (((__curthread())->td_proc)->p_pid
); (&tb->lock)->src_indicator = 260; } while (0)
;
229 tb->lockers++;
230 ReleaseWriteLock(&afs_bufferLock)do { ; (&afs_bufferLock)->excl_locked &= ~2; if ((
&afs_bufferLock)->wait_states) Afs_Lock_ReleaseR(&
afs_bufferLock); (&afs_bufferLock)->pid_writer=0; } while
(0)
;
231 if (page * AFS_BUFFER_PAGESIZE2048 >= adc->f.chunkBytes) {
232 tb->fid = NULLIDX(-1);
233 afs_reset_inode(&tb->inode);
234 tb->lockers--;
235 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); (&tb->lock)->pid_writer=0; } while (0)
;
236 return EIO5;
237 }
238 tfile = afs_CFileOpen(&adc->f.inode)(void *)(*(afs_cacheType->open))(&adc->f.inode);
239 code =
240 afs_CFileRead(tfile, tb->page * AFS_BUFFER_PAGESIZE, tb->data,(*(afs_cacheType->fread))(tfile, tb->page * 2048, tb->
data, 2048)
241 AFS_BUFFER_PAGESIZE)(*(afs_cacheType->fread))(tfile, tb->page * 2048, tb->
data, 2048)
;
242 afs_CFileClose(tfile)(*(afs_cacheType->close))(tfile);
243 if (code < AFS_BUFFER_PAGESIZE2048) {
244 tb->fid = NULLIDX(-1);
245 afs_reset_inode(&tb->inode);
246 tb->lockers--;
247 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); (&tb->lock)->pid_writer=0; } while (0)
;
248 return EIO5;
249 }
250 /* Note that findslot sets the page field in the buffer equal to
251 * what it is searching for. */
252 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); (&tb->lock)->pid_writer=0; } while (0)
;
253 entry->buffer = tb;
254 entry->data = tb->data;
255 return 0;
256}
257
258static void
259FixupBucket(struct buffer *ap)
260{
261 struct buffer **lp, *tp;
262 int i;
263 /* first try to get it out of its current hash bucket, in which it
264 * might not be */
265 AFS_STATCNT(FixupBucket)((afs_cmstats.callInfo.C_FixupBucket)++);
266 i = ap->hashIndex;
267 lp = &phTable[i];
268 for (tp = *lp; tp; tp = tp->hashNext) {
269 if (tp == ap) {
270 *lp = tp->hashNext;
271 break;
272 }
273 lp = &tp->hashNext;
274 }
275 /* now figure the new hash bucket */
276 i = pHash(ap->fid, ap->page)((((afs_int32)(ap->fid)) & 124) | (ap->page & 3
))
;
277 ap->hashIndex = i; /* remember where we are for deletion */
278 ap->hashNext = phTable[i]; /* add us to the list */
279 phTable[i] = ap; /* at the front, since it's LRU */
280}
281
282/* lp is pointer to a fairly-old buffer */
283static struct buffer *
284afs_newslot(struct dcache *adc, afs_int32 apage, struct buffer *lp)
285{
286 /* Find a usable buffer slot */
287 afs_int32 i;
288 afs_int32 lt = 0;
289 struct buffer *tp;
290 struct osi_file *tfile;
291
292 AFS_STATCNT(afs_newslot)((afs_cmstats.callInfo.C_afs_newslot)++);
293 /* we take a pointer here to a buffer which was at the end of an
294 * LRU hash chain. Odds are, it's one of the older buffers, not
295 * one of the newer. Having an older buffer to start with may
296 * permit us to avoid a few of the assignments in the "typical
297 * case" for loop below.
298 */
299 if (lp && (lp->lockers == 0)) {
300 lt = lp->accesstime;
301 } else {
302 lp = NULL((void *)0);
303 }
304
305 /* timecounter might have wrapped, if machine is very very busy
306 * and stays up for a long time. Timecounter mustn't wrap twice
307 * (positive->negative->positive) before calling newslot, but that
308 * would require 2 billion consecutive cache hits... Anyway, the
309 * penalty is only that the cache replacement policy will be
310 * almost MRU for the next ~2 billion DReads... newslot doesn't
311 * get called nearly as often as DRead, so in order to avoid the
312 * performance penalty of using the hypers, it's worth doing the
313 * extra check here every time. It's probably cheaper than doing
314 * hcmp, anyway. There is a little performance hit resulting from
315 * resetting all the access times to 0, but it only happens once
316 * every month or so, and the access times will rapidly sort
317 * themselves back out after just a few more DReads.
318 */
319 if (timecounterafs_timecounter < 0) {
320 timecounterafs_timecounter = 1;
321 tp = Buffers;
322 for (i = 0; i < nbuffers; i++, tp++) {
323 tp->accesstime = 0;
324 if (!lp && !tp->lockers) /* one is as good as the rest, I guess */
325 lp = tp;
326 }
327 } else {
328 /* this is the typical case */
329 tp = Buffers;
330 for (i = 0; i < nbuffers; i++, tp++) {
331 if (tp->lockers == 0) {
332 if (!lp || tp->accesstime < lt) {
333 lp = tp;
334 lt = tp->accesstime;
335 }
336 }
337 }
338 }
339
340 if (lp == 0) {
341 /* No unlocked buffers. If still possible, allocate a new increment */
342 if (nbuffers + NPB8 > afs_max_buffers) {
343 /* There are no unlocked buffers -- this used to panic, but that
344 * seems extreme. To the best of my knowledge, all the callers
345 * of DRead are prepared to handle a zero return. Some of them
346 * just panic directly, but not all of them. */
347 afs_warn("afs: all buffers locked\n");
348 return 0;
349 }
350
351 BufferData = afs_osi_Alloc(AFS_BUFFER_PAGESIZE2048 * NPB8);
352 osi_Assert(BufferData != NULL)(void)((BufferData != ((void *)0)) || (osi_AssertFailK( "BufferData != NULL"
, "/home/wollman/openafs/src/afs/afs_buffer.c", 352), 0))
;
353 for (i = 0; i< NPB8; i++) {
354 /* Fill in each buffer with an empty indication. */
355 tp = &Buffers[i + nbuffers];
356 tp->fid = NULLIDX(-1);
357 afs_reset_inode(&tp->inode);
358 tp->accesstime = 0;
359 tp->lockers = 0;
360 tp->data = &BufferData[AFS_BUFFER_PAGESIZE2048 * i];
361 tp->hashIndex = 0;
362 tp->dirty = 0;
363 AFS_RWLOCK_INIT(&tp->lock, "buffer lock")Lock_Init(&tp->lock);
364 }
365 lp = &Buffers[nbuffers];
366 nbuffers += NPB8;
367 }
368
369 if (lp->dirty) {
370 /* see DFlush for rationale for not getting and locking the dcache */
371 tfile = afs_CFileOpen(&lp->inode)(void *)(*(afs_cacheType->open))(&lp->inode);
372 afs_CFileWrite(tfile, lp->page * AFS_BUFFER_PAGESIZE, lp->data,(*(afs_cacheType->fwrite))(tfile, lp->page * 2048, lp->
data, 2048)
373 AFS_BUFFER_PAGESIZE)(*(afs_cacheType->fwrite))(tfile, lp->page * 2048, lp->
data, 2048)
;
374 lp->dirty = 0;
375 afs_CFileClose(tfile)(*(afs_cacheType->close))(tfile);
376 AFS_STATS(afs_stats_cmperf.bufFlushDirty++)afs_stats_cmperf.bufFlushDirty++;
377 }
378
379 /* Now fill in the header. */
380 lp->fid = adc->index;
381 afs_copy_inode(&lp->inode, &adc->f.inode);
382 lp->page = apage;
383 lp->accesstime = timecounterafs_timecounter++;
384 FixupBucket(lp); /* move to the right hash bucket */
385
386 return lp;
387}
388
389void
390DRelease(struct DirBuffer *entry, int flag)
391{
392 struct buffer *tp;
393
394 AFS_STATCNT(DRelease)((afs_cmstats.callInfo.C_DRelease)++);
395
396 tp = entry->buffer;
397 if (tp == NULL((void *)0))
1
Taking false branch
398 return;
399
400 tp = entry->buffer;
2
Assigned value is always the same as the existing value
401 ObtainWriteLock(&tp->lock, 261)do { ; if (!(&tp->lock)->excl_locked && !(&
tp->lock)->readers_reading) (&tp->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&tp->lock, 2); (&tp->
lock)->pid_writer = (((__curthread())->td_proc)->p_pid
); (&tp->lock)->src_indicator = 261; } while (0)
;
402 tp->lockers--;
403 if (flag)
404 tp->dirty = 1;
405 ReleaseWriteLock(&tp->lock)do { ; (&tp->lock)->excl_locked &= ~2; if ((&
tp->lock)->wait_states) Afs_Lock_ReleaseR(&tp->lock
); (&tp->lock)->pid_writer=0; } while (0)
;
406}
407
408int
409DVOffset(struct DirBuffer *entry)
410{
411 struct buffer *bp;
412
413 AFS_STATCNT(DVOffset)((afs_cmstats.callInfo.C_DVOffset)++);
414
415 bp = entry->buffer;
416 return AFS_BUFFER_PAGESIZE2048 * bp->page
417 + (char *)entry->data - (char *)bp->data;
418}
419
420/*!
421 * Zap one dcache entry: destroy one FID's buffers.
422 *
423 * 1/1/91 - I've modified the hash function to take the page as well
424 * as the *fid, so that lookup will be a bit faster. That presents some
425 * difficulties for Zap, which now has to have some knowledge of the nature
426 * of the hash function. Oh well. This should use the list traversal
427 * method of DRead...
428 *
429 * \param adc The dcache entry to be zapped.
430 */
431void
432DZap(struct dcache *adc)
433{
434 int i;
435 /* Destroy all buffers pertaining to a particular fid. */
436 struct buffer *tb;
437
438 AFS_STATCNT(DZap)((afs_cmstats.callInfo.C_DZap)++);
439 ObtainReadLock(&afs_bufferLock)do { ; if (!((&afs_bufferLock)->excl_locked & 2)) (
(&afs_bufferLock)->readers_reading)++; else Afs_Lock_Obtain
(&afs_bufferLock, 1); (&afs_bufferLock)->pid_last_reader
= (((__curthread())->td_proc)->p_pid ); } while (0)
;
440
441 for (i = 0; i <= PHPAGEMASK3; i++)
442 for (tb = phTable[pHash(adc->index, i)((((afs_int32)(adc->index)) & 124) | (i & 3))]; tb; tb = tb->hashNext)
443 if (tb->fid == adc->index) {
444 ObtainWriteLock(&tb->lock, 262)do { ; if (!(&tb->lock)->excl_locked && !(&
tb->lock)->readers_reading) (&tb->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&tb->lock, 2); (&tb->
lock)->pid_writer = (((__curthread())->td_proc)->p_pid
); (&tb->lock)->src_indicator = 262; } while (0)
;
445 tb->fid = NULLIDX(-1);
446 afs_reset_inode(&tb->inode);
447 tb->dirty = 0;
448 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); (&tb->lock)->pid_writer=0; } while (0)
;
449 }
450 ReleaseReadLock(&afs_bufferLock)do { ; if (!(--((&afs_bufferLock)->readers_reading)) &&
(&afs_bufferLock)->wait_states) Afs_Lock_ReleaseW(&
afs_bufferLock) ; if ( (&afs_bufferLock)->pid_last_reader
== (((__curthread())->td_proc)->p_pid ) ) (&afs_bufferLock
)->pid_last_reader =0; } while (0)
;
451}
452
453static void
454DFlushBuffer(struct buffer *ab)
455{
456 struct osi_file *tfile;
457
458 tfile = afs_CFileOpen(&ab->inode)(void *)(*(afs_cacheType->open))(&ab->inode);
459 afs_CFileWrite(tfile, ab->page * AFS_BUFFER_PAGESIZE,(*(afs_cacheType->fwrite))(tfile, ab->page * 2048, ab->
data, 2048)
460 ab->data, AFS_BUFFER_PAGESIZE)(*(afs_cacheType->fwrite))(tfile, ab->page * 2048, ab->
data, 2048)
;
461 ab->dirty = 0; /* Clear the dirty flag */
462 afs_CFileClose(tfile)(*(afs_cacheType->close))(tfile);
463}
464
465void
466DFlushDCache(struct dcache *adc)
467{
468 int i;
469 struct buffer *tb;
470
471 ObtainReadLock(&afs_bufferLock)do { ; if (!((&afs_bufferLock)->excl_locked & 2)) (
(&afs_bufferLock)->readers_reading)++; else Afs_Lock_Obtain
(&afs_bufferLock, 1); (&afs_bufferLock)->pid_last_reader
= (((__curthread())->td_proc)->p_pid ); } while (0)
;
472
473 for (i = 0; i <= PHPAGEMASK3; i++)
474 for (tb = phTable[pHash(adc->index, i)((((afs_int32)(adc->index)) & 124) | (i & 3))]; tb; tb = tb->hashNext)
475 if (tb->fid == adc->index) {
476 ObtainWriteLock(&tb->lock, 701)do { ; if (!(&tb->lock)->excl_locked && !(&
tb->lock)->readers_reading) (&tb->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&tb->lock, 2); (&tb->
lock)->pid_writer = (((__curthread())->td_proc)->p_pid
); (&tb->lock)->src_indicator = 701; } while (0)
;
477 tb->lockers++;
478 ReleaseReadLock(&afs_bufferLock)do { ; if (!(--((&afs_bufferLock)->readers_reading)) &&
(&afs_bufferLock)->wait_states) Afs_Lock_ReleaseW(&
afs_bufferLock) ; if ( (&afs_bufferLock)->pid_last_reader
== (((__curthread())->td_proc)->p_pid ) ) (&afs_bufferLock
)->pid_last_reader =0; } while (0)
;
479 if (tb->dirty) {
480 DFlushBuffer(tb);
481 }
482 tb->lockers--;
483 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); (&tb->lock)->pid_writer=0; } while (0)
;
484 ObtainReadLock(&afs_bufferLock)do { ; if (!((&afs_bufferLock)->excl_locked & 2)) (
(&afs_bufferLock)->readers_reading)++; else Afs_Lock_Obtain
(&afs_bufferLock, 1); (&afs_bufferLock)->pid_last_reader
= (((__curthread())->td_proc)->p_pid ); } while (0)
;
485 }
486
487 ReleaseReadLock(&afs_bufferLock)do { ; if (!(--((&afs_bufferLock)->readers_reading)) &&
(&afs_bufferLock)->wait_states) Afs_Lock_ReleaseW(&
afs_bufferLock) ; if ( (&afs_bufferLock)->pid_last_reader
== (((__curthread())->td_proc)->p_pid ) ) (&afs_bufferLock
)->pid_last_reader =0; } while (0)
;
488}
489
490int
491DFlush(void)
492{
493 /* Flush all the modified buffers. */
494 int i;
495 struct buffer *tb;
496
497 AFS_STATCNT(DFlush)((afs_cmstats.callInfo.C_DFlush)++);
498 tb = Buffers;
499 ObtainReadLock(&afs_bufferLock)do { ; if (!((&afs_bufferLock)->excl_locked & 2)) (
(&afs_bufferLock)->readers_reading)++; else Afs_Lock_Obtain
(&afs_bufferLock, 1); (&afs_bufferLock)->pid_last_reader
= (((__curthread())->td_proc)->p_pid ); } while (0)
;
500 for (i = 0; i < nbuffers; i++, tb++) {
501 if (tb->dirty) {
502 ObtainWriteLock(&tb->lock, 263)do { ; if (!(&tb->lock)->excl_locked && !(&
tb->lock)->readers_reading) (&tb->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&tb->lock, 2); (&tb->
lock)->pid_writer = (((__curthread())->td_proc)->p_pid
); (&tb->lock)->src_indicator = 263; } while (0)
;
503 tb->lockers++;
504 ReleaseReadLock(&afs_bufferLock)do { ; if (!(--((&afs_bufferLock)->readers_reading)) &&
(&afs_bufferLock)->wait_states) Afs_Lock_ReleaseW(&
afs_bufferLock) ; if ( (&afs_bufferLock)->pid_last_reader
== (((__curthread())->td_proc)->p_pid ) ) (&afs_bufferLock
)->pid_last_reader =0; } while (0)
;
505 if (tb->dirty) {
506 /* it seems safe to do this I/O without having the dcache
507 * locked, since the only things that will update the data in
508 * a directory are the buffer package, which holds the relevant
509 * tb->lock while doing the write, or afs_GetDCache, which
510 * DZap's the directory while holding the dcache lock.
511 * It is not possible to lock the dcache or even call
512 * afs_GetDSlot to map the index to the dcache since the dir
513 * package's caller has some dcache object locked already (so
514 * we cannot lock afs_xdcache). In addition, we cannot obtain
515 * a dcache lock while holding the tb->lock of the same file
516 * since that can deadlock with DRead/DNew */
517 DFlushBuffer(tb);
518 }
519 tb->lockers--;
520 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); (&tb->lock)->pid_writer=0; } while (0)
;
521 ObtainReadLock(&afs_bufferLock)do { ; if (!((&afs_bufferLock)->excl_locked & 2)) (
(&afs_bufferLock)->readers_reading)++; else Afs_Lock_Obtain
(&afs_bufferLock, 1); (&afs_bufferLock)->pid_last_reader
= (((__curthread())->td_proc)->p_pid ); } while (0)
;
522 }
523 }
524 ReleaseReadLock(&afs_bufferLock)do { ; if (!(--((&afs_bufferLock)->readers_reading)) &&
(&afs_bufferLock)->wait_states) Afs_Lock_ReleaseW(&
afs_bufferLock) ; if ( (&afs_bufferLock)->pid_last_reader
== (((__curthread())->td_proc)->p_pid ) ) (&afs_bufferLock
)->pid_last_reader =0; } while (0)
;
525
526 return 0;
527}
528
529int
530DNew(struct dcache *adc, int page, struct DirBuffer *entry)
531{
532 /* Same as read, only do *not* even try to read the page, since it
533 * probably doesn't exist. */
534 struct buffer *tb;
535 AFS_STATCNT(DNew)((afs_cmstats.callInfo.C_DNew)++);
536
537 ObtainWriteLock(&afs_bufferLock, 264)do { ; if (!(&afs_bufferLock)->excl_locked && !
(&afs_bufferLock)->readers_reading) (&afs_bufferLock
) -> excl_locked = 2; else Afs_Lock_Obtain(&afs_bufferLock
, 2); (&afs_bufferLock)->pid_writer = (((__curthread()
)->td_proc)->p_pid ); (&afs_bufferLock)->src_indicator
= 264; } while (0)
;
538 if ((tb = afs_newslot(adc, page, NULL((void *)0))) == 0) {
539 ReleaseWriteLock(&afs_bufferLock)do { ; (&afs_bufferLock)->excl_locked &= ~2; if ((
&afs_bufferLock)->wait_states) Afs_Lock_ReleaseR(&
afs_bufferLock); (&afs_bufferLock)->pid_writer=0; } while
(0)
;
540 return EIO5;
541 }
542 /* extend the chunk, if needed */
543 /* Do it now, not in DFlush or afs_newslot when the data is written out,
544 * since now our caller has adc->lock writelocked, and we can't acquire
545 * that lock (or even map from a fid to a dcache) in afs_newslot or
546 * DFlush due to lock hierarchy issues */
547 if ((page + 1) * AFS_BUFFER_PAGESIZE2048 > adc->f.chunkBytes) {
548 afs_AdjustSize(adc, (page + 1) * AFS_BUFFER_PAGESIZE2048);
549 afs_WriteDCache(adc, 1);
550 }
551 ObtainWriteLock(&tb->lock, 265)do { ; if (!(&tb->lock)->excl_locked && !(&
tb->lock)->readers_reading) (&tb->lock) -> excl_locked
= 2; else Afs_Lock_Obtain(&tb->lock, 2); (&tb->
lock)->pid_writer = (((__curthread())->td_proc)->p_pid
); (&tb->lock)->src_indicator = 265; } while (0)
;
552 tb->lockers++;
553 ReleaseWriteLock(&afs_bufferLock)do { ; (&afs_bufferLock)->excl_locked &= ~2; if ((
&afs_bufferLock)->wait_states) Afs_Lock_ReleaseR(&
afs_bufferLock); (&afs_bufferLock)->pid_writer=0; } while
(0)
;
554 ReleaseWriteLock(&tb->lock)do { ; (&tb->lock)->excl_locked &= ~2; if ((&
tb->lock)->wait_states) Afs_Lock_ReleaseR(&tb->lock
); (&tb->lock)->pid_writer=0; } while (0)
;
555 entry->buffer = tb;
556 entry->data = tb->data;
557
558 return 0;
559}
560
561void
562shutdown_bufferpackage(void)
563{
564 struct buffer *tp;
565 int i;
566
567 AFS_STATCNT(shutdown_bufferpackage)((afs_cmstats.callInfo.C_shutdown_bufferpackage)++);
568 /* Free all allocated Buffers and associated buffer pages */
569 DFlush();
570 if (afs_cold_shutdown) {
571 dinit_flag = 0;
572 tp = Buffers;
573 for (i = 0; i < nbuffers; i += NPB8, tp += NPB8) {
574 afs_osi_Free(tp->data, NPB8 * AFS_BUFFER_PAGESIZE2048);
575 }
576 afs_osi_Free(Buffers, nbuffers * sizeof(struct buffer));
577 nbuffers = 0;
578 timecounterafs_timecounter = 1;
579 for (i = 0; i < PHSIZE(3 + 124 + 1); i++)
580 phTable[i] = 0;
581 memset(&afs_bufferLock, 0, sizeof(afs_lock_t));
582 }
583}