#include <afsconfig.h>
#include <afs/param.h>
+#include <roken.h>
#include <stdio.h>
#include <stdlib.h>
pthread_mutex_t fileproc_glock_mutex;
#endif /* AFS_PTHREAD_ENV */
-#ifdef O_LARGEFILE
-#define afs_stat stat64
-#define afs_fstat fstat64
-#define afs_open open64
-#else /* !O_LARGEFILE */
-#define afs_stat stat
-#define afs_fstat fstat
-#define afs_open open
-#endif /* !O_LARGEFILE */
-
-
/* Useful local defines used by this module */
#define DONTCHECK 0
FS_UNLOCK;
} /*SetVolumeSync */
+/**
+ * Verify that the on-disk size for a vnode matches the length in the vnode
+ * index.
+ *
+ * @param[in] vp Volume pointer
+ * @param[in] vnp Vnode pointer
+ * @param[in] alen Size of the vnode on disk, if known. If unknown, give -1,
+ * and CheckLength itself will determine the on-disk size.
+ *
+ * @return operation status
+ * @retval 0 lengths match
+ * @retval nonzero Error; either the lengths do not match or there was an
+ * error determining the on-disk size. The volume should be
+ * taken offline and salvaged.
+ */
+static int
+CheckLength(struct Volume *vp, struct Vnode *vnp, afs_sfsize_t alen)
+{
+ afs_sfsize_t vlen;
+ VN_GET_LEN(vlen, vnp);
+
+ if (alen < 0) {
+ FdHandle_t *fdP;
+
+ fdP = IH_OPEN(vnp->handle);
+ if (fdP == NULL) {
+ ViceLog(0, ("CheckLength: cannot open inode for fid %lu.%lu.%lu\n",
+ afs_printable_uint32_lu(vp->hashid),
+ afs_printable_uint32_lu(Vn_id(vnp)),
+ afs_printable_uint32_lu(vnp->disk.uniquifier)));
+ return -1;
+ }
+ alen = FDH_SIZE(fdP);
+ FDH_CLOSE(fdP);
+ if (alen < 0) {
+ afs_int64 alen64 = alen;
+ ViceLog(0, ("CheckLength: cannot get size for inode for fid "
+ "%lu.%lu.%lu; FDH_SIZE returned %" AFS_INT64_FMT "\n",
+ afs_printable_uint32_lu(vp->hashid),
+ afs_printable_uint32_lu(Vn_id(vnp)),
+ afs_printable_uint32_lu(vnp->disk.uniquifier),
+ alen64));
+ return -1;
+ }
+ }
+
+ if (alen != vlen) {
+ afs_int64 alen64 = alen, vlen64 = vlen;
+ ViceLog(0, ("Fid %lu.%lu.%lu has inconsistent length (index "
+ "%" AFS_INT64_FMT ", inode %" AFS_INT64_FMT "); volume "
+ "must be salvaged\n",
+ afs_printable_uint32_lu(vp->hashid),
+ afs_printable_uint32_lu(Vn_id(vnp)),
+ afs_printable_uint32_lu(vnp->disk.uniquifier),
+ vlen64, alen64));
+ return -1;
+ }
+ return 0;
+}
+
/*
* Note that this function always returns a held host, so
* that CallPostamble can block without the host's disappearing.
* are incremented and they must be eventualy released.
*/
static afs_int32
-CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
+CheckVnodeWithCall(AFSFid * fid, Volume ** volptr, struct VCallByVol *cbv,
+ Vnode ** vptr, int lock)
{
Error fileCode = 0;
Error local_errorCode, errorCode = -1;
VRESTARTING
#endif
;
+#ifdef AFS_PTHREAD_ENV
+ static const struct timespec timeout_ts = { 0, 0 };
+ static const struct timespec * const ts = &timeout_ts;
+#else
+ static const struct timespec * const ts = NULL;
+#endif
errorCode = 0;
- *volptr = VGetVolumeNoWait(&local_errorCode, &errorCode, (afs_int32) fid->Volume);
+ *volptr = VGetVolumeWithCall(&local_errorCode, &errorCode,
+ fid->Volume, ts, cbv);
if (!errorCode) {
osi_Assert(*volptr);
break;
return (0);
} /*CheckVnode */
+static_inline afs_int32
+CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
+{
+ return CheckVnodeWithCall(fid, volptr, NULL, vptr, lock);
+}
+
/*
* This routine returns the ACL associated with the targetptr. If the
* targetptr isn't a directory, we access its parent dir and get the ACL
* interface calls.
*/
static afs_int32
-GetVolumePackage(struct rx_connection *tcon, AFSFid * Fid, Volume ** volptr,
- Vnode ** targetptr, int chkforDir, Vnode ** parent,
- struct client **client, int locktype, afs_int32 * rights,
- afs_int32 * anyrights)
+GetVolumePackageWithCall(struct rx_connection *tcon, struct VCallByVol *cbv,
+ AFSFid * Fid, Volume ** volptr, Vnode ** targetptr,
+ int chkforDir, Vnode ** parent, struct client **client,
+ int locktype, afs_int32 * rights, afs_int32 * anyrights)
{
struct acl_accessList *aCL; /* Internal access List */
int aCLSize; /* size of the access list */
Error errorCode = 0; /* return code to caller */
- if ((errorCode = CheckVnode(Fid, volptr, targetptr, locktype)))
+ if ((errorCode = CheckVnodeWithCall(Fid, volptr, cbv, targetptr, locktype)))
return (errorCode);
if (chkforDir) {
if (chkforDir == MustNOTBeDIR
} /*GetVolumePackage */
+static_inline afs_int32
+GetVolumePackage(struct rx_connection *tcon, AFSFid * Fid, Volume ** volptr,
+ Vnode ** targetptr, int chkforDir, Vnode ** parent,
+ struct client **client, int locktype, afs_int32 * rights,
+ afs_int32 * anyrights)
+{
+ return GetVolumePackageWithCall(tcon, NULL, Fid, volptr, targetptr,
+ chkforDir, parent, client, locktype,
+ rights, anyrights);
+}
+
/*
* This is the opposite of GetVolumePackage(), and is always used at the end of
* AFS calls to put back all used vnodes and the volume in the proper order!
*/
static void
-PutVolumePackage(Vnode * parentwhentargetnotdir, Vnode * targetptr,
- Vnode * parentptr, Volume * volptr, struct client **client)
+PutVolumePackageWithCall(Vnode * parentwhentargetnotdir, Vnode * targetptr,
+ Vnode * parentptr, Volume * volptr,
+ struct client **client, struct VCallByVol *cbv)
{
Error fileCode = 0; /* Error code returned by the volume package */
osi_Assert(!fileCode || (fileCode == VSALVAGE));
}
if (volptr) {
- VPutVolume(volptr);
+ VPutVolumeWithCall(volptr, cbv);
}
if (*client) {
PutClient(client);
}
} /*PutVolumePackage */
+static_inline void
+PutVolumePackage(Vnode * parentwhentargetnotdir, Vnode * targetptr,
+ Vnode * parentptr, Volume * volptr, struct client **client)
+{
+ PutVolumePackageWithCall(parentwhentargetnotdir, targetptr, parentptr,
+ volptr, client, NULL);
+}
+
static int
VolumeOwner(struct client *client, Vnode * targetptr)
{
} else { /* file */
/* must have read access, or be owner and have insert access */
if (!(rights & PRSFS_READ)
- && !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)))
+ && !((OWNSp(client, targetptr) && (rights & PRSFS_INSERT)
+ && (client->ViceId != AnonymousID))))
return (EACCES);
}
if (CallingRoutine == CHK_FETCHDATA
/* watch for invalid names */
if (!strcmp(Name, ".") || !strcmp(Name, ".."))
return (EINVAL);
+
+ if (CheckLength(volptr, parentptr, -1)) {
+ VTakeOffline_r(volptr);
+ return VSALVAGE;
+ }
+
if (parentptr->disk.cloned) {
ViceLog(25, ("DeleteTarget : CopyOnWrite called\n"));
if ((errorCode = CopyOnWrite(parentptr, volptr, 0, MAXFSIZE))) {
return (errorCode);
}
+ if (CheckLength(volptr, parentptr, -1)) {
+ VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
+ VTakeOffline_r(volptr);
+ return VSALVAGE;
+ }
+
*targetptr = VAllocVnode(&errorCode, volptr, FileType);
if (errorCode != 0) {
VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
afs_int32 rights, anyrights; /* rights for this and any user */
struct client *t_client = NULL; /* tmp ptr to client data */
struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
+ struct VCallByVol tcbv, *cbv = NULL;
#if FS_STATS_DETAILED
struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */
struct fs_stats_xferData *xferP; /* Ptr to this op's byte size struct */
("SRXAFS_FetchData, Fid = %u.%u.%u, Host %s:%d, Id %d\n",
Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
ntohs(rxr_PortOf(tcon)), t_client->ViceId));
+
+ queue_NodeInit(&tcbv);
+ tcbv.call = acall;
+ cbv = &tcbv;
+
/*
* Get volume/vnode for the fetched file; caller's access rights to
* it are also returned
*/
if ((errorCode =
- GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
+ GetVolumePackageWithCall(tcon, cbv, Fid, &volptr, &targetptr, DONTCHECK,
&parentwhentargetnotdir, &client, READ_LOCK,
&rights, &anyrights)))
goto Bad_FetchData;
Bad_FetchData:
/* Update and store volume/vnode and parent vnodes back */
- (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
- volptr, &client);
+ (void)PutVolumePackageWithCall(parentwhentargetnotdir, targetptr,
+ (Vnode *) 0, volptr, &client, cbv);
ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode));
errorCode = CallPostamble(tcon, errorCode, thost);
volptr->hashid));
return EIO;
}
+ if (CheckLength(volptr, targetptr, tlen)) {
+ FDH_CLOSE(fdP);
+ VTakeOffline(volptr);
+ return VSALVAGE;
+ }
if (Pos > tlen) {
Len = 0;
}
(*a_bytesFetchedP) += nBytes;
#endif /* FS_STATS_DETAILED */
if (nBytes != wlen) {
+ afs_int32 err;
FDH_CLOSE(fdP);
#ifndef HAVE_PIOV
FreeSendBuffer((struct afs_buffer *)tbuffer);
#endif /* HAVE_PIOV */
+ err = VIsGoingOffline(volptr);
+ if (err) {
+ return err;
+ }
return -31;
}
Len -= wlen;
lhp = IH_OPEN(V_linkHandle(vp));
if (!lhp)
return EIO;
-#ifdef AFS_NT40_ENV
- *lc = nt_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
-#else
- *lc = namei_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
-#endif
+ *lc = namei_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0, 0, 1);
FDH_CLOSE(lhp);
if (*lc < 0)
return -1;
volptr->hashid));
return EIO;
}
+ if (CheckLength(volptr, targetptr, DataLength)) {
+ FDH_CLOSE(fdP);
+ VTakeOffline(volptr);
+ return VSALVAGE;
+ }
if (linkCount != 1) {
afs_fsize_t size;