2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
18 * called with scp->rw lock held exclusive
21 raw_ReadData( cm_scache_t *scp, osi_hyper_t *offsetp,
22 afs_uint32 length, char *bufferp, afs_uint32 *readp,
23 cm_user_t *userp, cm_req_t *reqp)
26 cm_buf_t *bufp = NULL;
27 osi_hyper_t fileLength;
30 osi_hyper_t bufferOffset;
31 long bufIndex, nbytes;
34 /* start by looking up the file's end */
35 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
36 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
40 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
42 /* now we have the entry locked, look up the length */
43 fileLength = scp->length;
45 /* adjust length down so that it won't go past EOF */
46 thyper.LowPart = length;
48 thyper = LargeIntegerAdd(*offsetp, thyper); /* where read should end */
50 if (LargeIntegerGreaterThan(thyper, fileLength)) {
51 /* we'd read past EOF, so just stop at fileLength bytes.
52 * Start by computing how many bytes remain in the file.
54 thyper = LargeIntegerSubtract(fileLength, *offsetp);
56 /* if we are past EOF, read 0 bytes */
57 if (LargeIntegerLessThanZero(thyper))
60 length = thyper.LowPart;
65 /* now, copy the data one buffer at a time,
66 * until we've filled the request packet
69 /* if we've copied all the data requested, we're done */
70 if (length <= 0) break;
72 /* otherwise, load up a buffer of data */
73 thyper.HighPart = offsetp->HighPart;
74 thyper.LowPart = offsetp->LowPart & ~(cm_data.blockSize-1);
75 if (!bufp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
81 lock_ReleaseWrite(&scp->rw);
83 code = buf_Get(scp, &thyper, reqp, &bufp);
85 lock_ObtainWrite(&scp->rw);
87 bufferOffset = thyper;
89 /* now get the data in the cache */
91 code = cm_SyncOp(scp, bufp, userp, reqp, 0,
92 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
96 cm_SyncOpDone(scp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
98 if (cm_HaveBuffer(scp, bufp, 0)) break;
100 /* otherwise, load the buffer and try again */
101 code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
109 } /* if (wrong buffer) ... */
111 /* now we have the right buffer loaded. Copy out the
112 * data from here to the user's buffer.
114 bufIndex = offsetp->LowPart & (cm_data.blockSize - 1);
116 /* and figure out how many bytes we want from this buffer */
117 nbytes = cm_data.blockSize - bufIndex; /* what remains in buffer */
118 if (nbytes > length) nbytes = length; /* don't go past EOF */
120 /* now copy the data */
121 memcpy(bufferp, bufp->datap + bufIndex, nbytes);
123 /* adjust lengthers, pointers, etc. */
126 thyper.LowPart = nbytes;
128 *offsetp = LargeIntegerAdd(thyper, *offsetp);
135 if (code == 0 && sequential)
136 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, reqp);
143 * called with scp->rw lock held exclusive
147 raw_WriteData( cm_scache_t *scp, osi_hyper_t *offsetp, afs_uint32 length, char *bufferp,
148 cm_user_t *userp, cm_req_t *reqp, afs_uint32 *writtenp)
152 osi_hyper_t fileLength; /* file's length at start of write */
153 osi_hyper_t minLength; /* don't read past this */
154 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
155 cm_buf_t *bufp = NULL;
156 osi_hyper_t thyper; /* hyper tmp variable */
157 osi_hyper_t bufferOffset;
158 afs_uint32 bufIndex; /* index in buffer where our data is */
160 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
161 afs_uint32 writeBackLength;
164 /* start by looking up the file's end */
165 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
166 CM_SCACHESYNC_NEEDCALLBACK
167 | CM_SCACHESYNC_SETSTATUS
168 | CM_SCACHESYNC_GETSTATUS);
172 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
174 /* now we have the entry locked, look up the length */
175 fileLength = scp->length;
176 minLength = fileLength;
177 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
178 minLength = scp->serverLength;
180 /* adjust file length if we extend past EOF */
181 thyper.LowPart = length;
183 thyper = LargeIntegerAdd(*offsetp, thyper); /* where write should end */
184 if (LargeIntegerGreaterThan(thyper, fileLength)) {
185 /* we'd write past EOF, so extend the file */
186 scp->mask |= CM_SCACHEMASK_LENGTH;
187 scp->length = thyper;
188 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
190 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
193 writeBackOffset = *offsetp;
194 writeBackLength = length;
196 /* now, copy the data one buffer at a time, until we've filled the
199 /* if we've copied all the data requested, we're done */
200 if (length <= 0) break;
202 /* otherwise, load up a buffer of data */
203 thyper.HighPart = offsetp->HighPart;
204 thyper.LowPart = offsetp->LowPart & ~(cm_data.blockSize-1);
205 if (!bufp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
208 lock_ReleaseMutex(&bufp->mx);
212 lock_ReleaseWrite(&scp->rw);
214 code = buf_Get(scp, &thyper, reqp, &bufp);
216 lock_ObtainMutex(&bufp->mx);
218 lock_ObtainWrite(&scp->rw);
222 bufferOffset = thyper;
224 /* now get the data in the cache */
226 code = cm_SyncOp(scp, bufp, userp, reqp, 0,
227 CM_SCACHESYNC_NEEDCALLBACK
228 | CM_SCACHESYNC_WRITE
229 | CM_SCACHESYNC_BUFLOCKED);
233 cm_SyncOpDone(scp, bufp,
234 CM_SCACHESYNC_NEEDCALLBACK
235 | CM_SCACHESYNC_WRITE
236 | CM_SCACHESYNC_BUFLOCKED);
238 /* If we're overwriting the entire buffer, or
239 * if we're writing at or past EOF, mark the
240 * buffer as current so we don't call
241 * cm_GetBuffer. This skips the fetch from the
242 * server in those cases where we're going to
243 * obliterate all the data in the buffer anyway,
244 * or in those cases where there is no useful
245 * data at the server to start with.
247 * Use minLength instead of scp->length, since
248 * the latter has already been updated by this
251 if (LargeIntegerGreaterThanOrEqualTo(bufp->offset, minLength) ||
252 LargeIntegerEqualTo(*offsetp, bufp->offset) &&
253 (length >= cm_data.blockSize ||
254 LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(*offsetp, ConvertLongToLargeInteger(length)), minLength))) {
255 if (length < cm_data.blockSize
256 && bufp->dataVersion == CM_BUF_VERSION_BAD)
257 memset(bufp->datap, 0,
259 bufp->dataVersion = scp->dataVersion;
262 if (cm_HaveBuffer(scp, bufp, 1)) break;
264 /* otherwise, load the buffer and try again */
265 lock_ReleaseMutex(&bufp->mx);
266 code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
267 lock_ReleaseWrite(&scp->rw);
268 lock_ObtainMutex(&bufp->mx);
269 lock_ObtainWrite(&scp->rw);
274 lock_ReleaseMutex(&bufp->mx);
279 } /* if (wrong buffer) ... */
281 /* now we have the right buffer loaded. Copy out the
282 * data from here to the user's buffer.
284 bufIndex = offsetp->LowPart & (cm_data.blockSize - 1);
286 /* and figure out how many bytes we want from this buffer */
287 nbytes = cm_data.blockSize - bufIndex; /* what remains in buffer */
289 nbytes = length; /* don't go past end of request */
291 /* now copy the data */
292 memcpy(bufp->datap + bufIndex, bufferp, nbytes);
293 buf_SetDirty(bufp, reqp, bufIndex, nbytes, userp);
295 /* adjust lengthers, pointers, etc. */
299 thyper.LowPart = nbytes;
301 *offsetp = LargeIntegerAdd(thyper, *offsetp);
309 lock_ReleaseMutex(&bufp->mx);
313 if (code == 0 && doWriteBack) {
314 rock_BkgStore_t *rockp = malloc(sizeof(*rockp));
317 code = cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_ASYNCSTORE);
319 rockp->length = writeBackLength;
320 rockp->offset = writeBackOffset;
322 cm_QueueBKGRequest(scp, cm_BkgStore, rockp, userp, reqp);
324 /* rock is freed by cm_BkgDaemon */
331 /* cm_SyncOpDone is called when cm_BkgStore completes */