Unite CacheStoreProcs and add abstraction calls.
authorFelix Frank <ffrank@satyr4.ifh.de>
Thu, 2 Jul 2009 06:55:47 +0000 (08:55 +0200)
committerRuss Allbery <rra@stanford.edu>
Wed, 22 Jul 2009 18:01:35 +0000 (11:01 -0700)
The cache type specific differencies among afs_MemCacheStoreProc
and afs_UFSCacheStoreProc are divided into two sets of "storeOps".
Upon rxfs_storeInit, the appropriate set is chosen.

FIXME: Simon suggests that there should be a single set of storeOps,
as the main difference lies in what rx_ calls must be made.
This decision would then be made by calling a wrapper function from
each storeOp. These wrappers should be cachetype-specific and protocol-
independent. They would be associated to struct afs_cacheOps.
Reviewed-on: http://gerrit.openafs.org/http://gerrit.openafs.org/107
Tested-by: Russ Allbery <rra@stanford.edu>
Reviewed-by: Russ Allbery <rra@stanford.edu>

src/afs/afs.h
src/afs/afs_chunkops.h
src/afs/afs_dcache.c
src/afs/afs_fetchstore.c
src/afs/afs_prototypes.h

index e81d10e..6317dc0 100644 (file)
@@ -1348,6 +1348,15 @@ extern struct brequest afs_brs[NBRS];    /* request structures */
 struct buf;
 #endif
 
+struct storeOps {
+    int (*prepare)(void *rock, afs_uint32 size, afs_uint32 *bytestoxfer);
+    int (*read)(void *rock, struct osi_file *tfile, afs_uint32 offset,
+        afs_uint32 tlen, afs_uint32 *bytesread);
+    int (*write)(void *rock, afs_uint32 tlen, afs_uint32 *byteswritten);
+    int (*status)(void *rock);
+    int (*destroy)(void **rock, afs_int32 error);
+};
+
 /* fakestat support: opaque storage for afs_EvalFakeStat to remember
  * what vcache should be released.
  */
