]> err.no Git - linux-2.6/blobdiff - fs/ntfs/aops.c
[PATCH] x86: more asm cleanups
[linux-2.6] / fs / ntfs / aops.c
index 92215228eeaba68ef83aa8b8355b410c496c30be..78adad7a988d981a22f61b739cc082071ddc8513 100644 (file)
@@ -2,7 +2,7 @@
  * aops.c - NTFS kernel address space operations and page cache handling.
  *         Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2004 Anton Altaparmakov
+ * Copyright (c) 2001-2005 Anton Altaparmakov
  * Copyright (c) 2002 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -135,7 +135,7 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
                                        i * rec_size), rec_size);
                flush_dcache_page(page);
                kunmap_atomic(addr, KM_BIO_SRC_IRQ);
-               if (likely(!PageError(page) && page_uptodate))
+               if (likely(page_uptodate && !PageError(page)))
                        SetPageUptodate(page);
        }
        unlock_page(page);
@@ -264,7 +264,8 @@ lock_retry_remap:
                                        goto lock_retry_remap;
                                rl = NULL;
                                lcn = err;
-                       }
+                       } else if (!rl)
+                               up_read(&ni->runlist.lock);
                        /* Hard error, zero out region. */
                        bh->b_blocknr = -1;
                        SetPageError(page);
