vol-osi-assert-20080401
[openafs.git] / src / vol / fssync-server.c
index 44494ca..1d72556 100644 (file)
@@ -6,7 +6,7 @@
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
  *
- * Portions Copyright (c) 2006 Sine Nomine Associates
+ * Portions Copyright (c) 2006-2008 Sine Nomine Associates
  */
 
 /*
@@ -74,15 +74,7 @@ RCSID
 #include <afs/assert.h>
 #endif /* AFS_PTHREAD_ENV */
 #include <signal.h>
-
-#ifdef HAVE_STRING_H
 #include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#endif
-
 
 #include <rx/xdr.h>
 #include <afs/afsint.h>
@@ -96,18 +88,22 @@ RCSID
 #include "ihandle.h"
 #include "vnode.h"
 #include "volume.h"
+#include "volume_inline.h"
 #include "partition.h"
 
+#ifdef HAVE_POLL
+#include <sys/poll.h>
+#endif /* HAVE_POLL */
+
+#ifdef USE_UNIX_SOCKETS
+#include <sys/un.h>
+#include <afs/afsutil.h>
+#endif /* USE_UNIX_SOCKETS */
 
 #ifdef FSSYNC_BUILD_SERVER
 
 /*@printflike@*/ extern void Log(const char *format, ...);
 
-#ifdef osi_Assert
-#undef osi_Assert
-#endif
-#define osi_Assert(e) (void)(e)
-
 int (*V_BreakVolumeCallbacks) ();
 
 #define MAXHANDLERS    4       /* Up to 4 clients; must be at least 2, so that
@@ -118,35 +114,47 @@ int (*V_BreakVolumeCallbacks) ();
                                 * cloned read-only copies offline when salvaging
                                 * a single read-write volume */
 
-#define MAX_BIND_TRIES 5       /* Number of times to retry socket bind */
-
 
 
 static struct offlineInfo OfflineVolumes[MAXHANDLERS][MAXOFFLINEVOLUMES];
 
-static int AcceptSd = -1;      /* Socket used by server for accepting connections */
+/**
+ * fssync server socket handle.
+ */
+static SYNC_server_state_t fssync_server_state = 
+    { -1,                       /* file descriptor */
+      FSSYNC_ENDPOINT_DECL,     /* server endpoint */
+      FSYNC_PROTO_VERSION,      /* protocol version */
+      5,                        /* bind() retry limit */
+      100,                      /* listen() queue depth */
+      "FSSYNC",                 /* protocol name string */
+    };
 
-static int getport();
 
 /* Forward declarations */
-static void FSYNC_sync();
+static void * FSYNC_sync(void *);
 static void FSYNC_newconnection();
 static void FSYNC_com();
 static void FSYNC_Drop();
 static void AcceptOn();
 static void AcceptOff();
 static void InitHandler();
-static void CallHandler(fd_set * fdsetp);
 static int AddHandler();
 static int FindHandler();
 static int FindHandler_r();
 static int RemoveHandler();
+#if defined(HAVE_POLL) && defined (AFS_PTHREAD_ENV)
+static void CallHandler(struct pollfd *fds, int nfds, int mask);
+static void GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds);
+#else
+static void CallHandler(fd_set * fdsetp);
 static void GetHandler(fd_set * fdsetp, int *maxfdp);
-
+#endif
 extern int LogLevel;
 
 static afs_int32 FSYNC_com_VolOp(int fd, SYNC_command * com, SYNC_response * res);
 
+static afs_int32 FSYNC_com_VolError(FSSYNC_VolOp_command * com, SYNC_response * res);
 static afs_int32 FSYNC_com_VolOn(FSSYNC_VolOp_command * com, SYNC_response * res);
 static afs_int32 FSYNC_com_VolOff(FSSYNC_VolOp_command * com, SYNC_response * res);
 static afs_int32 FSYNC_com_VolMove(FSSYNC_VolOp_command * com, SYNC_response * res);
@@ -158,6 +166,8 @@ static afs_int32 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * com, SYNC_response
 static afs_int32 FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
 #endif /* AFS_DEMAND_ATTACH_FS */
 
+static afs_int32 FSYNC_com_VnQry(int fd, SYNC_command * com, SYNC_response * res);
+
 static afs_int32 FSYNC_com_StatsOp(int fd, SYNC_command * com, SYNC_response * res);
 
 static afs_int32 FSYNC_com_StatsOpGeneral(FSSYNC_StatsOp_command * scom, SYNC_response * res);