index 7804a58..283cb87 100644 (file)
@@ -91,8 +91,6 @@ struct afs_cacheOps {
 
 #define        afs_CacheFetchProc(call, file, base, adc, avc, toxfer, xfered, length) \
           (*(afs_cacheType->FetchProc))(call, file, (afs_size_t)base, adc, avc, (afs_size_t *)toxfer, (afs_size_t *)xfered, length)
-#define        afs_CacheStoreProc(call, file, bytes, avc, wake, toxfer, xfered) \
-          (*(afs_cacheType->StoreProc))(call, file, bytes, avc, wake, toxfer, xfered)
 
 /* These memcpys should get optimised to simple assignments when afs_dcache_id_t 
  * is simple */
index e36e9d9..626afeb 100644 (file)
@@ -108,7 +108,7 @@ struct afs_cacheOps afs_UfsCacheOps = {
     afs_UFSRead,
     afs_UFSWrite,
     afs_UFSCacheFetchProc,
-    afs_UFSCacheStoreProc,
+    afs_CacheStoreProc,
     afs_UFSGetDSlot,
     afs_UFSGetVolSlot,
     afs_UFSHandleLink,
@@ -123,7 +123,7 @@ struct afs_cacheOps afs_MemCacheOps = {
     afs_MemRead,
     afs_MemWrite,
     afs_MemCacheFetchProc,
-    afs_MemCacheStoreProc,
+    afs_CacheStoreProc,
     afs_MemGetDSlot,
     afs_MemGetVolSlot,
     afs_MemHandleLink,
index 50389f1..b8b7032 100644 (file)
 #include "afs/afs_stats.h"     /* statistics */
 #include "afs_prototypes.h"
 
-/*
- * afs_UFSCacheStoreProc
- *
- * Description:
- *     Called upon store.
- *
- * Parameters:
- *     acall : Ptr to the Rx call structure involved.
- *     afile : Ptr to the related file descriptor.
- *     alen  : Size of the file in bytes.
- *     avc   : Ptr to the vcache entry.
- *      shouldWake : is it "safe" to return early from close() ?
- *     abytesToXferP  : Set to the number of bytes to xfer.
- *                      NOTE: This parameter is only used if AFS_NOSTATS
- *                             is not defined.
- *     abytesXferredP : Set to the number of bytes actually xferred.
- *                      NOTE: This parameter is only used if AFS_NOSTATS
- *                             is not defined.
- *
- * Environment:
- *     Nothing interesting.
- */
-int
-afs_UFSCacheStoreProc(register struct rx_call *acall, struct osi_file *afile,
-                     register afs_int32 alen, struct vcache *avc,
-                     int *shouldWake, afs_size_t * abytesToXferP,
-                     afs_size_t * abytesXferredP)
+extern int cacheDiskType;
+
+/* rock and operations for RX_FILESERVER */
+
+struct rxfs_storeVariables {
+    struct rx_call *call;
+    char *tbuffer;
+    struct iovec *tiov;
+    afs_uint32 tnio;
+    afs_int32 hasNo64bit;
+    struct AFSStoreStatus InStatus;
+};
+
+afs_int32
+rxfs_storeUfsPrepare(void *r, afs_uint32 size, afs_uint32 *tlen)
 {
-    afs_int32 code, got;
-    register char *tbuffer;
-    register int tlen;
+    *tlen = (size > AFS_LRALLOCSIZ ?  AFS_LRALLOCSIZ : size);
+    return 0;
+}
 
-    AFS_STATCNT(UFS_CacheStoreProc);
+afs_int32
+rxfs_storeMemPrepare(void *r, afs_uint32 size, afs_uint32 *tlen)
+{
+    afs_int32 code;
+    struct rxfs_storeVariables *v = (struct rxfs_storeVariables *) r;
 
-#ifndef AFS_NOSTATS
-    /*
-     * In this case, alen is *always* the amount of data we'll be trying
-     * to ship here.
-     */
-    (*abytesToXferP) = alen;
-    (*abytesXferredP) = 0;
-#endif /* AFS_NOSTATS */
+    *tlen = (size > AFS_LRALLOCSIZ ?  AFS_LRALLOCSIZ : size);
+    RX_AFS_GUNLOCK();
+    code = rx_WritevAlloc(v->call, v->tiov, &v->tnio, RX_MAXIOVECS, *tlen);
+    RX_AFS_GLOCK();
+    if (code <= 0) {
+       code = rx_Error(v->call);
+       if ( !code )
+           code = -33;
+    }
+    else {
+       *tlen = code;
+       code = 0;
+    }
+    return code;
+}
 
-    afs_Trace4(afs_iclSetp, CM_TRACE_STOREPROC, ICL_TYPE_POINTER, avc,
-              ICL_TYPE_FID, &(avc->f.fid), ICL_TYPE_OFFSET,
-              ICL_HANDLE_OFFSET(avc->f.m.Length), ICL_TYPE_INT32, alen);
-    tbuffer = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
-    while (alen > 0) {
-       tlen = (alen > AFS_LRALLOCSIZ ? AFS_LRALLOCSIZ : alen);
-       got = afs_osi_Read(afile, -1, tbuffer, tlen);
-       if ((got < 0)
+afs_int32
+rxfs_storeUfsRead(void *r, struct osi_file *tfile, afs_uint32 offset,
+                 afs_uint32 tlen, afs_uint32 *got)
+{
+    afs_int32 code;
+    struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
+
+    *got = afs_osi_Read(tfile, -1, v->tbuffer, tlen);
+    if ((*got < 0)
 #if defined(KERNEL_HAVE_UERROR)
-           || (got != tlen && getuerror())
+               || (*got != tlen && getuerror())
 #endif
-           ) {
-           osi_FreeLargeSpace(tbuffer);
-           return EIO;
-       }
-       afs_Trace2(afs_iclSetp, CM_TRACE_STOREPROC2, ICL_TYPE_OFFSET,
-                  ICL_HANDLE_OFFSET(*tbuffer), ICL_TYPE_INT32, got);
-       RX_AFS_GUNLOCK();
-       code = rx_Write(acall, tbuffer, got);   /* writing 0 bytes will
-                                                * push a short packet.  Is that really what we want, just because the
-                                                * data didn't come back from the disk yet?  Let's try it and see. */
-       RX_AFS_GLOCK();
-#ifndef AFS_NOSTATS
-       (*abytesXferredP) += code;
-#endif /* AFS_NOSTATS */
-       if (code != got) {
-           code = rx_Error(acall);
-           osi_FreeLargeSpace(tbuffer);
-           return code ? code : -33;
-       }
-       alen -= got;
-       /*
-        * If file has been locked on server, we can allow the store
-        * to continue.
-        */
-       if (shouldWake && *shouldWake && (rx_GetRemoteStatus(acall) & 1)) {
-           *shouldWake = 0;    /* only do this once */
-           afs_wakeup(avc);
-       }
+               )
+       return EIO;
+    return 0;
+}
+
+afs_int32
+rxfs_storeMemRead(void *r, struct osi_file *tfile, afs_uint32 offset,
+                 afs_uint32 tlen, afs_uint32 *bytesread)
+{
+    afs_int32 code;
+    struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
+    struct memCacheEntry *mceP = (struct memCacheEntry *)tfile;
+
+    *bytesread = 0;
+    code = afs_MemReadvBlk(mceP, offset, v->tiov, v->tnio, tlen);
+    if (code != tlen)
+       return -33;
+    *bytesread = code;
+    return 0;
+}
+
+afs_int32
+rxfs_storeMemWrite(void *r, afs_uint32 l, afs_uint32 *byteswritten)
+{
+    afs_int32 code;
+    struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
+
+    RX_AFS_GUNLOCK();
+    code = rx_Writev(v->call, v->tiov, v->tnio, l);
+    RX_AFS_GLOCK();
+    if (code != l) {
+       code = rx_Error(v->call);
+        return (code ? code : -33);
     }
-    afs_Trace4(afs_iclSetp, CM_TRACE_STOREPROC, ICL_TYPE_POINTER, avc,
-              ICL_TYPE_FID, &(avc->f.fid), ICL_TYPE_OFFSET,
-              ICL_HANDLE_OFFSET(avc->f.m.Length), ICL_TYPE_INT32, alen);
-    osi_FreeLargeSpace(tbuffer);
+    *byteswritten = code;
     return 0;
+}
 
-}                              /* afs_UFSCacheStoreProc */
+afs_int32
+rxfs_storeUfsWrite(void *r, afs_uint32 l, afs_uint32 *byteswritten)
+{
+    afs_int32 code;
+    struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
 
+    RX_AFS_GUNLOCK();
+    code = rx_Write(v->call, v->tbuffer, l);
+       /* writing 0 bytes will
+        * push a short packet.  Is that really what we want, just because the
+        * data didn't come back from the disk yet?  Let's try it and see. */
+    RX_AFS_GLOCK();
+    if (code != l) {
+       code = rx_Error(v->call);
+        return (code ? code : -33);
+    }
+    *byteswritten = code;
+    return 0;
+}
+
+afs_int32
+rxfs_storeStatus(void *rock)
+{
+    struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)rock;
+
+    if (rx_GetRemoteStatus(v->call) & 1)
+       return 0;
+    return 1;
+}
+
+afs_int32
+rxfs_storeDestroy(void **r, afs_int32 error)
+{
+    afs_int32 code = error;
+    struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)*r;
+
+    *r = NULL;
+    if (v->tbuffer)
+       osi_FreeLargeSpace(v->tbuffer);
+    if (v->tiov)
+       osi_FreeSmallSpace(v->tiov);
+    osi_FreeSmallSpace(v);
+    return code;
+}
+
+static
+struct storeOps rxfs_storeUfsOps = {
+    rxfs_storeUfsPrepare,
+    rxfs_storeUfsRead,
+    rxfs_storeUfsWrite,
+    rxfs_storeStatus,
+    rxfs_storeDestroy
+};
+
+static
+struct storeOps rxfs_storeMemOps = {
+    rxfs_storeMemPrepare,
+    rxfs_storeMemRead,
+    rxfs_storeMemWrite,
+    rxfs_storeStatus,
+    rxfs_storeDestroy
+};
+
+afs_int32
+rxfs_storeInit(struct vcache *avc, struct storeOps **ops, void **rock)
+{
+    struct rxfs_storeVariables *v;
+
+    v = (struct rxfs_storeVariables *) osi_AllocSmallSpace(sizeof(struct rxfs_storeVariables));
+    if (!v)
+        osi_Panic("rxfs_storeInit: osi_AllocSmallSpace returned NULL\n");
+    memset(v, 0, sizeof(struct rxfs_storeVariables));
+
+    v->InStatus.ClientModTime = avc->f.m.Date;
+    v->InStatus.Mask = AFS_SETMODTIME;
+
+    if (cacheDiskType == AFS_FCACHE_TYPE_UFS) {
+       v->tbuffer = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+       if (!v->tbuffer)
+           osi_Panic
+              ("rxfs_storeInit: osi_AllocLargeSpace for iovecs returned NULL\n");
+       *ops = (struct storeOps *) &rxfs_storeUfsOps;
+    } else {
+       v->tiov = osi_AllocSmallSpace(sizeof(struct iovec) * RX_MAXIOVECS);
+       if (!v->tiov)
+           osi_Panic
+              ("rxfs_storeInit: osi_AllocSmallSpace for iovecs returned NULL\n");
+       *ops = (struct storeOps *) &rxfs_storeMemOps;
+#ifdef notdef
+       /* do this at a higher level now -- it's a parameter */
+       /* for now, only do 'continue from close' code if file fits in one
+        * chunk.  Could clearly do better: if only one modified chunk
+        * then can still do this.  can do this on *last* modified chunk */
+       tlen = avc->f.m.Length - 1;     /* byte position of last byte we'll store */
+       if (shouldWake) {
+           if (AFS_CHUNK(tlen) != 0)
+               *shouldWake = 0;
+           else
+               *shouldWake = 1;
+       }
+#endif /* notdef */
+    }
+    *rock = (void *)v;
+    return 0;
+}
 
 /*
  * afs_UFSCacheFetchProc
@@ -236,22 +342,44 @@ afs_UFSCacheFetchProc(register struct rx_call *acall, struct osi_file *afile,
 
 }                              /* afs_UFSCacheFetchProc */
 
+/*!
+ *     Called upon store.
+ *
+ * \param acall Ptr to the Rx call structure involved.
+ * \param fP Ptr to the related file descriptor.
+ * \param alen Size of the file in bytes.
+ * \param avc Ptr to the vcache entry.
+ * \param shouldWake is it "safe" to return early from close() ?
+ * \param abytesToXferP Set to the number of bytes to xfer.
+ *     NOTE: This parameter is only used if AFS_NOSTATS is not defined.
+ * \param abytesXferredP Set to the number of bytes actually xferred.
+ *     NOTE: This parameter is only used if AFS_NOSTATS is not defined.
+ *
+ * \note Environment: Nothing interesting.
+ */
 int
-afs_MemCacheStoreProc(register struct rx_call *acall,
+afs_CacheStoreProc(register struct rx_call *acall,
                      register struct osi_file *fP,
                      register afs_int32 alen, struct vcache *avc,
                      int *shouldWake, afs_size_t * abytesToXferP,
                      afs_size_t * abytesXferredP)
 {
-    register struct memCacheEntry *mceP = (struct memCacheEntry *)fP;
-
-    register afs_int32 code;
-    register int tlen;
+    afs_int32 code;
+    afs_uint32 tlen;
     int offset = 0;
-    struct iovec *tiov;                /* no data copying with iovec */
-    int tnio;                  /* temp for iovec size */
+    struct storeOps *ops;
+    void * rock = NULL;
 
-    AFS_STATCNT(afs_MemCacheStoreProc);
+    afs_Trace4(afs_iclSetp, CM_TRACE_STOREPROC, ICL_TYPE_POINTER, avc,
+              ICL_TYPE_FID, &(avc->f.fid), ICL_TYPE_OFFSET,
+              ICL_HANDLE_OFFSET(avc->f.m.Length), ICL_TYPE_INT32, alen);
+    code =  rxfs_storeInit(avc, &ops, &rock);
+    if ( code ) {
+       osi_Panic("afs_CacheStoreProc: rxfs_storeInit failed");
+    }
+    ((struct rxfs_storeVariables *)rock)->call = acall;
+
+    AFS_STATCNT(CacheStoreProc);
 #ifndef AFS_NOSTATS
     /*
      * In this case, alen is *always* the amount of data we'll be trying
@@ -261,68 +389,40 @@ afs_MemCacheStoreProc(register struct rx_call *acall,
     *(abytesXferredP) = 0;
 #endif /* AFS_NOSTATS */
 
-    /*
-     * We need to alloc the iovecs on the heap so that they are "pinned" rather than
-     * declare them on the stack - defect 11272
-     */
-    tiov =
-       (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec) *
-                                           RX_MAXIOVECS);
-    if (!tiov) {
-       osi_Panic
-           ("afs_MemCacheStoreProc: osi_AllocSmallSpace for iovecs returned NULL\n");
-    }
-#ifdef notdef
-    /* do this at a higher level now -- it's a parameter */
-    /* for now, only do 'continue from close' code if file fits in one
-     * chunk.  Could clearly do better: if only one modified chunk
-     * then can still do this.  can do this on *last* modified chunk */
-    tlen = avc->f.m.Length - 1;        /* byte position of last byte we'll store */
-    if (shouldWake) {
-       if (AFS_CHUNK(tlen) != 0)
-           *shouldWake = 0;
-       else
-           *shouldWake = 1;
-    }
-#endif /* notdef */
+    while ( alen > 0 ) {
+       afs_int32 bytesread, byteswritten;
+       code = (*ops->prepare)(rock, alen, &tlen);
+       if ( code )
+           break;
 
-    while (alen > 0) {
-       tlen = (alen > AFS_LRALLOCSIZ ? AFS_LRALLOCSIZ : alen);
-       RX_AFS_GUNLOCK();
-       code = rx_WritevAlloc(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
-       RX_AFS_GLOCK();
-       if (code <= 0) {
-           code = rx_Error(acall);
-           osi_FreeSmallSpace(tiov);
-           return code ? code : -33;
-       }
-       tlen = code;
-       code = afs_MemReadvBlk(mceP, offset, tiov, tnio, tlen);
-       if (code != tlen) {
-           osi_FreeSmallSpace(tiov);
-           return -33;
-       }
-       RX_AFS_GUNLOCK();
-       code = rx_Writev(acall, tiov, tnio, tlen);
-       RX_AFS_GLOCK();
+       code = (*ops->read)(rock, fP, offset, tlen, &bytesread);
+       if (code)
+           break;
+
+       tlen = bytesread;
+       code = (*ops->write)(rock, tlen, &byteswritten);
+       if (code)
+           break;
 #ifndef AFS_NOSTATS
-       (*abytesXferredP) += code;
+       (*abytesXferredP) += byteswritten;
 #endif /* AFS_NOSTATS */
-       if (code != tlen) {
-           code = rx_Error(acall);
-           osi_FreeSmallSpace(tiov);
-           return code ? code : -33;
-       }
+
        offset += tlen;
        alen -= tlen;
-       /* if file has been locked on server, can allow store to continue */
-       if (shouldWake && *shouldWake && (rx_GetRemoteStatus(acall) & 1)) {
+       /*
+        * if file has been locked on server, can allow
+        * store to continue
+        */
+       if (shouldWake && *shouldWake && ((*ops->status)(rock) == 0)) {
            *shouldWake = 0;    /* only do this once */
            afs_wakeup(avc);
        }
     }
-    osi_FreeSmallSpace(tiov);
-    return 0;
+    afs_Trace4(afs_iclSetp, CM_TRACE_STOREPROC, ICL_TYPE_POINTER, avc,
+              ICL_TYPE_FID, &(avc->f.fid), ICL_TYPE_OFFSET,
+              ICL_HANDLE_OFFSET(avc->f.m.Length), ICL_TYPE_INT32, alen);
+    code = (*ops->destroy)(&rock, code);
+    return code;
 }
 
 int
index 2d29703..ec5b233 100644 (file)
@@ -491,7 +491,7 @@ extern int afs_MemWritevBlk(register struct memCacheEntry *mceP, int offset,
 extern int afs_MemWriteUIO(afs_dcache_id_t *ainode, struct uio *uioP);
 extern int afs_MemCacheTruncate(register struct osi_file *fP,
                                int size);
-extern int afs_MemCacheStoreProc(register struct rx_call *acall,
+extern int afs_CacheStoreProc(register struct rx_call *acall,
                                 register struct osi_file *fP,
                                 register afs_int32 alen, struct vcache *avc,
                                 int *shouldWake, afs_size_t * abytesToXferP,