]> Pileus Git - ~andy/linux/blobdiff - fs/logfs/segment.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu
[~andy/linux] / fs / logfs / segment.c
index 664cd0dd3576a786065982470e31d86b1c28e1c3..0ecd8f07c11e466b531d002fd8d2aa0900983098 100644 (file)
@@ -93,49 +93,57 @@ void __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len,
        } while (len);
 }
 
-/*
- * bdev_writeseg will write full pages.  Memset the tail to prevent data leaks.
- */
-static void pad_wbuf(struct logfs_area *area, int final)
+static void pad_partial_page(struct logfs_area *area)
 {
        struct super_block *sb = area->a_sb;
-       struct logfs_super *super = logfs_super(sb);
        struct page *page;
        u64 ofs = dev_ofs(sb, area->a_segno, area->a_used_bytes);
        pgoff_t index = ofs >> PAGE_SHIFT;
        long offset = ofs & (PAGE_SIZE-1);
        u32 len = PAGE_SIZE - offset;
 
-       if (len == PAGE_SIZE) {
-               /* The math in this function can surely use some love */
-               len = 0;
-       }
-       if (len) {
-               BUG_ON(area->a_used_bytes >= super->s_segsize);
-
-               page = get_mapping_page(area->a_sb, index, 0);
+       if (len % PAGE_SIZE) {
+               page = get_mapping_page(sb, index, 0);
                BUG_ON(!page); /* FIXME: reserve a pool */
                memset(page_address(page) + offset, 0xff, len);
                SetPagePrivate(page);
                page_cache_release(page);
        }
+}
 
-       if (!final)
-               return;
+static void pad_full_pages(struct logfs_area *area)
+{
+       struct super_block *sb = area->a_sb;
+       struct logfs_super *super = logfs_super(sb);
+       u64 ofs = dev_ofs(sb, area->a_segno, area->a_used_bytes);
+       u32 len = super->s_segsize - area->a_used_bytes;
+       pgoff_t index = PAGE_CACHE_ALIGN(ofs) >> PAGE_CACHE_SHIFT;
+       pgoff_t no_indizes = len >> PAGE_CACHE_SHIFT;
+       struct page *page;
 
-       area->a_used_bytes += len;
-       for ( ; area->a_used_bytes < super->s_segsize;
-                       area->a_used_bytes += PAGE_SIZE) {
-               /* Memset another page */
-               index++;
-               page = get_mapping_page(area->a_sb, index, 0);
+       while (no_indizes) {
+               page = get_mapping_page(sb, index, 0);
                BUG_ON(!page); /* FIXME: reserve a pool */
-               memset(page_address(page), 0xff, PAGE_SIZE);
+               SetPageUptodate(page);
+               memset(page_address(page), 0xff, PAGE_CACHE_SIZE);
                SetPagePrivate(page);
                page_cache_release(page);
+               index++;
+               no_indizes--;
        }
 }
 
+/*
+ * bdev_writeseg will write full pages.  Memset the tail to prevent data leaks.
+ * Also make sure we allocate (and memset) all pages for final writeout.
+ */
+static void pad_wbuf(struct logfs_area *area, int final)
+{
+       pad_partial_page(area);
+       if (final)
+               pad_full_pages(area);
+}
+
 /*
  * We have to be careful with the alias tree.  Since lookup is done by bix,
  * it needs to be normalized, so 14, 15, 16, etc. all match when dealing with
@@ -352,7 +360,8 @@ int logfs_segment_write(struct inode *inode, struct page *page,
        int ret;
        void *buf;
 
-       BUG_ON(logfs_super(sb)->s_flags & LOGFS_SB_FLAG_SHUTDOWN);
+       super->s_flags |= LOGFS_SB_FLAG_DIRTY;
+       BUG_ON(super->s_flags & LOGFS_SB_FLAG_SHUTDOWN);
        do_compress = logfs_inode(inode)->li_flags & LOGFS_IF_COMPRESSED;
        if (shadow->gc_level != 0) {
                /* temporarily disable compression for indirect blocks */
@@ -653,11 +662,13 @@ int logfs_segment_read(struct inode *inode, struct page *page,
 int logfs_segment_delete(struct inode *inode, struct logfs_shadow *shadow)
 {
        struct super_block *sb = inode->i_sb;
+       struct logfs_super *super = logfs_super(sb);
        struct logfs_object_header h;
        u16 len;
        int err;
 
-       BUG_ON(logfs_super(sb)->s_flags & LOGFS_SB_FLAG_SHUTDOWN);
+       super->s_flags |= LOGFS_SB_FLAG_DIRTY;
+       BUG_ON(super->s_flags & LOGFS_SB_FLAG_SHUTDOWN);
        BUG_ON(shadow->old_ofs & LOGFS_FULLY_POPULATED);
        if (!shadow->old_ofs)
                return 0;
@@ -680,7 +691,7 @@ int logfs_segment_delete(struct inode *inode, struct logfs_shadow *shadow)
        return 0;
 }
 
-static void freeseg(struct super_block *sb, u32 segno)
+void freeseg(struct super_block *sb, u32 segno)
 {
        struct logfs_super *super = logfs_super(sb);
        struct address_space *mapping = super->s_mapping_inode->i_mapping;