afs_int32 PctSpare;
extern afs_int32 implicitAdminRights;
extern afs_int32 readonlyServer;
+extern int CopyOnWrite_calls, CopyOnWrite_off0, CopyOnWrite_size0;
+extern afs_fsize_t CopyOnWrite_maxsize;
/*
* Externals used by the xstat code.
* disk.inodeNumber and cloned)
*/
#define COPYBUFFSIZE 8192
+#define MAXFSIZE (~(afs_fsize_t) 0)
static int
-CopyOnWrite(Vnode * targetptr, Volume * volptr)
+CopyOnWrite(Vnode * targetptr, Volume * volptr, afs_fsize_t off, afs_fsize_t len)
{
Inode ino, nearInode;
int rdlen;
DFlush(); /* just in case? */
VN_GET_LEN(size, targetptr);
+ if (size > off)
+ size -= off;
+ else
+ size = 0;
+ if (size > len)
+ size = len;
+
buff = (char *)malloc(COPYBUFFSIZE);
if (buff == NULL) {
return EIO;
newFdP = IH_OPEN(newH);
assert(newFdP != NULL);
+ FDH_SEEK(targFdP, off, SEEK_SET);
+ FDH_SEEK(newFdP, off, SEEK_SET);
while (size > 0) {
if (size > COPYBUFFSIZE) { /* more than a buffer */
length = COPYBUFFSIZE;
return 0; /* success */
} /*CopyOnWrite */
+static int
+CopyOnWrite2(FdHandle_t *targFdP, FdHandle_t *newFdP, afs_fsize_t off, afs_fsize_t size) {
+ char *buff = (char *)malloc(COPYBUFFSIZE);
+ register int length;
+ int rdlen;
+ int wrlen;
+ int rc;
+
+ FDH_SEEK(targFdP, off, SEEK_SET);
+ FDH_SEEK(newFdP, off, SEEK_SET);
+
+ while (size > 0) {
+ if (size > COPYBUFFSIZE) { /* more than a buffer */
+ length = COPYBUFFSIZE;
+ size -= COPYBUFFSIZE;
+ } else {
+ length = (int)size;
+ size = 0;
+ }
+ rdlen = FDH_READ(targFdP, buff, length);
+ if (rdlen == length)
+ wrlen = FDH_WRITE(newFdP, buff, length);
+ else
+ wrlen = 0;
+
+ if ((rdlen != length) || (wrlen != length)) {
+ /* no error recovery, at the worst we'll have a "hole" in the file */
+ rc = 1;
+ break;
+ }
+ }
+ free(buff);
+ return rc;
+}
+
/*
* Common code to handle with removing the Name (file when it's called from
return (EINVAL);
if (parentptr->disk.cloned) {
ViceLog(25, ("DeleteTarget : CopyOnWrite called\n"));
- if ((errorCode = CopyOnWrite(parentptr, volptr))) {
+ if ((errorCode = CopyOnWrite(parentptr, volptr, 0, MAXFSIZE))) {
ViceLog(20,
("DeleteTarget %s: CopyOnWrite failed %d\n", Name,
errorCode));
if (parentptr->disk.cloned) {
ViceLog(25, ("Alloc_NewVnode : CopyOnWrite called\n"));
- if ((errorCode = CopyOnWrite(parentptr, volptr))) { /* disk full */
+ if ((errorCode = CopyOnWrite(parentptr, volptr, 0, MAXFSIZE))) { /* disk full */
ViceLog(25, ("Alloc_NewVnode : CopyOnWrite failed\n"));
/* delete the vnode previously allocated */
(*targetptr)->delete = 1;
*/
if (oldvptr->disk.cloned) {
ViceLog(25, ("Rename : calling CopyOnWrite on old dir\n"));
- if ((errorCode = CopyOnWrite(oldvptr, volptr)))
+ if ((errorCode = CopyOnWrite(oldvptr, volptr, 0, MAXFSIZE)))
goto Bad_Rename;
}
SetDirHandle(&olddir, oldvptr);
if (newvptr->disk.cloned) {
ViceLog(25, ("Rename : calling CopyOnWrite on new dir\n"));
- if ((errorCode = CopyOnWrite(newvptr, volptr)))
+ if ((errorCode = CopyOnWrite(newvptr, volptr, 0, MAXFSIZE)))
goto Bad_Rename;
}
*/
if ((fileptr->disk.type == vDirectory) && (fileptr->disk.cloned)) {
ViceLog(25, ("Rename : calling CopyOnWrite on target dir\n"));
- if ((errorCode = CopyOnWrite(fileptr, volptr)))
+ if ((errorCode = CopyOnWrite(fileptr, volptr, 0, MAXFSIZE)))
goto Bad_Rename;
}
}
if (parentptr->disk.cloned) {
ViceLog(25, ("Link : calling CopyOnWrite on target dir\n"));
- if ((errorCode = CopyOnWrite(parentptr, volptr)))
+ if ((errorCode = CopyOnWrite(parentptr, volptr, 0, MAXFSIZE)))
goto Bad_Link; /* disk full error */
}
afs_fsize_t NewLength; /* size after this store completes */
afs_sfsize_t adjustSize; /* bytes to call VAdjust... with */
int linkCount = 0; /* link count on inode */
- FdHandle_t *fdP;
+ afs_fsize_t CoW_off = 0, CoW_len = 0;
+ FdHandle_t *fdP, *origfdP = NULL;
struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
#if FS_STATS_DETAILED
* mechanisms (i.e. copy on write overhead.) Also the right size
* of the disk will be recorded...
*/
- FDH_CLOSE(fdP);
+ origfdP = fdP;
VN_GET_LEN(size, targetptr);
volptr->partition->flags &= ~PART_DONTUPDATE;
VSetPartitionDiskUsage(volptr->partition);
volptr->partition->flags |= PART_DONTUPDATE;
if ((errorCode = VDiskUsage(volptr, nBlocks(size)))) {
volptr->partition->flags &= ~PART_DONTUPDATE;
+ FDH_CLOSE(origfdP);
return (errorCode);
}
- ViceLog(25, ("StoreData : calling CopyOnWrite on target dir\n"));
- if ((errorCode = CopyOnWrite(targetptr, volptr))) {
+ if (Pos == 0)
+ CoW_off = Length; /* only copy remaining parts of file */
+ if (Length <= FileLength)
+ CoW_len = FileLength - Length;
+ CopyOnWrite_calls++;
+ if (CoW_len == 0) CopyOnWrite_size0++;
+ if (CoW_off == 0) CopyOnWrite_off0++;
+ if (CoW_len > CopyOnWrite_maxsize) CopyOnWrite_maxsize = CoW_len;
+
+ ViceLog(1, ("StoreData : calling CopyOnWrite on vnode %lu.%lu (%s) off 0x%llx size 0x%llx\n",
+ V_id(volptr), targetptr->vnodeNumber, V_name(volptr), CoW_off, CoW_len));
+ if ((errorCode = CopyOnWrite(targetptr, volptr, CoW_off, CoW_len))) {
ViceLog(25, ("StoreData : CopyOnWrite failed\n"));
volptr->partition->flags &= ~PART_DONTUPDATE;
+ FDH_CLOSE(origfdP);
return (errorCode);
}
volptr->partition->flags &= ~PART_DONTUPDATE;
if (fdP == NULL) {
ViceLog(25,
("StoreData : Reopen after CopyOnWrite failed\n"));
+ FDH_CLOSE(origfdP);
return ENOENT;
}
}
AdjustDiskUsage(volptr, adjustSize,
adjustSize - SpareComp(volptr)))) {
FDH_CLOSE(fdP);
+ if (origfdP) FDH_CLOSE(origfdP);
return (errorCode);
}
* need to update the target vnode.
*/
targetptr->changed_newTime = 1;
+ if (origfdP && (bytesTransfered < Length)) /* Need to "finish" CopyOnWrite still */
+ CopyOnWrite2(origfdP, fdP, bytesTransfered, Length - bytesTransfered);
+ if (origfdP) FDH_CLOSE(origfdP);
FDH_CLOSE(fdP);
/* set disk usage to be correct */
VAdjustDiskUsage(&errorCode, volptr,
nBlocks(NewLength)), 0);
return errorCode;
}
+ if (origfdP) FDH_CLOSE(origfdP);
FDH_CLOSE(fdP);
FT_GetTimeOfDay(&StopTime, 0);