@@ -347,14 +348,15 @@ handle_zblock:
  */
 static int ntfs_readpage(struct file *file, struct page *page)
 {
-       loff_t i_size;
        ntfs_inode *ni, *base_ni;
        u8 *kaddr;
        ntfs_attr_search_ctx *ctx;
        MFT_RECORD *mrec;
+       unsigned long flags;
        u32 attr_len;
        int err = 0;
 
+retry_readpage:
        BUG_ON(!PageLocked(page));
        /*
         * This can potentially happen because we clear PageUptodate() during
@@ -389,9 +391,9 @@ static int ntfs_readpage(struct file *file, struct page *page)
         * Attribute is resident, implying it is not compressed or encrypted.
         * This also means the attribute is smaller than an mft record and
         * hence smaller than a page, so can simply zero out any pages with
-        * index above 0.  We can also do this if the file size is 0.
+        * index above 0.
         */
-       if (unlikely(page->index > 0 || !i_size_read(VFS_I(ni)))) {
+       if (unlikely(page->index > 0)) {
                kaddr = kmap_atomic(page, KM_USER0);
                memset(kaddr, 0, PAGE_CACHE_SIZE);
                flush_dcache_page(page);
@@ -408,6 +410,14 @@ static int ntfs_readpage(struct file *file, struct page *page)
                err = PTR_ERR(mrec);
                goto err_out;
        }
+       /*
+        * If a parallel write made the attribute non-resident, drop the mft
+        * record and retry the readpage.
+        */
+       if (unlikely(NInoNonResident(ni))) {
+               unmap_mft_record(base_ni);
+               goto retry_readpage;
+       }
        ctx = ntfs_attr_get_search_ctx(base_ni, mrec);
        if (unlikely(!ctx)) {
                err = -ENOMEM;
@@ -418,9 +428,10 @@ static int ntfs_readpage(struct file *file, struct page *page)
        if (unlikely(err))
                goto put_unm_err_out;
        attr_len = le32_to_cpu(ctx->attr->data.resident.value_length);
-       i_size = i_size_read(VFS_I(ni));
-       if (unlikely(attr_len > i_size))
-               attr_len = i_size;
+       read_lock_irqsave(&ni->size_lock, flags);
+       if (unlikely(attr_len > ni->initialized_size))
+               attr_len = ni->initialized_size;
+       read_unlock_irqrestore(&ni->size_lock, flags);
        kaddr = kmap_atomic(page, KM_USER0);
        /* Copy the data to the page. */
        memcpy(kaddr, (u8*)ctx->attr +
@@ -680,7 +691,8 @@ lock_retry_remap:
                                goto lock_retry_remap;
                        rl = NULL;
                        lcn = err;
-               }
+               } else if (!rl)
+                       up_read(&ni->runlist.lock);
                /* Failed to map the buffer, even after retrying. */
                bh->b_blocknr = -1;
                ntfs_error(vol->sb, "Failed to write to inode 0x%lx, "
@@ -815,17 +827,15 @@ static int ntfs_write_mst_block(struct page *page,
        ntfs_inode *ni = NTFS_I(vi);
        ntfs_volume *vol = ni->vol;
        u8 *kaddr;
-       unsigned char bh_size_bits = vi->i_blkbits;
-       unsigned int bh_size = 1 << bh_size_bits;
        unsigned int rec_size = ni->itype.index.block_size;
        ntfs_inode *locked_nis[PAGE_CACHE_SIZE / rec_size];
        struct buffer_head *bh, *head, *tbh, *rec_start_bh;
-       int max_bhs = PAGE_CACHE_SIZE / bh_size;
-       struct buffer_head *bhs[max_bhs];
+       struct buffer_head *bhs[MAX_BUF_PER_PAGE];
        runlist_element *rl;
-       int i, nr_locked_nis, nr_recs, nr_bhs, bhs_per_rec, err, err2;
-       unsigned rec_size_bits;
+       int i, nr_locked_nis, nr_recs, nr_bhs, max_bhs, bhs_per_rec, err, err2;
+       unsigned bh_size, rec_size_bits;
        BOOL sync, is_mft, page_is_dirty, rec_is_dirty;
+       unsigned char bh_size_bits;
 
        ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index "
                        "0x%lx.", vi->i_ino, ni->type, page->index);
@@ -840,7 +850,11 @@ static int ntfs_write_mst_block(struct page *page,
         */
        BUG_ON(!(is_mft || S_ISDIR(vi->i_mode) ||
                        (NInoAttr(ni) && ni->type == AT_INDEX_ALLOCATION)));
+       bh_size_bits = vi->i_blkbits;
+       bh_size = 1 << bh_size_bits;
+       max_bhs = PAGE_CACHE_SIZE / bh_size;
        BUG_ON(!max_bhs);
+       BUG_ON(max_bhs > MAX_BUF_PER_PAGE);
 
        /* Were we called for sync purposes? */
        sync = (wbc->sync_mode == WB_SYNC_ALL);
@@ -910,6 +924,7 @@ static int ntfs_write_mst_block(struct page *page,
                        LCN lcn;
                        unsigned int vcn_ofs;
 
+                       bh->b_bdev = vol->sb->s_bdev;
                        /* Obtain the vcn and offset of the current block. */
                        vcn = (VCN)block << bh_size_bits;
                        vcn_ofs = vcn & vol->cluster_size_mask;
@@ -953,8 +968,11 @@ lock_retry_remap:
                                        if (err2 == -ENOMEM)
                                                page_is_dirty = TRUE;
                                        lcn = err2;
-                               } else
+                               } else {
                                        err2 = -EIO;
+                                       if (!rl)
+                                               up_read(&ni->runlist.lock);
+                               }
                                /* Hard error.  Abort writing this record. */
                                if (!err || err == -ENOMEM)
                                        err = err2;
@@ -964,7 +982,8 @@ lock_retry_remap:
                                                "attribute type 0x%x) because "
                                                "its location on disk could "
                                                "not be determined (error "
-                                               "code %lli).", (s64)block <<
+                                               "code %lli).",
+                                               (long long)block <<
                                                bh_size_bits >>
                                                vol->mft_record_size_bits,
                                                ni->mft_no, ni->type,
@@ -1246,21 +1265,8 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
        u32 attr_len;
        int err;
 
+retry_writepage:
        BUG_ON(!PageLocked(page));
-       /*
-        * If a previous ntfs_truncate() failed, repeat it and abort if it
-        * fails again.
-        */
-       if (unlikely(NInoTruncateFailed(ni))) {
-               down_write(&vi->i_alloc_sem);
-               err = ntfs_truncate(vi);
-               up_write(&vi->i_alloc_sem);
-               if (err || NInoTruncateFailed(ni)) {
-                       if (!err)
-                               err = -EIO;
-                       goto err_out;
-               }
-       }
        i_size = i_size_read(vi);
        /* Is the page fully outside i_size? (truncate in progress) */
        if (unlikely(page->index >= (i_size + PAGE_CACHE_SIZE - 1) >>
@@ -1350,6 +1356,14 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
                ctx = NULL;
                goto err_out;
        }
+       /*
+        * If a parallel write made the attribute non-resident, drop the mft
+        * record and retry the writepage.
+        */
+       if (unlikely(NInoNonResident(ni))) {
+               unmap_mft_record(base_ni);
+               goto retry_writepage;
+       }
        ctx = ntfs_attr_get_search_ctx(base_ni, m);
        if (unlikely(!ctx)) {
                err = -ENOMEM;
@@ -1392,14 +1406,11 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
 
        attr_len = le32_to_cpu(ctx->attr->data.resident.value_length);
        i_size = i_size_read(vi);
-       kaddr = kmap_atomic(page, KM_USER0);
        if (unlikely(attr_len > i_size)) {
-               /* Zero out of bounds area in the mft record. */
-               memset((u8*)ctx->attr + le16_to_cpu(
-                               ctx->attr->data.resident.value_offset) +
-                               i_size, 0, attr_len - i_size);
                attr_len = i_size;
+               ctx->attr->data.resident.value_length = cpu_to_le32(attr_len);
        }
+       kaddr = kmap_atomic(page, KM_USER0);
        /* Copy the data from the page to the mft record. */
        memcpy((u8*)ctx->attr +
                        le16_to_cpu(ctx->attr->data.resident.value_offset),
@@ -1493,13 +1504,12 @@ static int ntfs_prepare_nonresident_write(struct page *page,
 
        read_lock_irqsave(&ni->size_lock, flags);
        /*
-        * The first out of bounds block for the allocated size. No need to
+        * The first out of bounds block for the allocated size.  No need to
         * round up as allocated_size is in multiples of cluster size and the
         * minimum cluster size is 512 bytes, which is equal to the smallest
         * blocksize.
         */
        ablock = ni->allocated_size >> blocksize_bits;
-
        i_size = i_size_read(vi);
        initialized_size = ni->initialized_size;
        read_unlock_irqrestore(&ni->size_lock, flags);
@@ -1656,6 +1666,8 @@ lock_retry_remap:
                                                        "not supported yet. "
                                                        "Sorry.");
                                        err = -EOPNOTSUPP;
+                                       if (!rl)
+                                               up_read(&ni->runlist.lock);
                                        goto err_out;
                                } else if (!is_retry &&
                                                lcn == LCN_RL_NOT_MAPPED) {
@@ -1670,7 +1682,8 @@ lock_retry_remap:
                                                goto lock_retry_remap;
                                        rl = NULL;
                                        lcn = err;
-                               }
+                               } else if (!rl)
+                                       up_read(&ni->runlist.lock);
                                /*
                                 * Failed to map the buffer, even after
                                 * retrying.
@@ -1831,7 +1844,7 @@ static int ntfs_prepare_write(struct file *file, struct page *page,
                unsigned from, unsigned to)
 {
        s64 new_size;
-       unsigned long flags;
+       loff_t i_size;
        struct inode *vi = page->mapping->host;
        ntfs_inode *base_ni = NULL, *ni = NTFS_I(vi);
        ntfs_volume *vol = ni->vol;
@@ -1934,13 +1947,11 @@ static int ntfs_prepare_write(struct file *file, struct page *page,
        /* The total length of the attribute value. */
        attr_len = le32_to_cpu(a->data.resident.value_length);
        /* Fix an eventual previous failure of ntfs_commit_write(). */
-       read_lock_irqsave(&ni->size_lock, flags);
-       if (unlikely(ni->initialized_size < attr_len)) {
-               attr_len = ni->initialized_size;
+       i_size = i_size_read(vi);
+       if (unlikely(attr_len > i_size)) {
+               attr_len = i_size;
                a->data.resident.value_length = cpu_to_le32(attr_len);
-               BUG_ON(attr_len < i_size_read(vi));
        }
-       read_unlock_irqrestore(&ni->size_lock, flags);
        /* If we do not need to resize the attribute allocation we are done. */
        if (new_size <= attr_len)
                goto done_unm;