@@ -199,30 +209,19 @@ FSYNC_fsInit(void)
 #endif /* AFS_PTHREAD_ENV */
 }
 
+#if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
+static struct pollfd FSYNC_readfds[MAXHANDLERS];
+#else
 static fd_set FSYNC_readfds;
-
-static int
-getport(struct sockaddr_in *addr)
-{
-    int sd;
-
-    memset(addr, 0, sizeof(*addr));
-    assert((sd = socket(AF_INET, SOCK_STREAM, 0)) >= 0);
-#ifdef STRUCT_SOCKADDR_HAS_SA_LEN
-    addr->sin_len = sizeof(struct sockaddr_in);
 #endif
-    addr->sin_addr.s_addr = htonl(0x7f000001);
-    addr->sin_family = AF_INET;        /* was localhost->h_addrtype */
-    addr->sin_port = htons(2040);      /* XXXX htons not _really_ neccessary */
 
-    return sd;
-}
 
-
-static void
-FSYNC_sync()
+static void *
+FSYNC_sync(void * args)
 {
-    struct sockaddr_in addr;
+#ifdef USE_UNIX_SOCKETS
+    char tbuffer[AFSDIR_PATH_MAX];
+#endif /* USE_UNIX_SOCKETS */
     int on = 1;
     extern int VInit;
     int code;
@@ -230,6 +229,10 @@ FSYNC_sync()
 #ifdef AFS_PTHREAD_ENV
     int tid;
 #endif
+    SYNC_server_state_t * state = &fssync_server_state;
+
+    SYNC_getAddr(&state->endpoint, &state->addr);
+    SYNC_cleanupSock(state);
 
 #ifndef AFS_NT40_ENV
     (void)signal(SIGPIPE, SIG_IGN);
@@ -253,27 +256,21 @@ FSYNC_sync()
        LWP_DispatchProcess();
 #endif /* AFS_PTHREAD_ENV */
     }
-    AcceptSd = getport(&addr);
-    /* Reuseaddr needed because system inexplicably leaves crud lying around */
-    code =
-       setsockopt(AcceptSd, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
-                  sizeof(on));
-    if (code)
-       Log("FSYNC_sync: setsockopt failed with (%d)\n", errno);
-
-    for (numTries = 0; numTries < MAX_BIND_TRIES; numTries++) {
-       if ((code =
-            bind(AcceptSd, (struct sockaddr *)&addr, sizeof(addr))) == 0)
-           break;
-       Log("FSYNC_sync: bind failed with (%d), will sleep and retry\n",
-           errno);
-       sleep(5);
-    }
+
+    state->fd = SYNC_getSock(&state->endpoint);
+    code = SYNC_bindSock(state);
     assert(!code);
-    listen(AcceptSd, 100);
+
     InitHandler();
     AcceptOn();
+
     for (;;) {
+#if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
+        int nfds;
+        GetHandler(FSYNC_readfds, MAXHANDLERS, POLLIN|POLLPRI, &nfds);
+        if (poll(FSYNC_readfds, nfds, -1) >=1)
+           CallHandler(FSYNC_readfds, nfds, POLLIN|POLLPRI);
+#else
        int maxfd;
        GetHandler(&FSYNC_readfds, &maxfd);
        /* Note: check for >= 1 below is essential since IOMGR_select
@@ -285,13 +282,18 @@ FSYNC_sync()
        if (IOMGR_Select(maxfd + 1, &FSYNC_readfds, NULL, NULL, NULL) >= 1)
 #endif /* AFS_PTHREAD_ENV */
            CallHandler(&FSYNC_readfds);
+#endif
     }
 }
 
 static void
 FSYNC_newconnection(int afd)
 {
+#ifdef USE_UNIX_SOCKETS
+    struct sockaddr_un other;
+#else  /* USE_UNIX_SOCKETS */
     struct sockaddr_in other;
+#endif
     int junk, fd;
     junk = sizeof(other);
     fd = accept(afd, (struct sockaddr *)&other, &junk);
@@ -330,6 +332,14 @@ FSYNC_com(int fd)
        return;
     }
 
