]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfs_readwrite.c
xnu-1228.12.14.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_readwrite.c
index 958ca6e3a09a081c0e80d9082cd95abaa9bd56c1..1e836052f75bf15a6e9d6abd8dbc3c34d27a6d40 100644 (file)
@@ -479,20 +479,51 @@ sizeok:
 
                hfs_unlock(cp);
                cnode_locked = 0;
+               
+               /*
+                * We need to tell UBC the fork's new size BEFORE calling
+                * cluster_write, in case any of the new pages need to be
+                * paged out before cluster_write completes (which does happen
+                * in embedded systems due to extreme memory pressure).
+                * Similarly, we need to tell hfs_vnop_pageout what the new EOF
+                * will be, so that it can pass that on to cluster_pageout, and
+                * allow those pageouts.
+                *
+                * We don't update ff_size yet since we don't want pageins to
+                * be able to see uninitialized data between the old and new
+                * EOF, until cluster_write has completed and initialized that
+                * part of the file.
+                *
+                * The vnode pager relies on the file size last given to UBC via
+                * ubc_setsize.  hfs_vnop_pageout relies on fp->ff_new_size or
+                * ff_size (whichever is larger).  NOTE: ff_new_size is always
+                * zero, unless we are extending the file via write.
+                */
+               if (filesize > fp->ff_size) {
+                       fp->ff_new_size = filesize;
+                       ubc_setsize(vp, filesize);
+               }
                retval = cluster_write(vp, uio, fp->ff_size, filesize, zero_off,
                                tail_off, lflag | IO_NOZERODIRTY);
                if (retval) {
+                       fp->ff_new_size = 0;    /* no longer extending; use ff_size */
+                       if (filesize > origFileSize) {
+                               ubc_setsize(vp, origFileSize);
+                       }
                        goto ioerr_exit;
                }
-               offset = uio_offset(uio);
-               if (offset > fp->ff_size) {
-                       fp->ff_size = offset;
-
-                       ubc_setsize(vp, fp->ff_size);       /* XXX check errors */
+               
+               if (filesize > origFileSize) {
+                       fp->ff_size = filesize;
+                       
                        /* Files that are changing size are not hot file candidates. */
-                       if (hfsmp->hfc_stage == HFC_RECORDING)
+                       if (hfsmp->hfc_stage == HFC_RECORDING) {
                                fp->ff_bytesread = 0;
+                       }
                }
+               fp->ff_new_size = 0;    /* ff_size now has the correct size */
+               
+               /* If we wrote some bytes, then touch the change and mod times */
                if (resid > uio_resid(uio)) {
                        cp->c_touch_chgtime = TRUE;
                        cp->c_touch_modtime = TRUE;
@@ -2947,9 +2978,17 @@ hfs_vnop_pageout(struct vnop_pageout_args *ap)
        cp = VTOC(vp);
        fp = VTOF(vp);
        
-       if (vnode_isswap(vp)) {
-               filesize = fp->ff_size;
-       } else {
+       /*
+        * Figure out where the file ends, for pageout purposes.  If
+        * ff_new_size > ff_size, then we're in the middle of extending the
+        * file via a write, so it is safe (and necessary) that we be able
+        * to pageout up to that point.
+        */
+       filesize = fp->ff_size;
+       if (fp->ff_new_size > filesize)
+               filesize = fp->ff_new_size;
+       
+       if (!vnode_isswap(vp)) {
                off_t end_of_range;
                int tooklock = 0;
 
@@ -2966,7 +3005,6 @@ hfs_vnop_pageout(struct vnop_pageout_args *ap)
                    tooklock = 1;
                }
        
-               filesize = fp->ff_size;
                end_of_range = ap->a_f_offset + ap->a_size - 1;
        
                if (end_of_range >= filesize) {
@@ -3219,7 +3257,7 @@ hfs_relocate(struct  vnode *vp, u_int32_t  blockHint, kauth_cred_t cred,
                        retval = ENOSPC;
                        goto restore;
                } else if ((eflags & kEFMetadataMask) &&
-                          ((((u_int64_t)sector_b * hfsmp->hfs_phys_block_size) / blksize) >
+                          ((((u_int64_t)sector_b * hfsmp->hfs_logical_block_size) / blksize) >
                              hfsmp->hfs_metazone_end)) {
                        const char * filestr;
                        char emptystr = '\0';