/** Handle a SMB_COM_READ for an RPC fid Called from smb_ReceiveCoreRead when we receive a read on the RPC fid */ afs_int32 smb_RPCRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) { smb_rpc_t *rpcp; long count; char *op; afs_int32 code; cm_user_t *userp; count = smb_GetSMBParm(inp, 1); userp = smb_GetUserFromVCP(vcp, inp); osi_Log3(smb_logp, "smb_RPCRead for user[0x%p] fid[0x%p (%d)]", userp, fidp, fidp->fid); lock_ObtainMutex(&fidp->mx); rpcp = fidp->rpcp; code = smb_RPC_BeginOp(rpcp); lock_ReleaseMutex(&fidp->mx); if (code) { cm_ReleaseUser(userp); return code; } code = smb_RPC_PrepareRead(rpcp); if (code) { cm_ReleaseUser(userp); smb_RPC_EndOp(rpcp); return code; } count = smb_RPC_ReadPacketLength(rpcp, count); /* now set the parms for a read of count bytes */ smb_SetSMBParm(outp, 0, count); smb_SetSMBParm(outp, 1, 0); smb_SetSMBParm(outp, 2, 0); smb_SetSMBParm(outp, 3, 0); smb_SetSMBParm(outp, 4, 0); smb_SetSMBDataLength(outp, count+3); op = smb_GetSMBData(outp, NULL); *op++ = 1; *op++ = (char)(count & 0xff); *op++ = (char)((count >> 8) & 0xff); smb_RPC_ReadPacket(rpcp, op, count); smb_RPC_EndOp(rpcp); cm_ReleaseUser(userp); return 0; }
/* This must be called with cm_aclLock and the aclp->back->mx held */ static void CleanupACLEnt(cm_aclent_t * aclp) { cm_aclent_t *taclp; cm_aclent_t **laclpp; if (aclp->backp) { if (aclp->backp->randomACLp) { /* * Remove the entry from the vnode's list */ lock_AssertWrite(&aclp->backp->rw); laclpp = &aclp->backp->randomACLp; for (taclp = *laclpp; taclp; laclpp = &taclp->nextp, taclp = *laclpp) { if (taclp == aclp) break; } if (!taclp) osi_panic("CleanupACLEnt race", __FILE__, __LINE__); *laclpp = aclp->nextp; /* remove from vnode list */ } aclp->backp = NULL; } /* release the old user */ if (aclp->userp) { cm_ReleaseUser(aclp->userp); aclp->userp = NULL; } aclp->randomAccess = 0; aclp->tgtLifetime = 0; }
/* * Invalidate all ACL entries for particular user on this particular vnode. * * The scp must not be locked. */ void cm_InvalidateACLUser(cm_scache_t *scp, cm_user_t *userp) { cm_aclent_t *aclp; cm_aclent_t **laclpp; int found = 0; int callback = 0; lock_ObtainWrite(&scp->rw); lock_ObtainWrite(&cm_aclLock); laclpp = &scp->randomACLp; for (aclp = *laclpp; aclp; laclpp = &aclp->nextp, aclp = *laclpp) { if (userp == aclp->userp) { /* One for a given user/scache */ *laclpp = aclp->nextp; cm_ReleaseUser(aclp->userp); aclp->userp = NULL; aclp->backp = (struct cm_scache *) 0; found = 1; break; } } lock_ReleaseWrite(&cm_aclLock); if (found) callback = cm_HaveCallback(scp); lock_ReleaseWrite(&scp->rw); if (found && callback && RDR_Initialized) RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique, scp->fid.hash, scp->fileType, AFS_INVALIDATE_CREDS); }
void cm_QueueBKGRequest(cm_scache_t *scp, cm_bkgProc_t *procp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4, cm_user_t *userp, cm_req_t *reqp) { cm_bkgRequest_t *rp, *rpq; afs_uint32 daemonID; int duplicate = 0; rp = malloc(sizeof(*rp)); memset(rp, 0, sizeof(*rp)); cm_HoldSCache(scp); rp->scp = scp; cm_HoldUser(userp); rp->userp = userp; rp->procp = procp; rp->p1 = p1; rp->p2 = p2; rp->p3 = p3; rp->p4 = p4; rp->req = *reqp; /* Use separate queues for fetch and store operations */ daemonID = scp->fid.hash % (cm_nDaemons/2) * 2; if (procp == cm_BkgStore) daemonID++; lock_ObtainWrite(&cm_daemonLockp[daemonID]); /* Check to see if this is a duplicate request */ for (rpq = cm_bkgListpp[daemonID]; rpq; rpq = (cm_bkgRequest_t *) osi_QNext(&rpq->q)) { if ( rpq->p1 == p1 && rpq->p3 == p3 && rpq->procp == procp && rpq->p2 == p2 && rpq->p4 == p4 && rpq->scp == scp && rpq->userp == userp) { /* found a duplicate; update request with latest info */ duplicate = 1; break; } } if (!duplicate) { cm_bkgQueueCountp[daemonID]++; osi_QAddH((osi_queue_t **) &cm_bkgListpp[daemonID], (osi_queue_t **)&cm_bkgListEndpp[daemonID], &rp->q); } lock_ReleaseWrite(&cm_daemonLockp[daemonID]); if (duplicate) { cm_ReleaseSCache(scp); cm_ReleaseUser(userp); free(rp); } else { osi_Wakeup((LONG_PTR) &cm_bkgListpp[daemonID]); } }
/** Handle SMB_COM_WRITE_ANDX for an RPC fid Called from smb_ReceiveV3WriteX when we receive a write call on the RPC file descriptor. */ afs_int32 smb_RPCV3Write(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) { smb_rpc_t *rpcp; long count; afs_int32 code; char *op; cm_user_t *userp = NULL; code = 0; count = smb_GetSMBParm(inp, 10); userp = smb_GetUserFromVCP(vcp, inp); osi_Log3(smb_logp, "smb_RPCV3Write for user[0x%p] fid[0x%p (%d)]", userp, fidp, fidp->fid); if (userp == NULL) { code = CM_ERROR_BADSMB; goto done; } lock_ObtainMutex(&fidp->mx); rpcp = fidp->rpcp; code = smb_RPC_BeginOp(rpcp); lock_ReleaseMutex(&fidp->mx); if (code) goto done; smb_RPC_PrepareWrite(rpcp); op = inp->data + smb_GetSMBParm(inp, 11); code = smb_RPC_WritePacket(rpcp, op, count, userp); smb_RPC_EndOp(rpcp); done: /* return # of bytes written */ if (code == 0) { smb_SetSMBParm(outp, 2, count); smb_SetSMBParm(outp, 3, 0); /* reserved */ smb_SetSMBParm(outp, 4, 0); /* reserved */ smb_SetSMBParm(outp, 5, 0); /* reserved */ smb_SetSMBDataLength(outp, 0); } if (userp) cm_ReleaseUser(userp); return code; }
/* * Invalidate all ACL entries for particular user on this particular vnode. * * The scp must be locked. */ void cm_InvalidateACLUser(cm_scache_t *scp, cm_user_t *userp) { cm_aclent_t *aclp; cm_aclent_t **laclpp; lock_ObtainWrite(&cm_aclLock); laclpp = &scp->randomACLp; for (aclp = *laclpp; aclp; laclpp = &aclp->nextp, aclp = *laclpp) { if (userp == aclp->userp) { /* One for a given user/scache */ *laclpp = aclp->nextp; cm_ReleaseUser(aclp->userp); aclp->userp = NULL; aclp->backp = (struct cm_scache *) 0; break; } } lock_ReleaseWrite(&cm_aclLock); }
/* * Free all associated acl entries. We actually just clear the back pointer * since the acl entries are already in the free list. The scp must be locked * or completely unreferenced (such as when called while recycling the scp). */ void cm_FreeAllACLEnts(cm_scache_t *scp) { cm_aclent_t *aclp; cm_aclent_t *taclp; lock_ObtainWrite(&cm_aclLock); for (aclp = scp->randomACLp; aclp; aclp = taclp) { taclp = aclp->nextp; if (aclp->userp) { cm_ReleaseUser(aclp->userp); aclp->userp = NULL; } aclp->backp = (struct cm_scache *) 0; } scp->randomACLp = (struct cm_aclent *) 0; scp->anyAccess = 0; /* reset this, too */ lock_ReleaseWrite(&cm_aclLock); }
void cm_BkgDaemon(void * parm) { cm_bkgRequest_t *rp; afs_int32 code; char name[32] = ""; long daemonID = (long)parm; snprintf(name, sizeof(name), "cm_BkgDaemon_ShutdownEvent%d", daemonID); cm_BkgDaemon_ShutdownEvent[daemonID] = thrd_CreateEvent(NULL, FALSE, FALSE, name); if ( GetLastError() == ERROR_ALREADY_EXISTS ) afsi_log("Event Object Already Exists: %s", name); rx_StartClientThread(); lock_ObtainWrite(&cm_daemonLock); while (daemon_ShutdownFlag == 0) { if (powerStateSuspended) { Sleep(1000); continue; } if (!cm_bkgListEndp) { osi_SleepW((LONG_PTR)&cm_bkgListp, &cm_daemonLock); lock_ObtainWrite(&cm_daemonLock); continue; } /* we found a request */ for (rp = cm_bkgListEndp; rp; rp = (cm_bkgRequest_t *) osi_QPrev(&rp->q)) { if (cm_ServerAvailable(&rp->scp->fid, rp->userp) && !(rp->scp->flags & CM_SCACHEFLAG_DATASTORING)) break; } if (rp == NULL) { /* we couldn't find a request that we could process at the current time */ lock_ReleaseWrite(&cm_daemonLock); Sleep(1000); lock_ObtainWrite(&cm_daemonLock); continue; } osi_QRemoveHT((osi_queue_t **) &cm_bkgListp, (osi_queue_t **) &cm_bkgListEndp, &rp->q); osi_assertx(cm_bkgQueueCount-- > 0, "cm_bkgQueueCount 0"); lock_ReleaseWrite(&cm_daemonLock); osi_Log1(afsd_logp,"cm_BkgDaemon processing request 0x%p", rp); #ifdef DEBUG_REFCOUNT osi_Log2(afsd_logp,"cm_BkgDaemon (before) scp 0x%x ref %d",rp->scp, rp->scp->refCount); #endif code = (*rp->procp)(rp->scp, rp->p1, rp->p2, rp->p3, rp->p4, rp->userp); #ifdef DEBUG_REFCOUNT osi_Log2(afsd_logp,"cm_BkgDaemon (after) scp 0x%x ref %d",rp->scp, rp->scp->refCount); #endif /* * Keep the following list synchronized with the * error code list in cm_BkgStore. * cm_SyncOpDone(CM_SCACHESYNC_ASYNCSTORE) will be called there unless * one of these errors has occurred. */ switch ( code ) { case CM_ERROR_TIMEDOUT: /* or server restarting */ case CM_ERROR_RETRY: case CM_ERROR_WOULDBLOCK: case CM_ERROR_ALLBUSY: case CM_ERROR_ALLDOWN: case CM_ERROR_ALLOFFLINE: case CM_ERROR_PARTIALWRITE: if (rp->procp == cm_BkgStore) { osi_Log2(afsd_logp, "cm_BkgDaemon re-queueing failed request 0x%p code 0x%x", rp, code); lock_ObtainWrite(&cm_daemonLock); cm_bkgQueueCount++; osi_QAddT((osi_queue_t **) &cm_bkgListp, (osi_queue_t **)&cm_bkgListEndp, &rp->q); break; } /* otherwise fall through */ case 0: /* success */ default: /* other error */ if (code == 0) osi_Log1(afsd_logp,"cm_BkgDaemon SUCCESS: request 0x%p", rp); else osi_Log2(afsd_logp,"cm_BkgDaemon FAILED: request dropped 0x%p code 0x%x", rp, code); cm_ReleaseUser(rp->userp); cm_ReleaseSCache(rp->scp); free(rp); lock_ObtainWrite(&cm_daemonLock); } } lock_ReleaseWrite(&cm_daemonLock); thrd_SetEvent(cm_BkgDaemon_ShutdownEvent[daemonID]); }
afs_int32 smb_RPCNmpipeTransact(smb_fid_t *fidp, smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op) { smb_tran2Packet_t *outp = NULL; struct smb_rpc *rpcp; afs_int32 code = 0; cm_user_t * userp = NULL; smb_user_t * uidp = NULL; int len; osi_Log0(smb_logp, "smb_RPCNmpipeTransact() begin"); uidp = smb_FindUID(vcp, p->uid, 0); if (!uidp) return CM_ERROR_BADSMB; userp = smb_GetUserFromUID(uidp); osi_assertx(userp != NULL, "null cm_user_t"); if (uidp && uidp->unp) { osi_Log3(afsd_logp, "RPC Transact uid %d user %x name %S", uidp->userID, userp, osi_LogSaveClientString(afsd_logp, uidp->unp->name)); } else { if (uidp) osi_Log2(afsd_logp, "RPC Transact uid %d user %x no name", uidp->userID, userp); else osi_Log1(afsd_logp, "RPC Transact no uid user %x no name", userp); } lock_ObtainMutex(&fidp->mx); rpcp = fidp->rpcp; code = smb_RPC_BeginOp(rpcp); if (code) { osi_Log0(smb_logp, "Can't begin RPC op. Aborting"); lock_ReleaseMutex(&fidp->mx); smb_ReleaseUID(uidp); cm_ReleaseUser(userp); return code; } osi_assertx((fidp->flags & SMB_FID_RPC), "FID wasn't setup for RPC"); osi_assertx(fidp->rpcp, "smb_rpc_t not associated with RPC FID"); lock_ReleaseMutex(&fidp->mx); code = smb_RPC_PrepareWrite(rpcp); if (code) goto done; code = smb_RPC_WritePacket(rpcp, p->datap, p->totalData, userp); if (code) goto done; code = smb_RPC_PrepareRead(rpcp); if (code) goto done; len = smb_RPC_ReadPacketLength(rpcp, p->maxReturnData); outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, len); if (len > 0) { code = smb_RPC_ReadPacket(rpcp, outp->datap, len); if (code == CM_ERROR_RPC_MOREDATA) { outp->error_code = CM_ERROR_RPC_MOREDATA; } } if (code == 0 || code == CM_ERROR_RPC_MOREDATA) smb_SendTran2Packet(vcp, outp, op); smb_FreeTran2Packet(outp); done: smb_RPC_EndOp(rpcp); osi_Log1(smb_logp, "smb_RPCNmpipeTransact() end code=%d", code); if (uidp) smb_ReleaseUID(uidp); if (userp) cm_ReleaseUser(userp); return code; }
/** Handle SMB_COM_READ_ANDX for an RPC fid Called from smb_ReceiveV3ReadX to handle RPC descriptor reads */ afs_int32 smb_RPCV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp) { smb_rpc_t *rpcp; long count; afs_int32 code; char *op; cm_user_t *userp; smb_user_t *uidp; count = smb_GetSMBParm(inp, 5); uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0); if (!uidp) return CM_ERROR_BADSMB; userp = smb_GetUserFromUID(uidp); osi_assertx(userp != NULL, "null cm_user_t"); osi_Log3(smb_logp, "smb_RPCV3Read for user[0x%p] fid[0x%p (%d)]", userp, fidp, fidp->fid); if (uidp && uidp->unp) { osi_Log3(afsd_logp, "RPC uid %d user %x name %S", uidp->userID, userp, osi_LogSaveClientString(afsd_logp, uidp->unp->name)); } else { if (uidp) osi_Log2(afsd_logp, "RPC uid %d user %x no name", uidp->userID, userp); else osi_Log1(afsd_logp, "RPC no uid user %x no name", userp); } lock_ObtainMutex(&fidp->mx); rpcp = fidp->rpcp; code = smb_RPC_BeginOp(rpcp); lock_ReleaseMutex(&fidp->mx); if (code) { if (uidp) smb_ReleaseUID(uidp); cm_ReleaseUser(userp); return code; } code = smb_RPC_PrepareRead(rpcp); if (uidp) { smb_ReleaseUID(uidp); } if (code) { cm_ReleaseUser(userp); smb_RPC_EndOp(rpcp); return code; } count = smb_RPC_ReadPacketLength(rpcp, count); /* 0 and 1 are reserved for request chaining, were setup by our caller, * and will be further filled in after we return. */ smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */ smb_SetSMBParm(outp, 3, 0); /* resvd */ smb_SetSMBParm(outp, 4, 0); /* resvd */ smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */ /* fill in #6 when we have all the parameters' space reserved */ smb_SetSMBParm(outp, 7, 0); /* resv'd */ smb_SetSMBParm(outp, 8, 0); /* resv'd */ smb_SetSMBParm(outp, 9, 0); /* resv'd */ smb_SetSMBParm(outp, 10, 0); /* resv'd */ smb_SetSMBParm(outp, 11, 0); /* reserved */ /* get op ptr after putting in the last parm, since otherwise we don't * know where the data really is. */ op = smb_GetSMBData(outp, NULL); /* now fill in offset from start of SMB header to first data byte (to op) */ smb_SetSMBParm(outp, 6, ((int) (op - outp->data))); /* set the packet data length the count of the # of bytes */ smb_SetSMBDataLength(outp, count); smb_RPC_ReadPacket(rpcp, op, count); smb_RPC_EndOp(rpcp); /* and cleanup things */ cm_ReleaseUser(userp); return 0; }
void * cm_BkgDaemon(void * vparm) { cm_bkgRequest_t *rp; afs_int32 code; char name[32] = ""; long daemonID = (long)(LONG_PTR)vparm; snprintf(name, sizeof(name), "cm_BkgDaemon_ShutdownEvent%u", daemonID); cm_BkgDaemon_ShutdownEvent[daemonID] = thrd_CreateEvent(NULL, FALSE, FALSE, name); if ( GetLastError() == ERROR_ALREADY_EXISTS ) afsi_log("Event Object Already Exists: %s", name); rx_StartClientThread(); lock_ObtainWrite(&cm_daemonLockp[daemonID]); while (daemon_ShutdownFlag == 0) { int willBlock = 0; if (powerStateSuspended) { Sleep(1000); continue; } if (!cm_bkgListEndpp[daemonID]) { osi_SleepW((LONG_PTR)&cm_bkgListpp[daemonID], &cm_daemonLockp[daemonID]); lock_ObtainWrite(&cm_daemonLockp[daemonID]); continue; } /* we found a request */ for (rp = cm_bkgListEndpp[daemonID]; rp; rp = (cm_bkgRequest_t *) osi_QPrev(&rp->q)) { if (rp->scp->flags & CM_SCACHEFLAG_DELETED) break; /* * If the request has active I/O such that this worker would * be forced to block, leave the request in the queue and move * on to one that might be available for servicing. */ if (cm_RequestWillBlock(rp)) { willBlock++; continue; } if (cm_ServerAvailable(&rp->scp->fid, rp->userp)) break; } if (rp == NULL) { /* * Couldn't find a request that we could process at the * current time. If there were requests that would cause * the worker to block, sleep for 25ms so it can promptly * respond when it is available. Otherwise, sleep for 1s. * * This polling cycle needs to be replaced with a proper * producer/consumer dynamic worker pool. */ osi_Log2(afsd_logp,"cm_BkgDaemon[%u] sleeping %dms all tasks would block", daemonID, willBlock ? 100 : 1000); lock_ReleaseWrite(&cm_daemonLockp[daemonID]); Sleep(willBlock ? 100 : 1000); lock_ObtainWrite(&cm_daemonLockp[daemonID]); continue; } osi_QRemoveHT((osi_queue_t **) &cm_bkgListpp[daemonID], (osi_queue_t **) &cm_bkgListEndpp[daemonID], &rp->q); osi_assertx(cm_bkgQueueCountp[daemonID]-- > 0, "cm_bkgQueueCount 0"); lock_ReleaseWrite(&cm_daemonLockp[daemonID]); osi_Log2(afsd_logp,"cm_BkgDaemon[%u] processing request 0x%p", daemonID, rp); if (rp->scp->flags & CM_SCACHEFLAG_DELETED) { osi_Log2(afsd_logp,"cm_BkgDaemon[%u] DELETED scp 0x%x", daemonID, rp->scp); code = CM_ERROR_BADFD; } else { #ifdef DEBUG_REFCOUNT osi_Log3(afsd_logp,"cm_BkgDaemon[%u] (before) scp 0x%x ref %d", daemonID, rp->scp, rp->scp->refCount); #endif code = (*rp->procp)(rp->scp, rp->p1, rp->p2, rp->p3, rp->p4, rp->userp, &rp->req); #ifdef DEBUG_REFCOUNT osi_Log3(afsd_logp,"cm_BkgDaemon[%u] (after) scp 0x%x ref %d", daemonID, rp->scp, rp->scp->refCount); #endif } /* * Keep the following list synchronized with the * error code list in cm_BkgStore. * cm_SyncOpDone(CM_SCACHESYNC_ASYNCSTORE) will be called there unless * one of these errors has occurred. */ switch ( code ) { case CM_ERROR_TIMEDOUT: /* or server restarting */ case CM_ERROR_RETRY: case CM_ERROR_WOULDBLOCK: case CM_ERROR_ALLBUSY: case CM_ERROR_ALLDOWN: case CM_ERROR_ALLOFFLINE: case CM_ERROR_PARTIALWRITE: if (rp->procp == cm_BkgStore || rp->procp == RDR_BkgFetch) { osi_Log3(afsd_logp, "cm_BkgDaemon[%u] re-queueing failed request 0x%p code 0x%x", daemonID, rp, code); lock_ObtainWrite(&cm_daemonLockp[daemonID]); cm_bkgQueueCountp[daemonID]++; osi_QAddT((osi_queue_t **) &cm_bkgListpp[daemonID], (osi_queue_t **)&cm_bkgListEndpp[daemonID], &rp->q); break; } /* otherwise fall through */ case 0: /* success */ default: /* other error */ if (code == 0) { osi_Log2(afsd_logp,"cm_BkgDaemon[%u] SUCCESS: request 0x%p", daemonID, rp); } else { osi_Log3(afsd_logp,"cm_BkgDaemon[%u] FAILED: request dropped 0x%p code 0x%x", daemonID, rp, code); } cm_ReleaseUser(rp->userp); cm_ReleaseSCache(rp->scp); free(rp); lock_ObtainWrite(&cm_daemonLockp[daemonID]); } } lock_ReleaseWrite(&cm_daemonLockp[daemonID]); thrd_SetEvent(cm_BkgDaemon_ShutdownEvent[daemonID]); pthread_exit(NULL); return NULL; }