Discovered another case where VNOVNODE errors were not being handled.
If there are dirty buffers and a VNOVNODE error is received while
writing the buffer, the buffer would be left in the dirty buffers queue.
This caused a couple problems:
(1) any attempt to flush the file, volume, or cache would fail because
there were unflushed dirty buffers that could not be flushed.
(2) shutdown of the service would hang because the buffers could not
be flushed.
In addition, while a VNOVNODE error would result in the cm_scache_t
being marked CM_SCACHEFLAG_DELETED, this state was not being checked
at the SMB layer. As a result, if a smb_fid_t was allocated and it
referenced the deleted cm_scache_t, the SMB operations would continue
to be processed and report success even if the actual file or directory
no longer existed.
We now clear the dirty state on buffers which cannot be written due to
VNOVNODE errors. We also check the cm_scache_t for deletion prior to
use whenever a smb_fid_t is looked up. If the cm_scache_t is deleted,
the smb_fid_t is closed and the error CM_ERROR_NOSUCHFILE is returned
for files or CM_ERROR_NOSUCHPATH for directories.
* because we aren't going to be able to write this data to the file
* server.
*/
- if (code == CM_ERROR_NOSUCHFILE){
+ if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BADFD){
bp->flags &= ~CM_BUF_DIRTY;
bp->flags |= CM_BUF_ERROR;
bp->dirty_offset = 0;
bp->dirty_length = 0;
- bp->error = CM_ERROR_NOSUCHFILE;
+ bp->error = code;
bp->dataVersion = -1; /* bad */
bp->dirtyCounter++;
}
lock_ReleaseMutex(&bp->mx);
code = (*cm_buf_opsp->Stabilizep)(scp, userp, reqp);
- if (code)
+ if (code && code != CM_ERROR_BADFD)
goto skip;
+ /* if the scp's FID is bad its because we received VNOVNODE
+ * when attempting to FetchStatus before the write. This
+ * page therefore contains data that can no longer be stored.
+ */
+ lock_ObtainMutex(&bp->mx);
+ bp->flags &= ~CM_BUF_DIRTY;
+ bp->flags |= CM_BUF_ERROR;
+ bp->error = code;
+ bp->dirty_offset = 0;
+ bp->dirty_length = 0;
+ bp->dataVersion = -1; /* known bad */
+ bp->dirtyCounter++;
+ lock_ReleaseMutex(&bp->mx);
+
lock_ObtainWrite(&buf_globalLock);
/* actually, we only know that buffer is clean if ref
* count is 1, since we don't have buffer itself locked.
}
lock_ReleaseWrite(&buf_globalLock);
- (*cm_buf_opsp->Unstabilizep)(scp, userp);
+ if (code != CM_ERROR_BADFD)
+ (*cm_buf_opsp->Unstabilizep)(scp, userp);
}
skip:
*/
lock_ObtainMutex(&scp->mx);
- cm_AFSFidFromFid(&tfid, &scp->fid);
-
if (scp->flags & CM_SCACHEFLAG_DELETED) {
lock_ReleaseMutex(&scp->mx);
return CM_ERROR_NOSUCHFILE;
}
+ cm_AFSFidFromFid(&tfid, &scp->fid);
+
code = cm_SetupStoreBIOD(scp, offsetp, length, &biod, userp, reqp);
if (code) {
osi_Log1(afsd_logp, "cm_SetupStoreBIOD code %x", code);
outp->res[1] = inSmbp->res[1];
op->inCom = inSmbp->com;
}
- outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
+ outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
+#ifdef SEND_CANONICAL_PATHNAMES
+ outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
+#endif
outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
/* copy fields in generic packet area */
if (!fidp)
goto send1;
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ code = CM_ERROR_NOSUCHFILE;
+ goto send1a;
+ }
+
+
pid = ((smb_t *) inp)->pid;
{
LARGE_INTEGER LOffset, LLength;
if (!fidp)
return CM_ERROR_BADFD;
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
lock_ObtainMutex(&fidp->mx);
if (fidp->flags & SMB_FID_IOCTL) {
lock_ReleaseMutex(&fidp->mx);
return CM_ERROR_BADFD;
}
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
lock_ObtainMutex(&fidp->mx);
if (fidp->flags & SMB_FID_IOCTL) {
lock_ReleaseMutex(&fidp->mx);
fd = smb_GetSMBParm(inp, 0);
fidp = smb_FindFID(vcp, fd, 0);
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return;
+ }
+
osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
return CM_ERROR_BADFD;
}
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
{
unsigned pid;
cm_key_t key;
if (!fidp)
return CM_ERROR_BADFD;
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
lock_ObtainMutex(&fidp->mx);
if (fidp->flags & SMB_FID_IOCTL) {
lock_ReleaseMutex(&fidp->mx);
/* try to find the file descriptor */
fd = smb_ChainFID(fd, inp);
fidp = smb_FindFID(vcp, fd, 0);
-
if (!fidp)
return CM_ERROR_BADFD;
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
lock_ObtainMutex(&fidp->mx);
if (fidp->flags & SMB_FID_IOCTL) {
lock_ReleaseMutex(&fidp->mx);
return 0;
}
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return 0;
+ }
+
infoLevel = p->parmsp[1];
if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
responseSize = sizeof(qfi.u.QFbasicInfo);
return 0;
}
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return 0;
+ }
+
infoLevel = p->parmsp[1];
osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
if (!fidp)
return CM_ERROR_BADFD;
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
lock_ObtainMutex(&fidp->mx);
if (fidp->flags & SMB_FID_IOCTL) {
osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
if (!fidp)
return CM_ERROR_BADFD;
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
lock_ObtainMutex(&fidp->mx);
if (fidp->flags & SMB_FID_IOCTL) {
lock_ReleaseMutex(&fidp->mx);
if (!fidp)
return CM_ERROR_BADFD;
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
lock_ObtainMutex(&fidp->mx);
if (fidp->flags & SMB_FID_IOCTL) {
lock_ReleaseMutex(&fidp->mx);
if (!fidp)
return CM_ERROR_BADFD;
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
lock_ObtainMutex(&fidp->mx);
if (fidp->flags & SMB_FID_IOCTL) {
lock_ReleaseMutex(&fidp->mx);
return CM_ERROR_BADFD;
}
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
pid = ((smb_t *) inp)->pid;
key = cm_GenerateKey(vcp->vcID, pid, fd);
{
cm_ReleaseUser(userp);
return CM_ERROR_INVAL;
}
+
+ if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ free(realPathp);
+ cm_ReleaseUser(userp);
+ smb_CloseFID(vcp, baseFidp, NULL, 0);
+ smb_ReleaseFID(baseFidp);
+ return CM_ERROR_NOSUCHPATH;
+ }
+
baseDirp = baseFidp->scp;
tidPathp = NULL;
}
osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
free(realPathp);
cm_ReleaseUser(userp);
- return CM_ERROR_INVAL;
+ return CM_ERROR_BADFD;
}
+
+ if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ free(realPathp);
+ cm_ReleaseUser(userp);
+ smb_CloseFID(vcp, baseFidp, NULL, 0);
+ smb_ReleaseFID(baseFidp);
+ return CM_ERROR_NOSUCHPATH;
+ }
+
baseDirp = baseFidp->scp;
tidPathp = NULL;
}
return CM_ERROR_BADFD;
}
+ if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+ smb_CloseFID(vcp, fidp, NULL, 0);
+ smb_ReleaseFID(fidp);
+ return CM_ERROR_NOSUCHFILE;
+ }
+
/* Create a copy of the Directory Watch Packet to use when sending the
* notification if in the future a matching change is detected.
*/
lastWatch = watch;
watch = watch->nextp;
continue;
- }
- if (fidp->scp != dscp
- || (filter & notifyFilter) == 0
- || (!isDirectParent && !wtree)) {
+ }
+
+ if (fidp->scp != dscp ||
+ fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
+ (filter & notifyFilter) == 0 ||
+ (!isDirectParent && !wtree))
+ {
osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
smb_ReleaseFID(fidp);
lastWatch = watch;
lock_ReleaseMutex(&dscp->mx);
/* Convert to response packet */
- ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
+ ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
+#ifdef SEND_CANONICAL_PATHNAMES
+ ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
+#endif
((smb_t *) watch)->wct = 0;
/* out parms */