+    if (com.recv_len < sizeof(com.hdr)) {
+       Log("FSSYNC_com:  invalid protocol message length (%u)\n", com.recv_len);
+       res.hdr.response = SYNC_COM_ERROR;
+       res.hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+       res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
+       goto respond;
+    }
+
     if (com.hdr.proto_version != FSYNC_PROTO_VERSION) {
        Log("FSYNC_com:  invalid protocol version (%u)\n", com.hdr.proto_version);
        res.hdr.response = SYNC_COM_ERROR;
@@ -337,10 +347,20 @@ FSYNC_com(int fd)
        goto respond;
     }
 
+    if (com.hdr.command == SYNC_COM_CHANNEL_CLOSE) {
+       res.hdr.response = SYNC_OK;
+       res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
+       goto respond;
+    }
+
+
     VOL_LOCK;
     switch (com.hdr.command) {
     case FSYNC_VOL_ON:
+    case FSYNC_VOL_ATTACH:
+    case FSYNC_VOL_LEAVE_OFF:
     case FSYNC_VOL_OFF:
+    case FSYNC_VOL_FORCE_ERROR:
     case FSYNC_VOL_LISTVOLUMES:
     case FSYNC_VOL_NEEDVOLUME:
     case FSYNC_VOL_MOVE:
@@ -358,9 +378,8 @@ FSYNC_com(int fd)
     case FSYNC_VOL_STATS_VLRU:
        res.hdr.response = FSYNC_com_StatsOp(fd, &com, &res);
        break;
-    case SYNC_COM_CHANNEL_CLOSE:
-       res.hdr.response = SYNC_OK;
-       res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
+    case FSYNC_VOL_QUERY_VNODE:
+       res.hdr.response = FSYNC_com_VnQry(fd, &com, &res);
        break;
     default:
        res.hdr.response = SYNC_BAD_COMMAND;
@@ -404,6 +423,8 @@ FSYNC_com_VolOp(int fd, SYNC_command * com, SYNC_response * res)
 
     switch (com->hdr.command) {
     case FSYNC_VOL_ON:
+    case FSYNC_VOL_ATTACH:
+    case FSYNC_VOL_LEAVE_OFF:
        code = FSYNC_com_VolOn(&vcom, res);
        break;
     case FSYNC_VOL_OFF:
@@ -429,6 +450,9 @@ FSYNC_com_VolOp(int fd, SYNC_command * com, SYNC_response * res)
        code = FSYNC_com_VolHdrQuery(&vcom, res);
        break;
 #ifdef AFS_DEMAND_ATTACH_FS
+    case FSYNC_VOL_FORCE_ERROR:
+       code = FSYNC_com_VolError(&vcom, res);
+       break;
     case FSYNC_VOL_QUERY_VOP:
        code = FSYNC_com_VolOpQuery(&vcom, res);
        break;
@@ -493,29 +517,65 @@ FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 
     /* so, we need to attach the volume */
 
+#ifdef AFS_DEMAND_ATTACH_FS
+    /* check DAFS permissions */
+    vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
+    if (vp && !strcmp(VPartitionPath(V_partition(vp)), vcom->vop->partName) &&
+       vp->pending_vol_op && 
+       (vcom->hdr->programType != vp->pending_vol_op->com.programType)) {
+       /* a different program has this volume checked out. deny. */
+       Log("FSYNC_VolOn: WARNING: program type %u has attempted to manipulate "
+           "state for volume %u using command code %u while the volume is " 
+           "checked out by program type %u for command code %u.\n",
+           vcom->hdr->programType,
+           vcom->vop->volume,
+           vcom->hdr->command,
+           vp->pending_vol_op->com.programType,
+           vp->pending_vol_op->com.command);
+       code = SYNC_DENIED;
+       res->hdr.reason = FSYNC_EXCLUSIVE;
+       goto done;
+    }
+#endif
+
     if (vcom->v)
        vcom->v->volumeID = 0;
+
+
+    if (vcom->hdr->command == FSYNC_VOL_LEAVE_OFF) {
+       /* nothing much to do if we're leaving the volume offline */
+#ifdef AFS_DEMAND_ATTACH_FS
+       if (vp &&
+           !strcmp(VPartitionPath(V_partition(vp)), vcom->vop->partName)) {
+           VDeregisterVolOp_r(vp);
+           VChangeState_r(vp, VOL_STATE_UNATTACHED);
+       }
+#endif
+       goto done;
+    }
+
+#ifdef AFS_DEMAND_ATTACH_FS
+    /* first, check to see whether we have such a volume defined */
+    vp = VPreAttachVolumeById_r(&error,
+                               vcom->vop->partName,
+                               vcom->vop->volume);
+    if (vp) {
+       VDeregisterVolOp_r(vp);
+    }
+#else /* !AFS_DEMAND_ATTACH_FS */
     tvolName[0] = '/';
     snprintf(&tvolName[1], sizeof(tvolName)-1, VFORMAT, vcom->vop->volume);
     tvolName[sizeof(tvolName)-1] = '\0';
 
-#ifdef AFS_DEMAND_ATTACH_FS
-    vp = VPreAttachVolumeByName_r(&error, vcom->vop->partName, tvolName,
-                                 V_VOLUPD);
-    if (vp && vp->pending_vol_op) {
-       VDeregisterVolOp_r(vp, vp->pending_vol_op);
-    }
-#else /* AFS_DEMAND_ATTACH_FS */
     vp = VAttachVolumeByName_r(&error, vcom->vop->partName, tvolName,
                               V_VOLUPD);
     if (vp)
        VPutVolume_r(vp);
-#endif /* AFS_DEMAND_ATTACH_FS */
-
     if (error) {
        code = SYNC_DENIED;
        res->hdr.reason = error;
     }
+#endif /* !AFS_DEMAND_ATTACH_FS */
 
  done:
     return code;
@@ -760,14 +820,39 @@ FSYNC_com_VolDone(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 
 #ifdef AFS_DEMAND_ATTACH_FS
     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
-    if (vp && vp->pending_vol_op) {
-       VDeregisterVolOp_r(vp, vp->pending_vol_op);
+    if (vp) {
+       VChangeState_r(vp, VOL_STATE_UNATTACHED);
+       VDeregisterVolOp_r(vp);
     }
 #endif
 
     return SYNC_OK;
 }
 
+#ifdef AFS_DEMAND_ATTACH_FS
+/**
+ * force a volume into the hard error state.
+ */
+static afs_int32
+FSYNC_com_VolError(FSSYNC_VolOp_command * vcom, SYNC_response * res)
+{
+    Error error;
+    Volume * vp;
+    afs_int32 code = SYNC_DENIED;
+
+    vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
+    if (vp && !strcmp(VPartitionPath(V_partition(vp)), vcom->vop->partName)) {
+       memset(&vp->salvage, 0, sizeof(vp->salvage));
+       VChangeState_r(vp, VOL_STATE_ERROR);
+       code = SYNC_OK;
+    } else {
+       res->hdr.reason = FSYNC_UNKNOWN_VOLID;
+    }
+       
+    return code;
+}
+#endif
+
 static afs_int32
 FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 {
@@ -878,9 +963,60 @@ FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
 #endif /* AFS_DEMAND_ATTACH_FS */
 
 static afs_int32
+FSYNC_com_VnQry(int fd, SYNC_command * com, SYNC_response * res)
+{
+    afs_int32 code = SYNC_OK;
+    FSSYNC_VnQry_hdr * qry = com->payload.buf;
+    Volume * vp;
+    Vnode * vnp;
+    Error error;
+
+    if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_VnQry_hdr))) {
+       res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+       res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
+       return SYNC_COM_ERROR;
+    }
+
+#ifdef AFS_DEMAND_ATTACH_FS
+    vp = VLookupVolume_r(&error, qry->volume, NULL);
+#else /* !AFS_DEMAND_ATTACH_FS */
+    vp = VGetVolume_r(&error, qry->volume);
+#endif /* !AFS_DEMAND_ATTACH_FS */
+
+    if (!vp) {
+       res->hdr.reason = FSYNC_UNKNOWN_VOLID;
+       code = SYNC_FAILED;
+       goto done;
+    }
+
+    vnp = VLookupVnode(vp, qry->vnode);
+    if (!vnp) {
+       res->hdr.reason = FSYNC_UNKNOWN_VNID;
+       code = SYNC_FAILED;
+       goto cleanup;
+    }
+
+    if (Vn_class(vnp)->residentSize > res->payload.len) {
+       res->hdr.reason = SYNC_REASON_ENCODING_ERROR;
+       code = SYNC_FAILED;
+       goto cleanup;
+    }
+
+    memcpy(res->payload.buf, vnp, Vn_class(vnp)->residentSize);
+    res->hdr.response_len += Vn_class(vnp)->residentSize;
+
+ cleanup:
+#ifndef AFS_DEMAND_ATTACH_FS
+    VPutVolume_r(vp);
+#endif
+
+ done:
+    return code;
+}
+
+static afs_int32
 FSYNC_com_StatsOp(int fd, SYNC_command * com, SYNC_response * res)
 {
-    int i;
     afs_int32 code = SYNC_OK;
     FSSYNC_StatsOp_command scom;
 
@@ -937,8 +1073,8 @@ static afs_int32
 FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res)
 {
     afs_int32 code = SYNC_OK;
-    struct DiskPartition * dp;
-    struct DiskPartitionStats * stats;
+    struct DiskPartition64 * dp;
+    struct DiskPartitionStats64 * stats;
 
     if (SYNC_verifyProtocolString(scom->sop->args.partName, sizeof(scom->sop->args.partName))) {
        res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
@@ -950,14 +1086,14 @@ FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res)
     if (!dp) {
        code = SYNC_FAILED;
     } else {
-       stats = (struct DiskPartitionStats *) res->payload.buf;
+       stats = (struct DiskPartitionStats64 *) res->payload.buf;
        stats->free = dp->free;
        stats->totalUsable = dp->totalUsable;
        stats->minFree = dp->minFree;
        stats->f_files = dp->f_files;
        stats->vol_list_len = dp->vol_list.len;
        
-       res->hdr.response_len += sizeof(struct DiskPartitionStats);
+       res->hdr.response_len += sizeof(struct DiskPartitionStats64);
     }
 
  done:
@@ -1059,8 +1195,8 @@ static void
 AcceptOn()
 {
     if (AcceptHandler == -1) {
-       assert(AddHandler(AcceptSd, FSYNC_newconnection));
-       AcceptHandler = FindHandler(AcceptSd);
+       assert(AddHandler(fssync_server_state.fd, FSYNC_newconnection));
+       AcceptHandler = FindHandler(fssync_server_state.fd);
     }
 }
 
@@ -1068,7 +1204,7 @@ static void
 AcceptOff()
 {
     if (AcceptHandler != -1) {
-       assert(RemoveHandler(AcceptSd));
+       assert(RemoveHandler(fssync_server_state.fd));
        AcceptHandler = -1;
     }
 }
@@ -1090,6 +1226,24 @@ InitHandler()
     ReleaseWriteLock(&FSYNC_handler_lock);
 }
 
+#if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
+static void
+CallHandler(struct pollfd *fds, int nfds, int mask)
+{
+    int i;
+    int handler;
+    ObtainReadLock(&FSYNC_handler_lock);
+    for (i = 0; i < nfds; i++) {
+        if (fds[i].revents & mask) {
+           handler = FindHandler_r(fds[i].fd);
+            ReleaseReadLock(&FSYNC_handler_lock);
+            (*HandlerProc[handler]) (fds[i].fd);
+           ObtainReadLock(&FSYNC_handler_lock);
+        }
+    }
+    ReleaseReadLock(&FSYNC_handler_lock);
+}
+#else
 static void
 CallHandler(fd_set * fdsetp)
 {
@@ -1104,6 +1258,7 @@ CallHandler(fd_set * fdsetp)
     }
     ReleaseReadLock(&FSYNC_handler_lock);
 }
+#endif
 
 static int
 AddHandler(int afd, int (*aproc) ())
@@ -1159,6 +1314,25 @@ RemoveHandler(register int afd)
     return 1;
 }
 
+#if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
+static void
+GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds)
+{
+    int i;
+    int fdi = 0;
+    ObtainReadLock(&FSYNC_handler_lock);
+    for (i = 0; i < MAXHANDLERS; i++)
+       if (HandlerFD[i] != -1) {
+           assert(fdi<maxfds);
+           fds[fdi].fd = HandlerFD[i];
+           fds[fdi].events = events;
+           fds[fdi].revents = 0;
+           fdi++;
+       }
+    *nfds = fdi;
+    ReleaseReadLock(&FSYNC_handler_lock);
+}
+#else
 static void
 GetHandler(fd_set * fdsetp, int *maxfdp)
 {
@@ -1175,5 +1349,6 @@ GetHandler(fd_set * fdsetp, int *maxfdp)
     *maxfdp = maxfd;
     ReleaseReadLock(&FSYNC_handler_lock);      /* just in case */
 }
+#endif /* HAVE_POLL && AFS_PTHREAD_ENV */
 
 #endif /* FSSYNC_BUILD_SERVER */