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
13 #define CM_BUF_SIZE 4096
14 long buf_bufferSize = CM_BUF_SIZE;
16 long ReadData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
17 cm_user_t *userp, long *readp)
22 osi_hyper_t fileLength;
25 osi_hyper_t bufferOffset;
26 long bufIndex, nbytes;
34 lock_ObtainWrite(&scp->rw);
36 /* start by looking up the file's end */
37 code = cm_SyncOp(scp, NULL, userp, &req, 0,
38 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
42 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
44 /* now we have the entry locked, look up the length */
45 fileLength = scp->length;
47 /* adjust count down so that it won't go past EOF */
48 thyper.LowPart = count;
50 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
52 if (LargeIntegerGreaterThan(thyper, fileLength)) {
53 /* we'd read past EOF, so just stop at fileLength bytes.
54 * Start by computing how many bytes remain in the file.
56 thyper = LargeIntegerSubtract(fileLength, offset);
58 /* if we are past EOF, read 0 bytes */
59 if (LargeIntegerLessThanZero(thyper))
62 count = thyper.LowPart;
67 /* now, copy the data one buffer at a time,
68 * until we've filled the request packet
71 /* if we've copied all the data requested, we're done */
72 if (count <= 0) break;
74 /* otherwise, load up a buffer of data */
75 thyper.HighPart = offset.HighPart;
76 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
77 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
83 lock_ReleaseWrite(&scp->rw);
85 code = buf_Get(scp, &thyper, &bufferp);
87 lock_ObtainWrite(&scp->rw);
89 bufferOffset = thyper;
91 /* now get the data in the cache */
93 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
94 CM_SCACHESYNC_NEEDCALLBACK
95 | CM_SCACHESYNC_READ);
99 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
101 if (cm_HaveBuffer(scp, bufferp, 0)) break;
103 /* otherwise, load the buffer and try again */
104 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
108 buf_Release(bufferp);
112 } /* if (wrong buffer) ... */
114 /* now we have the right buffer loaded. Copy out the
115 * data from here to the user's buffer.
117 bufIndex = offset.LowPart & (buf_bufferSize - 1);
119 /* and figure out how many bytes we want from this buffer */
120 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
121 if (nbytes > count) nbytes = count; /* don't go past EOF */
123 /* now copy the data */
124 memcpy(op, bufferp->datap + bufIndex, nbytes);
126 /* adjust counters, pointers, etc. */
129 thyper.LowPart = nbytes;
131 offset = LargeIntegerAdd(thyper, offset);
135 lock_ReleaseWrite(&scp->rw);
136 //lock_ReleaseMutex(&fidp->mx);
138 buf_Release(bufferp);
140 if (code == 0 && sequential)
141 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
147 long WriteData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
148 cm_user_t *userp, long *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 */
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
170 lock_ObtainWrite(&scp->rw);
172 /* start by looking up the file's end */
173 code = cm_SyncOp(scp, NULL, userp, &req, 0,
174 CM_SCACHESYNC_NEEDCALLBACK
175 | CM_SCACHESYNC_SETSTATUS
176 | CM_SCACHESYNC_GETSTATUS);
180 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
183 /* make sure we have a writable FD */
184 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
185 code = CM_ERROR_BADFDOP;
190 /* now we have the entry locked, look up the length */
191 fileLength = scp->length;
192 minLength = fileLength;
193 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
194 minLength = scp->serverLength;
196 /* adjust file length if we extend past EOF */
197 thyper.LowPart = count;
199 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
200 if (LargeIntegerGreaterThan(thyper, fileLength)) {
201 /* we'd write past EOF, so extend the file */
202 scp->mask |= CM_SCACHEMASK_LENGTH;
203 scp->length = thyper;
204 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
206 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
208 /* now, if the new position (thyper) and the old (offset) are in
209 * different storeback windows, remember to store back the previous
210 * storeback window when we're done with the write.
212 if ((thyper.LowPart & (-cm_chunkSize)) !=
213 (offset.LowPart & (-cm_chunkSize))) {
214 /* they're different */
216 writeBackOffset.HighPart = offset.HighPart;
217 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
222 /* now, copy the data one buffer at a time, until we've filled the
225 /* if we've copied all the data requested, we're done */
226 if (count <= 0) break;
228 /* handle over quota or out of space */
229 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
234 /* otherwise, load up a buffer of data */
235 thyper.HighPart = offset.HighPart;
236 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
237 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
240 lock_ReleaseMutex(&bufferp->mx);
241 buf_Release(bufferp);
244 lock_ReleaseWrite(&scp->rw);
246 code = buf_Get(scp, &thyper, &bufferp);
248 lock_ObtainMutex(&bufferp->mx);
249 lock_ObtainWrite(&scp->rw);
253 bufferOffset = thyper;
255 /* now get the data in the cache */
257 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
258 CM_SCACHESYNC_NEEDCALLBACK
259 | CM_SCACHESYNC_WRITE
260 | CM_SCACHESYNC_BUFLOCKED);
264 cm_SyncOpDone(scp, bufferp,
265 CM_SCACHESYNC_NEEDCALLBACK
266 | CM_SCACHESYNC_WRITE
267 | CM_SCACHESYNC_BUFLOCKED);
269 /* If we're overwriting the entire buffer, or
270 * if we're writing at or past EOF, mark the
271 * buffer as current so we don't call
272 * cm_GetBuffer. This skips the fetch from the
273 * server in those cases where we're going to
274 * obliterate all the data in the buffer anyway,
275 * or in those cases where there is no useful
276 * data at the server to start with.
278 * Use minLength instead of scp->length, since
279 * the latter has already been updated by this
282 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength) ||
283 LargeIntegerEqualTo(offset, bufferp->offset) &&
284 (count >= buf_bufferSize ||
285 LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset, ConvertLongToLargeInteger(count)), minLength))) {
286 if (count < buf_bufferSize
287 && bufferp->dataVersion == -1)
288 memset(bufferp->datap, 0,
290 bufferp->dataVersion = scp->dataVersion;
293 if (cm_HaveBuffer(scp, bufferp, 1)) break;
295 /* otherwise, load the buffer and try again */
296 lock_ReleaseMutex(&bufferp->mx);
297 code = cm_GetBuffer(scp, bufferp, NULL, userp,
299 lock_ReleaseWrite(&scp->rw);
300 lock_ObtainMutex(&bufferp->mx);
301 lock_ObtainWrite(&scp->rw);
306 lock_ReleaseMutex(&bufferp->mx);
307 buf_Release(bufferp);
311 } /* if (wrong buffer) ... */
313 /* now we have the right buffer loaded. Copy out the
314 * data from here to the user's buffer.
316 bufIndex = offset.LowPart & (buf_bufferSize - 1);
318 /* and figure out how many bytes we want from this buffer */
319 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
321 nbytes = count; /* don't go past end of request */
323 /* now copy the data */
324 memcpy(bufferp->datap + bufIndex, op, nbytes);
325 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
327 /* adjust counters, pointers, etc. */
331 thyper.LowPart = nbytes;
333 offset = LargeIntegerAdd(thyper, offset);
337 lock_ReleaseWrite(&scp->rw);
339 lock_ReleaseMutex(&bufferp->mx);
340 buf_Release(bufferp);
343 if (code == 0 && doWriteBack) {
344 lock_ObtainWrite(&scp->rw);
345 cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
346 lock_ReleaseWrite(&scp->rw);
347 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
348 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
351 /* cm_SyncOpDone is called when cm_BkgStore completes */