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
15 #define CM_BUF_SIZE 4096
16 long buf_bufferSize = CM_BUF_SIZE;
18 long ReadData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
19 cm_user_t *userp, long *readp)
24 osi_hyper_t fileLength;
27 osi_hyper_t bufferOffset;
28 long bufIndex, nbytes;
36 lock_ObtainMutex(&scp->mx);
38 /* start by looking up the file's end */
39 code = cm_SyncOp(scp, NULL, userp, &req, 0,
40 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
43 /* now we have the entry locked, look up the length */
44 fileLength = scp->length;
46 /* adjust count down so that it won't go past EOF */
47 thyper.LowPart = count;
49 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
51 if (LargeIntegerGreaterThan(thyper, fileLength)) {
52 /* we'd read past EOF, so just stop at fileLength bytes.
53 * Start by computing how many bytes remain in the file.
55 thyper = LargeIntegerSubtract(fileLength, offset);
57 /* if we are past EOF, read 0 bytes */
58 if (LargeIntegerLessThanZero(thyper))
61 count = thyper.LowPart;
66 /* now, copy the data one buffer at a time,
67 * until we've filled the request packet
70 /* if we've copied all the data requested, we're done */
71 if (count <= 0) break;
73 /* otherwise, load up a buffer of data */
74 thyper.HighPart = offset.HighPart;
75 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
76 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
82 lock_ReleaseMutex(&scp->mx);
84 lock_ObtainRead(&scp->bufCreateLock);
85 code = buf_Get(scp, &thyper, &bufferp);
86 lock_ReleaseRead(&scp->bufCreateLock);
88 lock_ObtainMutex(&scp->mx);
90 bufferOffset = thyper;
92 /* now get the data in the cache */
94 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
95 CM_SCACHESYNC_NEEDCALLBACK
96 | CM_SCACHESYNC_READ);
99 if (cm_HaveBuffer(scp, bufferp, 0)) break;
101 /* otherwise, load the buffer and try again */
102 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
106 buf_Release(bufferp);
110 } /* if (wrong buffer) ... */
112 /* now we have the right buffer loaded. Copy out the
113 * data from here to the user's buffer.
115 bufIndex = offset.LowPart & (buf_bufferSize - 1);
117 /* and figure out how many bytes we want from this buffer */
118 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
119 if (nbytes > count) nbytes = count; /* don't go past EOF */
121 /* now copy the data */
122 memcpy(op, bufferp->datap + bufIndex, nbytes);
124 /* adjust counters, pointers, etc. */
127 thyper.LowPart = nbytes;
129 offset = LargeIntegerAdd(thyper, offset);
133 lock_ReleaseMutex(&scp->mx);
134 //lock_ReleaseMutex(&fidp->mx);
135 if (bufferp) buf_Release(bufferp);
137 if (code == 0 && sequential)
138 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
144 long WriteData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
145 cm_user_t *userp, long *writtenp)
150 osi_hyper_t fileLength; /* file's length at start of write */
151 osi_hyper_t minLength; /* don't read past this */
152 long nbytes; /* # of bytes to transfer this iteration */
154 osi_hyper_t thyper; /* hyper tmp variable */
155 osi_hyper_t bufferOffset;
156 long bufIndex; /* index in buffer where our data is */
158 osi_hyper_t writeBackOffset; /* offset of region to write back when
169 lock_ObtainMutex(&scp->mx);
171 /* start by looking up the file's end */
172 code = cm_SyncOp(scp, NULL, userp, &req, 0,
173 CM_SCACHESYNC_NEEDCALLBACK
174 | CM_SCACHESYNC_SETSTATUS
175 | CM_SCACHESYNC_GETSTATUS);
179 /* make sure we have a writable FD */
180 /*if (!(fidp->flags & SMB_FID_OPENWRITE)) {
181 code = CM_ERROR_BADFDOP;
185 /* now we have the entry locked, look up the length */
186 fileLength = scp->length;
187 minLength = fileLength;
188 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
189 minLength = scp->serverLength;
191 /* adjust file length if we extend past EOF */
192 thyper.LowPart = count;
194 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
195 if (LargeIntegerGreaterThan(thyper, fileLength)) {
196 /* we'd write past EOF, so extend the file */
197 scp->mask |= CM_SCACHEMASK_LENGTH;
198 scp->length = thyper;
199 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
201 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
203 /* now, if the new position (thyper) and the old (offset) are in
204 * different storeback windows, remember to store back the previous
205 * storeback window when we're done with the write.
207 if ((thyper.LowPart & (-cm_chunkSize)) !=
208 (offset.LowPart & (-cm_chunkSize))) {
209 /* they're different */
211 writeBackOffset.HighPart = offset.HighPart;
212 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
217 /* now, copy the data one buffer at a time, until we've filled the
220 /* if we've copied all the data requested, we're done */
221 if (count <= 0) break;
223 /* handle over quota or out of space */
224 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
229 /* otherwise, load up a buffer of data */
230 thyper.HighPart = offset.HighPart;
231 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
232 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
235 lock_ReleaseMutex(&bufferp->mx);
236 buf_Release(bufferp);
239 lock_ReleaseMutex(&scp->mx);
241 lock_ObtainRead(&scp->bufCreateLock);
242 code = buf_Get(scp, &thyper, &bufferp);
243 lock_ReleaseRead(&scp->bufCreateLock);
245 lock_ObtainMutex(&bufferp->mx);
246 lock_ObtainMutex(&scp->mx);
249 bufferOffset = thyper;
251 /* now get the data in the cache */
253 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
254 CM_SCACHESYNC_NEEDCALLBACK
255 | CM_SCACHESYNC_WRITE
256 | CM_SCACHESYNC_BUFLOCKED);
260 /* If we're overwriting the entire buffer, or
261 * if we're writing at or past EOF, mark the
262 * buffer as current so we don't call
263 * cm_GetBuffer. This skips the fetch from the
264 * server in those cases where we're going to
265 * obliterate all the data in the buffer anyway,
266 * or in those cases where there is no useful
267 * data at the server to start with.
269 * Use minLength instead of scp->length, since
270 * the latter has already been updated by this
273 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength) ||
274 LargeIntegerEqualTo(offset, bufferp->offset) &&
275 (count >= buf_bufferSize ||
276 LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset, ConvertLongToLargeInteger(count)), minLength))) {
277 if (count < buf_bufferSize
278 && bufferp->dataVersion == -1)
279 memset(bufferp->datap, 0,
281 bufferp->dataVersion = scp->dataVersion;
284 if (cm_HaveBuffer(scp, bufferp, 1)) break;
286 /* otherwise, load the buffer and try again */
287 lock_ReleaseMutex(&bufferp->mx);
288 code = cm_GetBuffer(scp, bufferp, NULL, userp,
290 lock_ReleaseMutex(&scp->mx);
291 lock_ObtainMutex(&bufferp->mx);
292 lock_ObtainMutex(&scp->mx);
296 lock_ReleaseMutex(&bufferp->mx);
297 buf_Release(bufferp);
301 } /* if (wrong buffer) ... */
303 /* now we have the right buffer loaded. Copy out the
304 * data from here to the user's buffer.
306 bufIndex = offset.LowPart & (buf_bufferSize - 1);
308 /* and figure out how many bytes we want from this buffer */
309 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
311 nbytes = count; /* don't go past end of request */
313 /* now copy the data */
316 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
319 memcpy(bufferp->datap + bufIndex, op, nbytes);
320 buf_SetDirty(bufferp);
322 /* and record the last writer */
323 if (bufferp->userp != userp) {
326 cm_ReleaseUser(bufferp->userp);
327 bufferp->userp = userp;
330 /* adjust counters, pointers, etc. */
334 thyper.LowPart = nbytes;
336 offset = LargeIntegerAdd(thyper, offset);
340 lock_ReleaseMutex(&scp->mx);
342 lock_ReleaseMutex(&bufferp->mx);
343 buf_Release(bufferp);
346 if (code == 0 /* && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
347 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)*/) {
348 /*smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
349 fidp->NTopen_dscp, fidp->NTopen_pathp,
353 if (code == 0 && doWriteBack) {
354 lock_ObtainMutex(&scp->mx);
355 cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
356 lock_ReleaseMutex(&scp->mx);
357 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
358 writeBackOffset.HighPart, cm_chunkSize, 0, userp);