]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge tag 'for-f2fs-3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 13 Nov 2013 06:24:40 +0000 (15:24 +0900)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 13 Nov 2013 06:24:40 +0000 (15:24 +0900)
Pull f2fs updates from Jaegeuk Kim:
 "This patch-set includes the following major enhancement patches.
   - add a sysfs to control reclaiming free segments
   - enhance the f2fs global lock procedures
   - enhance the victim selection flow
   - wait for selected node blocks during fsync
   - add some tracepoints
   - add a config to remove abundant BUG_ONs

  The other bug fixes are as follows.
   - fix deadlock on acl operations
   - fix some bugs with respect to orphan inodes

  And, there are a bunch of cleanups"

* tag 'for-f2fs-3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (42 commits)
  f2fs: issue more large discard command
  f2fs: fix memory leak after kobject init failed in fill_super
  f2fs: cleanup waiting routine for writeback pages in cp
  f2fs: avoid to use a NULL point in destroy_segment_manager
  f2fs: remove unnecessary TestClearPageError when wait pages writeback
  f2fs: update f2fs document
  f2fs: avoid to wait all the node blocks during fsync
  f2fs: check all ones or zeros bitmap with bitops for better mount performance
  f2fs: change the method of calculating the number summary blocks
  f2fs: fix calculating incorrect free size when update xattr in __f2fs_setxattr
  f2fs: add an option to avoid unnecessary BUG_ONs
  f2fs: introduce CONFIG_F2FS_CHECK_FS for BUG_ON control
  f2fs: fix a deadlock during init_acl procedure
  f2fs: clean up acl flow for better readability
  f2fs: remove unnecessary segment bitmap updates
  f2fs: add tracepoint for vm_page_mkwrite
  f2fs: add tracepoint for set_page_dirty
  f2fs: remove redundant set_page_dirty from write_compacted_summaries
  f2fs: add reclaiming control by sysfs
  f2fs: introduce f2fs_balance_fs_bg for some background jobs
  ...

19 files changed:
Documentation/filesystems/f2fs.txt
fs/f2fs/Kconfig
fs/f2fs/acl.c
fs/f2fs/acl.h
fs/f2fs/checkpoint.c
fs/f2fs/data.c
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/gc.c
fs/f2fs/inode.c
fs/f2fs/namei.c
fs/f2fs/node.c
fs/f2fs/recovery.c
fs/f2fs/segment.c
fs/f2fs/segment.h
fs/f2fs/super.c
fs/f2fs/xattr.c
include/trace/events/f2fs.h

index 3cd27bed6349ebeb051419b1de18a63e84288649..a3fe811bbdbc59bd6a393042fb9151281edfb850 100644 (file)
@@ -119,6 +119,7 @@ active_logs=%u         Support configuring the number of active logs. In the
                        Default number is 6.
 disable_ext_identify   Disable the extension list configured by mkfs, so f2fs
                        does not aware of cold files such as media files.
+inline_xattr           Enable the inline xattrs feature.
 
 ================================================================================
 DEBUGFS ENTRIES
@@ -164,6 +165,12 @@ Files in /sys/fs/f2fs/<devname>
                               gc_idle = 1 will select the Cost Benefit approach
                               & setting gc_idle = 2 will select the greedy aproach.
 
+ reclaim_segments             This parameter controls the number of prefree
+                              segments to be reclaimed. If the number of prefree
+                             segments is larger than this number, f2fs tries to
+                             conduct checkpoint to reclaim the prefree segments
+                             to free segments. By default, 100 segments, 200MB.
+
 ================================================================================
 USAGE
 ================================================================================
index e06e0995e00fdf619d1bbd7f48ebe0e9df25ebc0..214fe1054fceef32e74589e06a8d89203d9cc601 100644 (file)
@@ -63,3 +63,11 @@ config F2FS_FS_SECURITY
          the extended attribute support in advance.
 
          If you are not using a security module, say N.
+
+config F2FS_CHECK_FS
+       bool "F2FS consistency checking feature"
+       depends on F2FS_FS
+       help
+         Enables BUG_ONs which check the file system consistency in runtime.
+
+         If you want to improve the performance, say N.
index b7826ec1b47062fdb30891192b42a8dbf5e20788..d0fc287efeff4511fa7f4e84369cf77f0ae31538 100644 (file)
@@ -205,7 +205,8 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
        return acl;
 }
 
-static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
+static int f2fs_set_acl(struct inode *inode, int type,
+                       struct posix_acl *acl, struct page *ipage)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct f2fs_inode_info *fi = F2FS_I(inode);
@@ -250,7 +251,7 @@ static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
                }
        }
 
-       error = f2fs_setxattr(inode, name_index, "", value, size, NULL);
+       error = f2fs_setxattr(inode, name_index, "", value, size, ipage);
 
        kfree(value);
        if (!error)
@@ -260,10 +261,10 @@ static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
        return error;
 }
 
-int f2fs_init_acl(struct inode *inode, struct inode *dir)
+int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage)
 {
-       struct posix_acl *acl = NULL;
        struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
+       struct posix_acl *acl = NULL;
        int error = 0;
 
        if (!S_ISLNK(inode->i_mode)) {
@@ -276,19 +277,19 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir)
                        inode->i_mode &= ~current_umask();
        }
 
-       if (test_opt(sbi, POSIX_ACL) && acl) {
+       if (!test_opt(sbi, POSIX_ACL) || !acl)
+               goto cleanup;
 
-               if (S_ISDIR(inode->i_mode)) {
-                       error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl);
-                       if (error)
-                               goto cleanup;
-               }
-               error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
-               if (error < 0)
-                       return error;
-               if (error > 0)
-                       error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl);
+       if (S_ISDIR(inode->i_mode)) {
+               error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl, ipage);
+               if (error)
+                       goto cleanup;
        }
+       error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
+       if (error < 0)
+               return error;
+       if (error > 0)
+               error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, ipage);
 cleanup:
        posix_acl_release(acl);
        return error;
@@ -313,7 +314,8 @@ int f2fs_acl_chmod(struct inode *inode)
        error = posix_acl_chmod(&acl, GFP_KERNEL, mode);
        if (error)
                return error;
-       error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl);
+
+       error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, NULL);
        posix_acl_release(acl);
        return error;
 }
@@ -388,7 +390,7 @@ static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name,
                acl = NULL;
        }
 
-       error = f2fs_set_acl(inode, type, acl);
+       error = f2fs_set_acl(inode, type, acl, NULL);
 
 release_and_out:
        posix_acl_release(acl);
index 80f430674417a696925f90fdf622dac8710e0909..49633131e038db76e14d21803538f1701a93d873 100644 (file)
@@ -36,9 +36,9 @@ struct f2fs_acl_header {
 
 #ifdef CONFIG_F2FS_FS_POSIX_ACL
 
-extern struct posix_acl *f2fs_get_acl(struct inode *inode, int type);
-extern int f2fs_acl_chmod(struct inode *inode);
-extern int f2fs_init_acl(struct inode *inode, struct inode *dir);
+extern struct posix_acl *f2fs_get_acl(struct inode *, int);
+extern int f2fs_acl_chmod(struct inode *);
+extern int f2fs_init_acl(struct inode *, struct inode *, struct page *);
 #else
 #define f2fs_check_acl NULL
 #define f2fs_get_acl   NULL
@@ -49,7 +49,8 @@ static inline int f2fs_acl_chmod(struct inode *inode)
        return 0;
 }
 
-static inline int f2fs_init_acl(struct inode *inode, struct inode *dir)
+static inline int f2fs_init_acl(struct inode *inode, struct inode *dir,
+                                                       struct page *page)
 {
        return 0;
 }
index bb312201ca950114782f6a811725102da3baa718..5716e5eb4e8ec7ab2c63c69079259e2c5d772918 100644 (file)
@@ -81,7 +81,7 @@ static int f2fs_write_meta_page(struct page *page,
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
 
        /* Should not write any meta pages, if any IO error was occurred */
-       if (wbc->for_reclaim ||
+       if (wbc->for_reclaim || sbi->por_doing ||
                        is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ERROR_FLAG)) {
                dec_page_count(sbi, F2FS_DIRTY_META);
                wbc->pages_skipped++;
@@ -142,8 +142,8 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
                for (i = 0; i < nr_pages; i++) {
                        struct page *page = pvec.pages[i];
                        lock_page(page);
-                       BUG_ON(page->mapping != mapping);
-                       BUG_ON(!PageDirty(page));
+                       f2fs_bug_on(page->mapping != mapping);
+                       f2fs_bug_on(!PageDirty(page));
                        clear_page_dirty_for_io(page);
                        if (f2fs_write_meta_page(page, &wbc)) {
                                unlock_page(page);
@@ -167,6 +167,8 @@ static int f2fs_set_meta_page_dirty(struct page *page)
        struct address_space *mapping = page->mapping;
        struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
 
+       trace_f2fs_set_page_dirty(page, META);
+
        SetPageUptodate(page);
        if (!PageDirty(page)) {
                __set_page_dirty_nobuffers(page);
@@ -206,6 +208,7 @@ int acquire_orphan_inode(struct f2fs_sb_info *sbi)
 void release_orphan_inode(struct f2fs_sb_info *sbi)
 {
        mutex_lock(&sbi->orphan_inode_mutex);
+       f2fs_bug_on(sbi->n_orphans == 0);
        sbi->n_orphans--;
        mutex_unlock(&sbi->orphan_inode_mutex);
 }
@@ -225,12 +228,8 @@ void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
                        break;
                orphan = NULL;
        }
-retry:
-       new = kmem_cache_alloc(orphan_entry_slab, GFP_ATOMIC);
-       if (!new) {
-               cond_resched();
-               goto retry;
-       }
+
+       new = f2fs_kmem_cache_alloc(orphan_entry_slab, GFP_ATOMIC);
        new->ino = ino;
 
        /* add new_oentry into list which is sorted by inode number */
@@ -253,6 +252,7 @@ void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
                if (orphan->ino == ino) {
                        list_del(&orphan->list);
                        kmem_cache_free(orphan_entry_slab, orphan);
+                       f2fs_bug_on(sbi->n_orphans == 0);
                        sbi->n_orphans--;
                        break;
                }
@@ -263,7 +263,7 @@ void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
 static void recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
 {
        struct inode *inode = f2fs_iget(sbi->sb, ino);
-       BUG_ON(IS_ERR(inode));
+       f2fs_bug_on(IS_ERR(inode));
        clear_nlink(inode);
 
        /* truncate all the data during iput */
@@ -277,7 +277,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
        if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG))
                return 0;
 
-       sbi->por_doing = 1;
+       sbi->por_doing = true;
        start_blk = __start_cp_addr(sbi) + 1;
        orphan_blkaddr = __start_sum_addr(sbi) - 1;
 
@@ -294,7 +294,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
        }
        /* clear Orphan Flag */
        clear_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG);
-       sbi->por_doing = 0;
+       sbi->por_doing = false;
        return 0;
 }
 
@@ -469,9 +469,7 @@ static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new)
                        return -EEXIST;
        }
        list_add_tail(&new->list, head);
-#ifdef CONFIG_F2FS_STAT_FS
-       sbi->n_dirty_dirs++;
-#endif
+       stat_inc_dirty_dir(sbi);
        return 0;
 }
 
@@ -482,12 +480,8 @@ void set_dirty_dir_page(struct inode *inode, struct page *page)
 
        if (!S_ISDIR(inode->i_mode))
                return;
-retry:
-       new = kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
-       if (!new) {
-               cond_resched();
-               goto retry;
-       }
+
+       new = f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
        new->inode = inode;
        INIT_LIST_HEAD(&new->list);
 
@@ -504,13 +498,9 @@ retry:
 void add_dirty_dir_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-       struct dir_inode_entry *new;
-retry:
-       new = kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
-       if (!new) {
-               cond_resched();
-               goto retry;
-       }
+       struct dir_inode_entry *new =
+                       f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
+
        new->inode = inode;
        INIT_LIST_HEAD(&new->list);
 
@@ -541,9 +531,7 @@ void remove_dirty_dir_inode(struct inode *inode)
                if (entry->inode == inode) {
                        list_del(&entry->list);
                        kmem_cache_free(inode_entry_slab, entry);
-#ifdef CONFIG_F2FS_STAT_FS
-                       sbi->n_dirty_dirs--;
-#endif
+                       stat_dec_dirty_dir(sbi);
                        break;
                }
        }
@@ -617,11 +605,10 @@ static void block_operations(struct f2fs_sb_info *sbi)
        blk_start_plug(&plug);
 
 retry_flush_dents:
-       mutex_lock_all(sbi);
-
+       f2fs_lock_all(sbi);
        /* write all the dirty dentry pages */
        if (get_pages(sbi, F2FS_DIRTY_DENTS)) {
-               mutex_unlock_all(sbi);
+               f2fs_unlock_all(sbi);
                sync_dirty_dir_inodes(sbi);
                goto retry_flush_dents;
        }
@@ -644,7 +631,22 @@ retry_flush_nodes:
 static void unblock_operations(struct f2fs_sb_info *sbi)
 {
        mutex_unlock(&sbi->node_write);
-       mutex_unlock_all(sbi);
+       f2fs_unlock_all(sbi);
+}
+
+static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)
+{
+       DEFINE_WAIT(wait);
+
+       for (;;) {
+               prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE);
+
+               if (!get_pages(sbi, F2FS_WRITEBACK))
+                       break;
+
+               io_schedule();
+       }
+       finish_wait(&sbi->cp_wait, &wait);
 }
 
 static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
@@ -756,8 +758,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
        f2fs_put_page(cp_page, 1);
 
        /* wait for previous submitted node/meta pages writeback */
-       while (get_pages(sbi, F2FS_WRITEBACK))
-               congestion_wait(BLK_RW_ASYNC, HZ / 50);
+       wait_on_all_pages_writeback(sbi);
 
        filemap_fdatawait_range(sbi->node_inode->i_mapping, 0, LONG_MAX);
        filemap_fdatawait_range(sbi->meta_inode->i_mapping, 0, LONG_MAX);
index 941f9b9ca3a5b41fa9208f1d929b20212e08dfcb..aa3438c571fa9a2dfaf3e1ab61bd4328f580b0d6 100644 (file)
@@ -68,9 +68,6 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
                                        struct buffer_head *bh_result)
 {
        struct f2fs_inode_info *fi = F2FS_I(inode);
-#ifdef CONFIG_F2FS_STAT_FS
-       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-#endif
        pgoff_t start_fofs, end_fofs;
        block_t start_blkaddr;
 
@@ -80,9 +77,8 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
                return 0;
        }
 
-#ifdef CONFIG_F2FS_STAT_FS
-       sbi->total_hit_ext++;
-#endif
+       stat_inc_total_hit(inode->i_sb);
+
        start_fofs = fi->ext.fofs;
        end_fofs = fi->ext.fofs + fi->ext.len - 1;
        start_blkaddr = fi->ext.blk_addr;
@@ -100,9 +96,7 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
                else
                        bh_result->b_size = UINT_MAX;
 
-#ifdef CONFIG_F2FS_STAT_FS
-               sbi->read_hit_ext++;
-#endif
+               stat_inc_read_hit(inode->i_sb);
                read_unlock(&fi->ext.ext_lock);
                return 1;
        }
@@ -116,7 +110,7 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn)
        pgoff_t fofs, start_fofs, end_fofs;
        block_t start_blkaddr, end_blkaddr;
 
-       BUG_ON(blk_addr == NEW_ADDR);
+       f2fs_bug_on(blk_addr == NEW_ADDR);
        fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) +
                                                        dn->ofs_in_node;
 
@@ -442,7 +436,7 @@ static int get_data_block_ro(struct inode *inode, sector_t iblock,
        }
 
        /* It does not support data allocation */
-       BUG_ON(create);
+       f2fs_bug_on(create);
 
        if (dn.data_blkaddr != NEW_ADDR && dn.data_blkaddr != NULL_ADDR) {
                int i;
@@ -560,9 +554,9 @@ write:
                inode_dec_dirty_dents(inode);
                err = do_write_data_page(page);
        } else {
-               int ilock = mutex_lock_op(sbi);
+               f2fs_lock_op(sbi);
                err = do_write_data_page(page);
-               mutex_unlock_op(sbi, ilock);
+               f2fs_unlock_op(sbi);
                need_balance_fs = true;
        }
        if (err == -ENOENT)
@@ -641,7 +635,6 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
        pgoff_t index = ((unsigned long long) pos) >> PAGE_CACHE_SHIFT;
        struct dnode_of_data dn;
        int err = 0;
-       int ilock;
 
        f2fs_balance_fs(sbi);
 repeat:
@@ -650,7 +643,7 @@ repeat:
                return -ENOMEM;
        *pagep = page;
 
-       ilock = mutex_lock_op(sbi);
+       f2fs_lock_op(sbi);
 
        set_new_dnode(&dn, inode, NULL, NULL, 0);
        err = get_dnode_of_data(&dn, index, ALLOC_NODE);
@@ -664,7 +657,7 @@ repeat:
        if (err)
                goto err;
 
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
 
        if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
                return 0;
@@ -700,7 +693,7 @@ out:
        return 0;
 
 err:
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
        f2fs_put_page(page, 1);
        return err;
 }
@@ -763,6 +756,8 @@ static int f2fs_set_data_page_dirty(struct page *page)
        struct address_space *mapping = page->mapping;
        struct inode *inode = mapping->host;
 
+       trace_f2fs_set_page_dirty(page, DATA);
+
        SetPageUptodate(page);
        if (!PageDirty(page)) {
                __set_page_dirty_nobuffers(page);
index 384c6daf9a89a668b25bf2a22a193ac9f23f6a8a..594fc1bb64ef44f1ea734ec7222b710a670b37fe 100644 (file)
@@ -139,7 +139,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
        bool room = false;
        int max_slots = 0;
 
-       BUG_ON(level > MAX_DIR_HASH_DEPTH);
+       f2fs_bug_on(level > MAX_DIR_HASH_DEPTH);
 
        nbucket = dir_buckets(level);
        nblock = bucket_blocks(level);
@@ -346,7 +346,7 @@ static struct page *init_inode_metadata(struct inode *inode,
                                goto error;
                }
 
-               err = f2fs_init_acl(inode, dir);
+               err = f2fs_init_acl(inode, dir, page);
                if (err)
                        goto error;
 
index 608f0df5b9190f8e8b301dd61e085fa70c66c5db..89dc7508faf2edf173441a9e25cad8a9ff4856aa 100644 (file)
 #include <linux/crc32.h>
 #include <linux/magic.h>
 #include <linux/kobject.h>
+#include <linux/sched.h>
+
+#ifdef CONFIG_F2FS_CHECK_FS
+#define f2fs_bug_on(condition) BUG_ON(condition)
+#else
+#define f2fs_bug_on(condition)
+#endif
 
 /*
  * For mount options
@@ -298,6 +305,9 @@ struct f2fs_sm_info {
        unsigned int main_segments;     /* # of segments in main area */
        unsigned int reserved_segments; /* # of reserved segments */
        unsigned int ovp_segments;      /* # of overprovision segments */
+
+       /* a threshold to reclaim prefree segments */
+       unsigned int rec_prefree_segments;
 };
 
 /*
@@ -317,14 +327,6 @@ enum count_type {
        NR_COUNT_TYPE,
 };
 
-/*
- * Uses as sbi->fs_lock[NR_GLOBAL_LOCKS].
- * The checkpoint procedure blocks all the locks in this fs_lock array.
- * Some FS operations grab free locks, and if there is no free lock,
- * then wait to grab a lock in a round-robin manner.
- */
-#define NR_GLOBAL_LOCKS        8
-
 /*
  * The below are the page types of bios used in submti_bio().
  * The available types are:
@@ -365,12 +367,12 @@ struct f2fs_sb_info {
        struct f2fs_checkpoint *ckpt;           /* raw checkpoint pointer */
        struct inode *meta_inode;               /* cache meta blocks */
        struct mutex cp_mutex;                  /* checkpoint procedure lock */
-       struct mutex fs_lock[NR_GLOBAL_LOCKS];  /* blocking FS operations */
+       struct rw_semaphore cp_rwsem;           /* blocking FS operations */
        struct mutex node_write;                /* locking node writes */
        struct mutex writepages;                /* mutex for writepages() */
-       unsigned char next_lock_num;            /* round-robin global locks */
-       int por_doing;                          /* recovery is doing or not */
-       int on_build_free_nids;                 /* build_free_nids is doing */
+       bool por_doing;                         /* recovery is doing or not */
+       bool on_build_free_nids;                /* build_free_nids is doing */
+       wait_queue_head_t cp_wait;
 
        /* for orphan inode management */
        struct list_head orphan_inode_list;     /* orphan inode list */
@@ -520,48 +522,24 @@ static inline void clear_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
        cp->ckpt_flags = cpu_to_le32(ckpt_flags);
 }
 
-static inline void mutex_lock_all(struct f2fs_sb_info *sbi)
+static inline void f2fs_lock_op(struct f2fs_sb_info *sbi)
 {
-       int i;
-
-       for (i = 0; i < NR_GLOBAL_LOCKS; i++) {
-               /*
-                * This is the only time we take multiple fs_lock[]
-                * instances; the order is immaterial since we
-                * always hold cp_mutex, which serializes multiple
-                * such operations.
-                */
-               mutex_lock_nest_lock(&sbi->fs_lock[i], &sbi->cp_mutex);
-       }
+       down_read(&sbi->cp_rwsem);
 }
 
-static inline void mutex_unlock_all(struct f2fs_sb_info *sbi)
+static inline void f2fs_unlock_op(struct f2fs_sb_info *sbi)
 {
-       int i = 0;
-       for (; i < NR_GLOBAL_LOCKS; i++)
-               mutex_unlock(&sbi->fs_lock[i]);
+       up_read(&sbi->cp_rwsem);
 }
 
-static inline int mutex_lock_op(struct f2fs_sb_info *sbi)
+static inline void f2fs_lock_all(struct f2fs_sb_info *sbi)
 {
-       unsigned char next_lock = sbi->next_lock_num % NR_GLOBAL_LOCKS;
-       int i = 0;
-
-       for (; i < NR_GLOBAL_LOCKS; i++)
-               if (mutex_trylock(&sbi->fs_lock[i]))
-                       return i;
-
-       mutex_lock(&sbi->fs_lock[next_lock]);
-       sbi->next_lock_num++;
-       return next_lock;
+       down_write_nest_lock(&sbi->cp_rwsem, &sbi->cp_mutex);
 }
 
-static inline void mutex_unlock_op(struct f2fs_sb_info *sbi, int ilock)
+static inline void f2fs_unlock_all(struct f2fs_sb_info *sbi)
 {
-       if (ilock < 0)
-               return;
-       BUG_ON(ilock >= NR_GLOBAL_LOCKS);
-       mutex_unlock(&sbi->fs_lock[ilock]);
+       up_write(&sbi->cp_rwsem);
 }
 
 /*
@@ -612,8 +590,8 @@ static inline int dec_valid_block_count(struct f2fs_sb_info *sbi,
                                                blkcnt_t count)
 {
        spin_lock(&sbi->stat_lock);
-       BUG_ON(sbi->total_valid_block_count < (block_t) count);
-       BUG_ON(inode->i_blocks < count);
+       f2fs_bug_on(sbi->total_valid_block_count < (block_t) count);
+       f2fs_bug_on(inode->i_blocks < count);
        inode->i_blocks -= count;
        sbi->total_valid_block_count -= (block_t)count;
        spin_unlock(&sbi->stat_lock);
@@ -745,9 +723,9 @@ static inline void dec_valid_node_count(struct f2fs_sb_info *sbi,
 {
        spin_lock(&sbi->stat_lock);
 
-       BUG_ON(sbi->total_valid_block_count < count);
-       BUG_ON(sbi->total_valid_node_count < count);
-       BUG_ON(inode->i_blocks < count);
+       f2fs_bug_on(sbi->total_valid_block_count < count);
+       f2fs_bug_on(sbi->total_valid_node_count < count);
+       f2fs_bug_on(inode->i_blocks < count);
 
        inode->i_blocks -= count;
        sbi->total_valid_node_count -= count;
@@ -768,7 +746,7 @@ static inline unsigned int valid_node_count(struct f2fs_sb_info *sbi)
 static inline void inc_valid_inode_count(struct f2fs_sb_info *sbi)
 {
        spin_lock(&sbi->stat_lock);
-       BUG_ON(sbi->total_valid_inode_count == sbi->total_node_count);
+       f2fs_bug_on(sbi->total_valid_inode_count == sbi->total_node_count);
        sbi->total_valid_inode_count++;
        spin_unlock(&sbi->stat_lock);
 }
@@ -776,7 +754,7 @@ static inline void inc_valid_inode_count(struct f2fs_sb_info *sbi)
 static inline int dec_valid_inode_count(struct f2fs_sb_info *sbi)
 {
        spin_lock(&sbi->stat_lock);
-       BUG_ON(!sbi->total_valid_inode_count);
+       f2fs_bug_on(!sbi->total_valid_inode_count);
        sbi->total_valid_inode_count--;
        spin_unlock(&sbi->stat_lock);
        return 0;
@@ -797,7 +775,7 @@ static inline void f2fs_put_page(struct page *page, int unlock)
                return;
 
        if (unlock) {
-               BUG_ON(!PageLocked(page));
+               f2fs_bug_on(!PageLocked(page));
                unlock_page(page);
        }
        page_cache_release(page);
@@ -819,6 +797,20 @@ static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name,
        return kmem_cache_create(name, size, 0, SLAB_RECLAIM_ACCOUNT, ctor);
 }
 
+static inline void *f2fs_kmem_cache_alloc(struct kmem_cache *cachep,
+                                               gfp_t flags)
+{
+       void *entry;
+retry:
+       entry = kmem_cache_alloc(cachep, flags);
+       if (!entry) {
+               cond_resched();
+               goto retry;
+       }
+
+       return entry;
+}
+
 #define RAW_IS_INODE(p)        ((p)->footer.nid == (p)->footer.ino)
 
 static inline bool IS_INODE(struct page *page)
@@ -979,6 +971,7 @@ long f2fs_compat_ioctl(struct file *, unsigned int, unsigned long);
  */
 void f2fs_set_inode_flags(struct inode *);
 struct inode *f2fs_iget(struct super_block *, unsigned long);
+int try_to_free_nats(struct f2fs_sb_info *, int);
 void update_inode(struct inode *, struct page *);
 int update_inode_page(struct inode *);
 int f2fs_write_inode(struct inode *, struct writeback_control *);
@@ -1033,6 +1026,7 @@ void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
 int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int);
 int truncate_inode_blocks(struct inode *, pgoff_t);
 int truncate_xattr_node(struct inode *, struct page *);
+int wait_on_node_pages_writeback(struct f2fs_sb_info *, nid_t);
 int remove_inode_page(struct inode *);
 struct page *new_inode_page(struct inode *, const struct qstr *);
 struct page *new_node_page(struct dnode_of_data *, unsigned int, struct page *);
@@ -1059,6 +1053,7 @@ void destroy_node_manager_caches(void);
  * segment.c
  */
 void f2fs_balance_fs(struct f2fs_sb_info *);
+void f2fs_balance_fs_bg(struct f2fs_sb_info *);
 void invalidate_blocks(struct f2fs_sb_info *, block_t);
 void clear_prefree_segments(struct f2fs_sb_info *);
 int npages_for_summary_flush(struct f2fs_sb_info *);
@@ -1172,7 +1167,16 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi)
        return (struct f2fs_stat_info*)sbi->stat_info;
 }
 
-#define stat_inc_call_count(si)        ((si)->call_count++)
+#define stat_inc_call_count(si)                ((si)->call_count++)
+#define stat_inc_bggc_count(sbi)       ((sbi)->bg_gc++)
+#define stat_inc_dirty_dir(sbi)                ((sbi)->n_dirty_dirs++)
+#define stat_dec_dirty_dir(sbi)                ((sbi)->n_dirty_dirs--)
+#define stat_inc_total_hit(sb)         ((F2FS_SB(sb))->total_hit_ext++)
+#define stat_inc_read_hit(sb)          ((F2FS_SB(sb))->read_hit_ext++)
+#define stat_inc_seg_type(sbi, curseg)                                 \
+               ((sbi)->segment_count[(curseg)->alloc_type]++)
+#define stat_inc_block_count(sbi, curseg)                              \
+               ((sbi)->block_count[(curseg)->alloc_type]++)
 
 #define stat_inc_seg_count(sbi, type)                                  \
        do {                                                            \
@@ -1207,6 +1211,13 @@ void __init f2fs_create_root_stats(void);
 void f2fs_destroy_root_stats(void);
 #else
 #define stat_inc_call_count(si)
+#define stat_inc_bggc_count(si)
+#define stat_inc_dirty_dir(sbi)
+#define stat_dec_dirty_dir(sbi)
+#define stat_inc_total_hit(sb)
+#define stat_inc_read_hit(sb)
+#define stat_inc_seg_type(sbi, curseg)
+#define stat_inc_block_count(sbi, curseg)
 #define stat_inc_seg_count(si, type)
 #define stat_inc_tot_blk_count(si, blks)
 #define stat_inc_data_blk_count(si, blks)
index 02c906971cc6311f43527a6adfb9f75ee77eae9e..7d714f4972d59505e04576306dfd99a363f3b7d4 100644 (file)
@@ -35,18 +35,18 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        block_t old_blk_addr;
        struct dnode_of_data dn;
-       int err, ilock;
+       int err;
 
        f2fs_balance_fs(sbi);
 
        sb_start_pagefault(inode->i_sb);
 
        /* block allocation */
-       ilock = mutex_lock_op(sbi);
+       f2fs_lock_op(sbi);
        set_new_dnode(&dn, inode, NULL, NULL, 0);
        err = get_dnode_of_data(&dn, page->index, ALLOC_NODE);
        if (err) {
-               mutex_unlock_op(sbi, ilock);
+               f2fs_unlock_op(sbi);
                goto out;
        }
 
@@ -56,12 +56,12 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
                err = reserve_new_block(&dn);
                if (err) {
                        f2fs_put_dnode(&dn);
-                       mutex_unlock_op(sbi, ilock);
+                       f2fs_unlock_op(sbi);
                        goto out;
                }
        }
        f2fs_put_dnode(&dn);
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
 
        file_update_time(vma->vm_file);
        lock_page(page);
@@ -88,6 +88,7 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
        set_page_dirty(page);
        SetPageUptodate(page);
 
+       trace_f2fs_vm_page_mkwrite(page, DATA);
 mapped:
        /* fill the page */
        wait_on_page_writeback(page);
@@ -188,8 +189,9 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
                        if (ret)
                                goto out;
                }
-               filemap_fdatawait_range(sbi->node_inode->i_mapping,
-                                                       0, LONG_MAX);
+               ret = wait_on_node_pages_writeback(sbi, inode->i_ino);
+               if (ret)
+                       goto out;
                ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
        }
 out:
@@ -270,7 +272,7 @@ static int truncate_blocks(struct inode *inode, u64 from)
        unsigned int blocksize = inode->i_sb->s_blocksize;
        struct dnode_of_data dn;
        pgoff_t free_from;
-       int count = 0, ilock = -1;
+       int count = 0;
        int err;
 
        trace_f2fs_truncate_blocks_enter(inode, from);
@@ -278,13 +280,13 @@ static int truncate_blocks(struct inode *inode, u64 from)
        free_from = (pgoff_t)
                        ((from + blocksize - 1) >> (sbi->log_blocksize));
 
-       ilock = mutex_lock_op(sbi);
+       f2fs_lock_op(sbi);
        set_new_dnode(&dn, inode, NULL, NULL, 0);
        err = get_dnode_of_data(&dn, free_from, LOOKUP_NODE);
        if (err) {
                if (err == -ENOENT)
                        goto free_next;
-               mutex_unlock_op(sbi, ilock);
+               f2fs_unlock_op(sbi);
                trace_f2fs_truncate_blocks_exit(inode, err);
                return err;
        }
@@ -295,7 +297,7 @@ static int truncate_blocks(struct inode *inode, u64 from)
                count = ADDRS_PER_BLOCK;
 
        count -= dn.ofs_in_node;
-       BUG_ON(count < 0);
+       f2fs_bug_on(count < 0);
 
        if (dn.ofs_in_node || IS_INODE(dn.node_page)) {
                truncate_data_blocks_range(&dn, count);
@@ -305,7 +307,7 @@ static int truncate_blocks(struct inode *inode, u64 from)
        f2fs_put_dnode(&dn);
 free_next:
        err = truncate_inode_blocks(inode, free_from);
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
 
        /* lastly zero out the first data page */
        truncate_partial_data_page(inode, from);
@@ -416,16 +418,15 @@ static void fill_zero(struct inode *inode, pgoff_t index,
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct page *page;
-       int ilock;
 
        if (!len)
                return;
 
        f2fs_balance_fs(sbi);
 
-       ilock = mutex_lock_op(sbi);
+       f2fs_lock_op(sbi);
        page = get_new_data_page(inode, NULL, index, false);
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
 
        if (!IS_ERR(page)) {
                wait_on_page_writeback(page);
@@ -484,7 +485,6 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len, int mode)
                        struct address_space *mapping = inode->i_mapping;
                        loff_t blk_start, blk_end;
                        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-                       int ilock;
 
                        f2fs_balance_fs(sbi);
 
@@ -493,9 +493,9 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len, int mode)
                        truncate_inode_pages_range(mapping, blk_start,
                                        blk_end - 1);
 
-                       ilock = mutex_lock_op(sbi);
+                       f2fs_lock_op(sbi);
                        ret = truncate_hole(inode, pg_start, pg_end);
-                       mutex_unlock_op(sbi, ilock);
+                       f2fs_unlock_op(sbi);
                }
        }
 
@@ -529,13 +529,12 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
 
        for (index = pg_start; index <= pg_end; index++) {
                struct dnode_of_data dn;
-               int ilock;
 
-               ilock = mutex_lock_op(sbi);
+               f2fs_lock_op(sbi);
                set_new_dnode(&dn, inode, NULL, NULL, 0);
                ret = get_dnode_of_data(&dn, index, ALLOC_NODE);
                if (ret) {
-                       mutex_unlock_op(sbi, ilock);
+                       f2fs_unlock_op(sbi);
                        break;
                }
 
@@ -543,12 +542,12 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
                        ret = reserve_new_block(&dn);
                        if (ret) {
                                f2fs_put_dnode(&dn);
-                               mutex_unlock_op(sbi, ilock);
+                               f2fs_unlock_op(sbi);
                                break;
                        }
                }
                f2fs_put_dnode(&dn);
-               mutex_unlock_op(sbi, ilock);
+               f2fs_unlock_op(sbi);
 
                if (pg_start == pg_end)
                        new_size = offset + len;
index 2f157e883687d5edb07f7cd53745d0ab6571cb6a..b7ad1ec7e4ccb50227d1b48ce6d9ee7d26796f07 100644 (file)
@@ -77,13 +77,15 @@ static int gc_thread_func(void *data)
                else
                        wait_ms = increase_sleep_time(gc_th, wait_ms);
 
-#ifdef CONFIG_F2FS_STAT_FS
-               sbi->bg_gc++;
-#endif
+               stat_inc_bggc_count(sbi);
 
                /* if return value is not zero, no victim was selected */
                if (f2fs_gc(sbi))
                        wait_ms = gc_th->no_gc_sleep_time;
+
+               /* balancing f2fs's metadata periodically */
+               f2fs_balance_fs_bg(sbi);
+
        } while (!kthread_should_stop());
        return 0;
 }
@@ -236,8 +238,8 @@ static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno)
        return UINT_MAX - ((100 * (100 - u) * age) / (100 + u));
 }
 
-static unsigned int get_gc_cost(struct f2fs_sb_info *sbi, unsigned int segno,
-                                       struct victim_sel_policy *p)
+static inline unsigned int get_gc_cost(struct f2fs_sb_info *sbi,
+                       unsigned int segno, struct victim_sel_policy *p)
 {
        if (p->alloc_mode == SSR)
                return get_seg_entry(sbi, segno)->ckpt_valid_blocks;
@@ -293,7 +295,11 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
                        }
                        break;
                }
-               p.offset = ((segno / p.ofs_unit) * p.ofs_unit) + p.ofs_unit;
+
+               p.offset = segno + p.ofs_unit;
+               if (p.ofs_unit > 1)
+                       p.offset -= segno % p.ofs_unit;
+
                secno = GET_SECNO(sbi, segno);
 
                if (sec_usage_check(sbi, secno))
@@ -306,10 +312,9 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
                if (p.min_cost > cost) {
                        p.min_segno = segno;
                        p.min_cost = cost;
-               }
-
-               if (cost == max_cost)
+               } else if (unlikely(cost == max_cost)) {
                        continue;
+               }
 
                if (nsearched++ >= p.max_search) {
                        sbi->last_victim[p.gc_mode] = segno;
@@ -358,12 +363,8 @@ static void add_gc_inode(struct inode *inode, struct list_head *ilist)
                iput(inode);
                return;
        }
-repeat:
-       new_ie = kmem_cache_alloc(winode_slab, GFP_NOFS);
-       if (!new_ie) {
-               cond_resched();
-               goto repeat;
-       }
+
+       new_ie = f2fs_kmem_cache_alloc(winode_slab, GFP_NOFS);
        new_ie->inode = inode;
        list_add_tail(&new_ie->list, ilist);
 }
index 9339cd292047b897bbc7bb0c5ef5ff337f9190ab..d0eaa9faeca0a948bfd662846a0b173f69ea1206 100644 (file)
@@ -37,6 +37,31 @@ void f2fs_set_inode_flags(struct inode *inode)
                inode->i_flags |= S_DIRSYNC;
 }
 
+static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
+{
+       if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
+                       S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
+               if (ri->i_addr[0])
+                       inode->i_rdev = old_decode_dev(le32_to_cpu(ri->i_addr[0]));
+               else
+                       inode->i_rdev = new_decode_dev(le32_to_cpu(ri->i_addr[1]));
+       }
+}
+
+static void __set_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
+{
+       if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
+               if (old_valid_dev(inode->i_rdev)) {
+                       ri->i_addr[0] = cpu_to_le32(old_encode_dev(inode->i_rdev));
+                       ri->i_addr[1] = 0;
+               } else {
+                       ri->i_addr[0] = 0;
+                       ri->i_addr[1] = cpu_to_le32(new_encode_dev(inode->i_rdev));
+                       ri->i_addr[2] = 0;
+               }
+       }
+}
+
 static int do_read_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
@@ -73,10 +98,6 @@ static int do_read_inode(struct inode *inode)
        inode->i_ctime.tv_nsec = le32_to_cpu(ri->i_ctime_nsec);
        inode->i_mtime.tv_nsec = le32_to_cpu(ri->i_mtime_nsec);
        inode->i_generation = le32_to_cpu(ri->i_generation);
-       if (ri->i_addr[0])
-               inode->i_rdev = old_decode_dev(le32_to_cpu(ri->i_addr[0]));
-       else
-               inode->i_rdev = new_decode_dev(le32_to_cpu(ri->i_addr[1]));
 
        fi->i_current_depth = le32_to_cpu(ri->i_current_depth);
        fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid);
@@ -84,8 +105,13 @@ static int do_read_inode(struct inode *inode)
        fi->flags = 0;
        fi->i_advise = ri->i_advise;
        fi->i_pino = le32_to_cpu(ri->i_pino);
+
        get_extent_info(&fi->ext, ri->i_ext);
        get_inline_info(fi, ri);
+
+       /* get rdev by using inline_info */
+       __get_inode_rdev(inode, ri);
+
        f2fs_put_page(node_page, 1);
        return 0;
 }
@@ -179,21 +205,10 @@ void update_inode(struct inode *inode, struct page *node_page)
        ri->i_pino = cpu_to_le32(F2FS_I(inode)->i_pino);
        ri->i_generation = cpu_to_le32(inode->i_generation);
 
-       if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
-               if (old_valid_dev(inode->i_rdev)) {
-                       ri->i_addr[0] =
-                               cpu_to_le32(old_encode_dev(inode->i_rdev));
-                       ri->i_addr[1] = 0;
-               } else {
-                       ri->i_addr[0] = 0;
-                       ri->i_addr[1] =
-                               cpu_to_le32(new_encode_dev(inode->i_rdev));
-                       ri->i_addr[2] = 0;
-               }
-       }
-
+       __set_inode_rdev(inode, ri);
        set_cold_node(inode, node_page);
        set_page_dirty(node_page);
+
        clear_inode_flag(F2FS_I(inode), FI_DIRTY_INODE);
 }
 
@@ -214,7 +229,7 @@ int update_inode_page(struct inode *inode)
 int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-       int ret, ilock;
+       int ret;
 
        if (inode->i_ino == F2FS_NODE_INO(sbi) ||
                        inode->i_ino == F2FS_META_INO(sbi))
@@ -227,9 +242,9 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
         * We need to lock here to prevent from producing dirty node pages
         * during the urgent cleaning time when runing out of free sections.
         */
-       ilock = mutex_lock_op(sbi);
+       f2fs_lock_op(sbi);
        ret = update_inode_page(inode);
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
 
        if (wbc)
                f2fs_balance_fs(sbi);
@@ -243,7 +258,6 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
 void f2fs_evict_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-       int ilock;
 
        trace_f2fs_evict_inode(inode);
        truncate_inode_pages(&inode->i_data, 0);
@@ -252,7 +266,7 @@ void f2fs_evict_inode(struct inode *inode)
                        inode->i_ino == F2FS_META_INO(sbi))
                goto no_delete;
 
-       BUG_ON(atomic_read(&F2FS_I(inode)->dirty_dents));
+       f2fs_bug_on(atomic_read(&F2FS_I(inode)->dirty_dents));
        remove_dirty_dir_inode(inode);
 
        if (inode->i_nlink || is_bad_inode(inode))
@@ -265,9 +279,9 @@ void f2fs_evict_inode(struct inode *inode)
        if (F2FS_HAS_BLOCKS(inode))
                f2fs_truncate(inode);
 
-       ilock = mutex_lock_op(sbi);
+       f2fs_lock_op(sbi);
        remove_inode_page(inode);
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
 
        sb_end_intwrite(inode->i_sb);
 no_delete:
index 2a5359c990fc09b0141982a2e26b345033848245..575adac17f8be2b55935498b0a49a15b78daddcf 100644 (file)
@@ -27,19 +27,19 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
        nid_t ino;
        struct inode *inode;
        bool nid_free = false;
-       int err, ilock;
+       int err;
 
        inode = new_inode(sb);
        if (!inode)
                return ERR_PTR(-ENOMEM);
 
-       ilock = mutex_lock_op(sbi);
+       f2fs_lock_op(sbi);
        if (!alloc_nid(sbi, &ino)) {
-               mutex_unlock_op(sbi, ilock);
+               f2fs_unlock_op(sbi);
                err = -ENOSPC;
                goto fail;
        }
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
 
        inode->i_uid = current_fsuid();
 
@@ -115,7 +115,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
        struct inode *inode;
        nid_t ino = 0;
-       int err, ilock;
+       int err;
 
        f2fs_balance_fs(sbi);
 
@@ -131,9 +131,9 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        inode->i_mapping->a_ops = &f2fs_dblock_aops;
        ino = inode->i_ino;
 
-       ilock = mutex_lock_op(sbi);
+       f2fs_lock_op(sbi);
        err = f2fs_add_link(dentry, inode);
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
        if (err)
                goto out;
 
@@ -157,7 +157,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
        struct inode *inode = old_dentry->d_inode;
        struct super_block *sb = dir->i_sb;
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
-       int err, ilock;
+       int err;
 
        f2fs_balance_fs(sbi);
 
@@ -165,9 +165,9 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
        ihold(inode);
 
        set_inode_flag(F2FS_I(inode), FI_INC_LINK);
-       ilock = mutex_lock_op(sbi);
+       f2fs_lock_op(sbi);
        err = f2fs_add_link(dentry, inode);
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
        if (err)
                goto out;
 
@@ -220,7 +220,6 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
        struct f2fs_dir_entry *de;
        struct page *page;
        int err = -ENOENT;
-       int ilock;
 
        trace_f2fs_unlink_enter(dir, dentry);
        f2fs_balance_fs(sbi);
@@ -229,16 +228,16 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
        if (!de)
                goto fail;
 
+       f2fs_lock_op(sbi);
        err = acquire_orphan_inode(sbi);
        if (err) {
+               f2fs_unlock_op(sbi);
                kunmap(page);
                f2fs_put_page(page, 0);
                goto fail;
        }
-
-       ilock = mutex_lock_op(sbi);
        f2fs_delete_entry(de, page, inode);
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
 
        /* In order to evict this inode,  we set it dirty */
        mark_inode_dirty(inode);
@@ -254,7 +253,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
        struct inode *inode;
        size_t symlen = strlen(symname) + 1;
-       int err, ilock;
+       int err;
 
        f2fs_balance_fs(sbi);
 
@@ -265,9 +264,9 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
        inode->i_op = &f2fs_symlink_inode_operations;
        inode->i_mapping->a_ops = &f2fs_dblock_aops;
 
-       ilock = mutex_lock_op(sbi);
+       f2fs_lock_op(sbi);
        err = f2fs_add_link(dentry, inode);
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
        if (err)
                goto out;
 
@@ -290,7 +289,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
        struct inode *inode;
-       int err, ilock;
+       int err;
 
        f2fs_balance_fs(sbi);
 
@@ -304,9 +303,9 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO);
 
        set_inode_flag(F2FS_I(inode), FI_INC_LINK);
-       ilock = mutex_lock_op(sbi);
+       f2fs_lock_op(sbi);
        err = f2fs_add_link(dentry, inode);
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
        if (err)
                goto out_fail;
 
@@ -342,7 +341,6 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
        struct inode *inode;
        int err = 0;
-       int ilock;
 
        if (!new_valid_dev(rdev))
                return -EINVAL;
@@ -356,9 +354,9 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
        init_special_inode(inode, inode->i_mode, rdev);
        inode->i_op = &f2fs_special_inode_operations;
 
-       ilock = mutex_lock_op(sbi);
+       f2fs_lock_op(sbi);
        err = f2fs_add_link(dentry, inode);
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
        if (err)
                goto out;
 
@@ -387,7 +385,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct f2fs_dir_entry *old_dir_entry = NULL;
        struct f2fs_dir_entry *old_entry;
        struct f2fs_dir_entry *new_entry;
-       int err = -ENOENT, ilock = -1;
+       int err = -ENOENT;
 
        f2fs_balance_fs(sbi);
 
@@ -402,7 +400,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        goto out_old;
        }
 
-       ilock = mutex_lock_op(sbi);
+       f2fs_lock_op(sbi);
 
        if (new_inode) {
 
@@ -467,7 +465,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                update_inode_page(old_dir);
        }
 
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
        return 0;
 
 put_out_dir:
@@ -477,7 +475,7 @@ out_dir:
                kunmap(old_dir_page);
                f2fs_put_page(old_dir_page, 0);
        }
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
 out_old:
        kunmap(old_page);
        f2fs_put_page(old_page, 0);
index 51ef2789443322ea0e3a2d683d305b753997aeae..4ac4150d421dc05e6c20812d5fd36dcc910a938a 100644 (file)
@@ -204,7 +204,7 @@ retry:
                }
                e->ni = *ni;
                e->checkpointed = true;
-               BUG_ON(ni->blk_addr == NEW_ADDR);
+               f2fs_bug_on(ni->blk_addr == NEW_ADDR);
        } else if (new_blkaddr == NEW_ADDR) {
                /*
                 * when nid is reallocated,
@@ -212,19 +212,19 @@ retry:
                 * So, reinitialize it with new information.
                 */
                e->ni = *ni;
-               BUG_ON(ni->blk_addr != NULL_ADDR);
+               f2fs_bug_on(ni->blk_addr != NULL_ADDR);
        }
 
        if (new_blkaddr == NEW_ADDR)
                e->checkpointed = false;
 
        /* sanity check */
-       BUG_ON(nat_get_blkaddr(e) != ni->blk_addr);
-       BUG_ON(nat_get_blkaddr(e) == NULL_ADDR &&
+       f2fs_bug_on(nat_get_blkaddr(e) != ni->blk_addr);
+       f2fs_bug_on(nat_get_blkaddr(e) == NULL_ADDR &&
                        new_blkaddr == NULL_ADDR);
-       BUG_ON(nat_get_blkaddr(e) == NEW_ADDR &&
+       f2fs_bug_on(nat_get_blkaddr(e) == NEW_ADDR &&
                        new_blkaddr == NEW_ADDR);
-       BUG_ON(nat_get_blkaddr(e) != NEW_ADDR &&
+       f2fs_bug_on(nat_get_blkaddr(e) != NEW_ADDR &&
                        nat_get_blkaddr(e) != NULL_ADDR &&
                        new_blkaddr == NEW_ADDR);
 
@@ -240,7 +240,7 @@ retry:
        write_unlock(&nm_i->nat_tree_lock);
 }
 
-static int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
+int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
 
@@ -495,10 +495,10 @@ static void truncate_node(struct dnode_of_data *dn)
 
        get_node_info(sbi, dn->nid, &ni);
        if (dn->inode->i_blocks == 0) {
-               BUG_ON(ni.blk_addr != NULL_ADDR);
+               f2fs_bug_on(ni.blk_addr != NULL_ADDR);
                goto invalidate;
        }
-       BUG_ON(ni.blk_addr == NULL_ADDR);
+       f2fs_bug_on(ni.blk_addr == NULL_ADDR);
 
        /* Deallocate node address */
        invalidate_blocks(sbi, ni.blk_addr);
@@ -822,7 +822,7 @@ int remove_inode_page(struct inode *inode)
        }
 
        /* 0 is possible, after f2fs_new_inode() is failed */
-       BUG_ON(inode->i_blocks != 0 && inode->i_blocks != 1);
+       f2fs_bug_on(inode->i_blocks != 0 && inode->i_blocks != 1);
        set_new_dnode(&dn, inode, page, page, ino);
        truncate_node(&dn);
        return 0;
@@ -863,7 +863,7 @@ struct page *new_node_page(struct dnode_of_data *dn,
        get_node_info(sbi, dn->nid, &old_ni);
 
        /* Reinitialize old_ni with new node page */
-       BUG_ON(old_ni.blk_addr != NULL_ADDR);
+       f2fs_bug_on(old_ni.blk_addr != NULL_ADDR);
        new_ni = old_ni;
        new_ni.ino = dn->inode->i_ino;
        set_node_addr(sbi, &new_ni, NEW_ADDR);
@@ -969,7 +969,7 @@ repeat:
                goto repeat;
        }
 got_it:
-       BUG_ON(nid != nid_of_node(page));
+       f2fs_bug_on(nid != nid_of_node(page));
        mark_page_accessed(page);
        return page;
 }
@@ -1148,6 +1148,47 @@ continue_unlock:
        return nwritten;
 }
 
+int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino)
+{
+       struct address_space *mapping = sbi->node_inode->i_mapping;
+       pgoff_t index = 0, end = LONG_MAX;
+       struct pagevec pvec;
+       int nr_pages;
+       int ret2 = 0, ret = 0;
+
+       pagevec_init(&pvec, 0);
+       while ((index <= end) &&
+                       (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
+                       PAGECACHE_TAG_WRITEBACK,
+                       min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1)) != 0) {
+               unsigned i;
+
+               for (i = 0; i < nr_pages; i++) {
+                       struct page *page = pvec.pages[i];
+
+                       /* until radix tree lookup accepts end_index */
+                       if (page->index > end)
+                               continue;
+
+                       if (ino && ino_of_node(page) == ino) {
+                               wait_on_page_writeback(page);
+                               if (TestClearPageError(page))
+                                       ret = -EIO;
+                       }
+               }
+               pagevec_release(&pvec);
+               cond_resched();
+       }
+
+       if (test_and_clear_bit(AS_ENOSPC, &mapping->flags))
+               ret2 = -ENOSPC;
+       if (test_and_clear_bit(AS_EIO, &mapping->flags))
+               ret2 = -EIO;
+       if (!ret)
+               ret = ret2;
+       return ret;
+}
+
 static int f2fs_write_node_page(struct page *page,
                                struct writeback_control *wbc)
 {
@@ -1156,11 +1197,14 @@ static int f2fs_write_node_page(struct page *page,
        block_t new_addr;
        struct node_info ni;
 
+       if (sbi->por_doing)
+               goto redirty_out;
+
        wait_on_page_writeback(page);
 
        /* get old block addr of this node page */
        nid = nid_of_node(page);
-       BUG_ON(page->index != nid);
+       f2fs_bug_on(page->index != nid);
 
        get_node_info(sbi, nid, &ni);
 
@@ -1171,12 +1215,8 @@ static int f2fs_write_node_page(struct page *page,
                return 0;
        }
 
-       if (wbc->for_reclaim) {
-               dec_page_count(sbi, F2FS_DIRTY_NODES);
-               wbc->pages_skipped++;
-               set_page_dirty(page);
-               return AOP_WRITEPAGE_ACTIVATE;
-       }
+       if (wbc->for_reclaim)
+               goto redirty_out;
 
        mutex_lock(&sbi->node_write);
        set_page_writeback(page);
@@ -1186,6 +1226,12 @@ static int f2fs_write_node_page(struct page *page,
        mutex_unlock(&sbi->node_write);
        unlock_page(page);
        return 0;
+
+redirty_out:
+       dec_page_count(sbi, F2FS_DIRTY_NODES);
+       wbc->pages_skipped++;
+       set_page_dirty(page);
+       return AOP_WRITEPAGE_ACTIVATE;
 }
 
 /*
@@ -1200,11 +1246,8 @@ static int f2fs_write_node_pages(struct address_space *mapping,
        struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
        long nr_to_write = wbc->nr_to_write;
 
-       /* First check balancing cached NAT entries */
-       if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK)) {
-               f2fs_sync_fs(sbi->sb, true);
-               return 0;
-       }
+       /* balancing f2fs's metadata in background */
+       f2fs_balance_fs_bg(sbi);
 
        /* collect a number of dirty node pages and write together */
        if (get_pages(sbi, F2FS_DIRTY_NODES) < COLLECT_DIRTY_NODES)
@@ -1223,6 +1266,8 @@ static int f2fs_set_node_page_dirty(struct page *page)
        struct address_space *mapping = page->mapping;
        struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
 
+       trace_f2fs_set_page_dirty(page, NODE);
+
        SetPageUptodate(page);
        if (!PageDirty(page)) {
                __set_page_dirty_nobuffers(page);
@@ -1291,23 +1336,18 @@ static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build)
        if (nid == 0)
                return 0;
 
-       if (!build)
-               goto retry;
-
-       /* do not add allocated nids */
-       read_lock(&nm_i->nat_tree_lock);
-       ne = __lookup_nat_cache(nm_i, nid);
-       if (ne && nat_get_blkaddr(ne) != NULL_ADDR)
-               allocated = true;
-       read_unlock(&nm_i->nat_tree_lock);
-       if (allocated)
-               return 0;
-retry:
-       i = kmem_cache_alloc(free_nid_slab, GFP_NOFS);
-       if (!i) {
-               cond_resched();
-               goto retry;
+       if (build) {
+               /* do not add allocated nids */
+               read_lock(&nm_i->nat_tree_lock);
+               ne = __lookup_nat_cache(nm_i, nid);
+               if (ne && nat_get_blkaddr(ne) != NULL_ADDR)
+                       allocated = true;
+               read_unlock(&nm_i->nat_tree_lock);
+               if (allocated)
+                       return 0;
        }
+
+       i = f2fs_kmem_cache_alloc(free_nid_slab, GFP_NOFS);
        i->nid = nid;
        i->state = NID_NEW;
 
@@ -1350,7 +1390,7 @@ static void scan_nat_page(struct f2fs_nm_info *nm_i,
                        break;
 
                blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr);
-               BUG_ON(blk_addr == NEW_ADDR);
+               f2fs_bug_on(blk_addr == NEW_ADDR);
                if (blk_addr == NULL_ADDR) {
                        if (add_free_nid(nm_i, start_nid, true) < 0)
                                break;
@@ -1421,14 +1461,14 @@ retry:
 
        /* We should not use stale free nids created by build_free_nids */
        if (nm_i->fcnt && !sbi->on_build_free_nids) {
-               BUG_ON(list_empty(&nm_i->free_nid_list));
+               f2fs_bug_on(list_empty(&nm_i->free_nid_list));
                list_for_each(this, &nm_i->free_nid_list) {
                        i = list_entry(this, struct free_nid, list);
                        if (i->state == NID_NEW)
                                break;
                }
 
-               BUG_ON(i->state != NID_NEW);
+               f2fs_bug_on(i->state != NID_NEW);
                *nid = i->nid;
                i->state = NID_ALLOC;
                nm_i->fcnt--;
@@ -1439,9 +1479,9 @@ retry:
 
        /* Let's scan nat pages and its caches to get free nids */
        mutex_lock(&nm_i->build_lock);
-       sbi->on_build_free_nids = 1;
+       sbi->on_build_free_nids = true;
        build_free_nids(sbi);
-       sbi->on_build_free_nids = 0;
+       sbi->on_build_free_nids = false;
        mutex_unlock(&nm_i->build_lock);
        goto retry;
 }
@@ -1456,7 +1496,7 @@ void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid)
 
        spin_lock(&nm_i->free_nid_list_lock);
        i = __lookup_free_nid_list(nid, &nm_i->free_nid_list);
-       BUG_ON(!i || i->state != NID_ALLOC);
+       f2fs_bug_on(!i || i->state != NID_ALLOC);
        __del_from_free_nid_list(i);
        spin_unlock(&nm_i->free_nid_list_lock);
 }
@@ -1474,7 +1514,7 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
 
        spin_lock(&nm_i->free_nid_list_lock);
        i = __lookup_free_nid_list(nid, &nm_i->free_nid_list);
-       BUG_ON(!i || i->state != NID_ALLOC);
+       f2fs_bug_on(!i || i->state != NID_ALLOC);
        if (nm_i->fcnt > 2 * MAX_FREE_NIDS) {
                __del_from_free_nid_list(i);
        } else {
@@ -1677,7 +1717,7 @@ to_nat_page:
                        nat_blk = page_address(page);
                }
 
-               BUG_ON(!nat_blk);
+               f2fs_bug_on(!nat_blk);
                raw_ne = nat_blk->entries[nid - start_nid];
 flush_now:
                new_blkaddr = nat_get_blkaddr(ne);
@@ -1781,11 +1821,11 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
        /* destroy free nid list */
        spin_lock(&nm_i->free_nid_list_lock);
        list_for_each_entry_safe(i, next_i, &nm_i->free_nid_list, list) {
-               BUG_ON(i->state == NID_ALLOC);
+               f2fs_bug_on(i->state == NID_ALLOC);
                __del_from_free_nid_list(i);
                nm_i->fcnt--;
        }
-       BUG_ON(nm_i->fcnt);
+       f2fs_bug_on(nm_i->fcnt);
        spin_unlock(&nm_i->free_nid_list_lock);
 
        /* destroy nat cache */
@@ -1799,7 +1839,7 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
                        __del_from_nat_cache(nm_i, e);
                }
        }
-       BUG_ON(nm_i->nat_cnt);
+       f2fs_bug_on(nm_i->nat_cnt);
        write_unlock(&nm_i->nat_tree_lock);
 
        kfree(nm_i->nat_bitmap);
index 51ef5eec33d7fec07503e6eb9c90b86256b1dc3a..fdc81161f2543a4818e371946ba691515aa9f3c4 100644 (file)
@@ -64,24 +64,31 @@ static int recover_dentry(struct page *ipage, struct inode *inode)
        name.name = raw_inode->i_name;
 retry:
        de = f2fs_find_entry(dir, &name, &page);
-       if (de && inode->i_ino == le32_to_cpu(de->ino)) {
-               kunmap(page);
-               f2fs_put_page(page, 0);
-               goto out;
-       }
+       if (de && inode->i_ino == le32_to_cpu(de->ino))
+               goto out_unmap_put;
        if (de) {
                einode = f2fs_iget(inode->i_sb, le32_to_cpu(de->ino));
                if (IS_ERR(einode)) {
                        WARN_ON(1);
                        if (PTR_ERR(einode) == -ENOENT)
                                err = -EEXIST;
-                       goto out;
+                       goto out_unmap_put;
+               }
+               err = acquire_orphan_inode(F2FS_SB(inode->i_sb));
+               if (err) {
+                       iput(einode);
+                       goto out_unmap_put;
                }
                f2fs_delete_entry(de, page, einode);
                iput(einode);
                goto retry;
        }
        err = __f2fs_add_link(dir, &name, inode);
+       goto out;
+
+out_unmap_put:
+       kunmap(page);
+       f2fs_put_page(page, 0);
 out:
        f2fs_msg(inode->i_sb, KERN_NOTICE, "recover_inode and its dentry: "
                        "ino = %x, name = %s, dir = %lx, err = %d",
@@ -285,7 +292,6 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
        struct f2fs_summary sum;
        struct node_info ni;
        int err = 0, recovered = 0;
-       int ilock;
 
        start = start_bidx_of_node(ofs_of_node(page), fi);
        if (IS_INODE(page))
@@ -293,20 +299,20 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
        else
                end = start + ADDRS_PER_BLOCK;
 
-       ilock = mutex_lock_op(sbi);
+       f2fs_lock_op(sbi);
        set_new_dnode(&dn, inode, NULL, NULL, 0);
 
        err = get_dnode_of_data(&dn, start, ALLOC_NODE);
        if (err) {
-               mutex_unlock_op(sbi, ilock);
+               f2fs_unlock_op(sbi);
                return err;
        }
 
        wait_on_page_writeback(dn.node_page);
 
        get_node_info(sbi, dn.nid, &ni);
-       BUG_ON(ni.ino != ino_of_node(page));
-       BUG_ON(ofs_of_node(dn.node_page) != ofs_of_node(page));
+       f2fs_bug_on(ni.ino != ino_of_node(page));
+       f2fs_bug_on(ofs_of_node(dn.node_page) != ofs_of_node(page));
 
        for (; start < end; start++) {
                block_t src, dest;
@@ -316,9 +322,9 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
 
                if (src != dest && dest != NEW_ADDR && dest != NULL_ADDR) {
                        if (src == NULL_ADDR) {
-                               int err = reserve_new_block(&dn);
+                               err = reserve_new_block(&dn);
                                /* We should not get -ENOSPC */
-                               BUG_ON(err);
+                               f2fs_bug_on(err);
                        }
 
                        /* Check the previous node page having this index */
@@ -349,7 +355,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
        recover_node_page(sbi, dn.node_page, &sum, &ni, blkaddr);
 err:
        f2fs_put_dnode(&dn);
-       mutex_unlock_op(sbi, ilock);
+       f2fs_unlock_op(sbi);
 
        f2fs_msg(sbi->sb, KERN_NOTICE, "recover_data: ino = %lx, "
                        "recovered_data = %d blocks, err = %d",
@@ -419,6 +425,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
 {
        struct list_head inode_list;
        int err;
+       bool need_writecp = false;
 
        fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
                        sizeof(struct fsync_inode_entry), NULL);
@@ -428,7 +435,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
        INIT_LIST_HEAD(&inode_list);
 
        /* step #1: find fsynced inode numbers */
-       sbi->por_doing = 1;
+       sbi->por_doing = true;
        err = find_fsync_dnodes(sbi, &inode_list);
        if (err)
                goto out;
@@ -436,14 +443,16 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
        if (list_empty(&inode_list))
                goto out;
 
+       need_writecp = true;
+
        /* step #2: recover data */
        err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE);
-       BUG_ON(!list_empty(&inode_list));
+       f2fs_bug_on(!list_empty(&inode_list));
 out:
        destroy_fsync_dnodes(&inode_list);
        kmem_cache_destroy(fsync_entry_slab);
-       sbi->por_doing = 0;
-       if (!err)
+       sbi->por_doing = false;
+       if (!err && need_writecp)
                write_checkpoint(sbi, false);
        return err;
 }
index 09af9c7b0f52673fff92f00be5a37a6030b72668..fa284d397199faed53f1c8ffb4de611440ad2e73 100644 (file)
@@ -36,6 +36,14 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi)
        }
 }
 
+void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
+{
+       /* check the # of cached NAT entries and prefree segments */
+       if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK) ||
+                               excess_prefree_segs(sbi))
+               f2fs_sync_fs(sbi->sb, true);
+}
+
 static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
                enum dirty_type dirty_type)
 {
@@ -50,20 +58,10 @@ static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
 
        if (dirty_type == DIRTY) {
                struct seg_entry *sentry = get_seg_entry(sbi, segno);
-               enum dirty_type t = DIRTY_HOT_DATA;
-
-               dirty_type = sentry->type;
-
-               if (!test_and_set_bit(segno, dirty_i->dirty_segmap[dirty_type]))
-                       dirty_i->nr_dirty[dirty_type]++;
+               enum dirty_type t = sentry->type;
 
-               /* Only one bitmap should be set */
-               for (; t <= DIRTY_COLD_NODE; t++) {
-                       if (t == dirty_type)
-                               continue;
-                       if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
-                               dirty_i->nr_dirty[t]--;
-               }
+               if (!test_and_set_bit(segno, dirty_i->dirty_segmap[t]))
+                       dirty_i->nr_dirty[t]++;
        }
 }
 
@@ -76,12 +74,11 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
                dirty_i->nr_dirty[dirty_type]--;
 
        if (dirty_type == DIRTY) {
-               enum dirty_type t = DIRTY_HOT_DATA;
+               struct seg_entry *sentry = get_seg_entry(sbi, segno);
+               enum dirty_type t = sentry->type;
 
-               /* clear all the bitmaps */
-               for (; t <= DIRTY_COLD_NODE; t++)
-                       if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
-                               dirty_i->nr_dirty[t]--;
+               if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
+                       dirty_i->nr_dirty[t]--;
 
                if (get_valid_blocks(sbi, segno, sbi->segs_per_sec) == 0)
                        clear_bit(GET_SECNO(sbi, segno),
@@ -142,27 +139,33 @@ static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi)
 void clear_prefree_segments(struct f2fs_sb_info *sbi)
 {
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
-       unsigned int segno = -1;
+       unsigned long *prefree_map = dirty_i->dirty_segmap[PRE];
        unsigned int total_segs = TOTAL_SEGS(sbi);
+       unsigned int start = 0, end = -1;
 
        mutex_lock(&dirty_i->seglist_lock);
+
        while (1) {
-               segno = find_next_bit(dirty_i->dirty_segmap[PRE], total_segs,
-                               segno + 1);
-               if (segno >= total_segs)
+               int i;
+               start = find_next_bit(prefree_map, total_segs, end + 1);
+               if (start >= total_segs)
                        break;
+               end = find_next_zero_bit(prefree_map, total_segs, start + 1);
+
+               for (i = start; i < end; i++)
+                       clear_bit(i, prefree_map);
 
-               if (test_and_clear_bit(segno, dirty_i->dirty_segmap[PRE]))
-                       dirty_i->nr_dirty[PRE]--;
-
-               /* Let's use trim */
-               if (test_opt(sbi, DISCARD))
-                       blkdev_issue_discard(sbi->sb->s_bdev,
-                                       START_BLOCK(sbi, segno) <<
-                                       sbi->log_sectors_per_block,
-                                       1 << (sbi->log_sectors_per_block +
-                                               sbi->log_blocks_per_seg),
-                                       GFP_NOFS, 0);
+               dirty_i->nr_dirty[PRE] -= end - start;
+
+               if (!test_opt(sbi, DISCARD))
+                       continue;
+
+               blkdev_issue_discard(sbi->sb->s_bdev,
+                               START_BLOCK(sbi, start) <<
+                               sbi->log_sectors_per_block,
+                               (1 << (sbi->log_sectors_per_block +
+                               sbi->log_blocks_per_seg)) * (end - start),
+                               GFP_NOFS, 0);
        }
        mutex_unlock(&dirty_i->seglist_lock);
 }
@@ -195,7 +198,7 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
        new_vblocks = se->valid_blocks + del;
        offset = GET_SEGOFF_FROM_SEG0(sbi, blkaddr) & (sbi->blocks_per_seg - 1);
 
-       BUG_ON((new_vblocks >> (sizeof(unsigned short) << 3) ||
+       f2fs_bug_on((new_vblocks >> (sizeof(unsigned short) << 3) ||
                                (new_vblocks > sbi->blocks_per_seg)));
 
        se->valid_blocks = new_vblocks;
@@ -235,7 +238,7 @@ void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr)
        unsigned int segno = GET_SEGNO(sbi, addr);
        struct sit_info *sit_i = SIT_I(sbi);
 
-       BUG_ON(addr == NULL_ADDR);
+       f2fs_bug_on(addr == NULL_ADDR);
        if (addr == NEW_ADDR)
                return;
 
@@ -267,9 +270,8 @@ static void __add_sum_entry(struct f2fs_sb_info *sbi, int type,
  */
 int npages_for_summary_flush(struct f2fs_sb_info *sbi)
 {
-       int total_size_bytes = 0;
        int valid_sum_count = 0;
-       int i, sum_space;
+       int i, sum_in_page;
 
        for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
                if (sbi->ckpt->alloc_type[i] == SSR)
@@ -278,13 +280,12 @@ int npages_for_summary_flush(struct f2fs_sb_info *sbi)
                        valid_sum_count += curseg_blkoff(sbi, i);
        }
 
-       total_size_bytes = valid_sum_count * (SUMMARY_SIZE + 1)
-                       + sizeof(struct nat_journal) + 2
-                       + sizeof(struct sit_journal) + 2;
-       sum_space = PAGE_CACHE_SIZE - SUM_FOOTER_SIZE;
-       if (total_size_bytes < sum_space)
+       sum_in_page = (PAGE_CACHE_SIZE - 2 * SUM_JOURNAL_SIZE -
+                       SUM_FOOTER_SIZE) / SUMMARY_SIZE;
+       if (valid_sum_count <= sum_in_page)
                return 1;
-       else if (total_size_bytes < 2 * sum_space)
+       else if ((valid_sum_count - sum_in_page) <=
+               (PAGE_CACHE_SIZE - SUM_FOOTER_SIZE) / SUMMARY_SIZE)
                return 2;
        return 3;
 }
@@ -350,7 +351,7 @@ find_other_zone:
                if (dir == ALLOC_RIGHT) {
                        secno = find_next_zero_bit(free_i->free_secmap,
                                                        TOTAL_SECS(sbi), 0);
-                       BUG_ON(secno >= TOTAL_SECS(sbi));
+                       f2fs_bug_on(secno >= TOTAL_SECS(sbi));
                } else {
                        go_left = 1;
                        left_start = hint - 1;
@@ -366,7 +367,7 @@ find_other_zone:
                }
                left_start = find_next_zero_bit(free_i->free_secmap,
                                                        TOTAL_SECS(sbi), 0);
-               BUG_ON(left_start >= TOTAL_SECS(sbi));
+               f2fs_bug_on(left_start >= TOTAL_SECS(sbi));
                break;
        }
        secno = left_start;
@@ -405,7 +406,7 @@ skip_left:
        }
 got_it:
        /* set it as dirty segment in free segmap */
-       BUG_ON(test_bit(segno, free_i->free_segmap));
+       f2fs_bug_on(test_bit(segno, free_i->free_segmap));
        __set_inuse(sbi, segno);
        *newseg = segno;
        write_unlock(&free_i->segmap_lock);
@@ -550,9 +551,8 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
                change_curseg(sbi, type, true);
        else
                new_curseg(sbi, type, false);
-#ifdef CONFIG_F2FS_STAT_FS
-       sbi->segment_count[curseg->alloc_type]++;
-#endif
+
+       stat_inc_seg_type(sbi, curseg);
 }
 
 void allocate_new_segments(struct f2fs_sb_info *sbi)
@@ -597,6 +597,11 @@ static void f2fs_end_io_write(struct bio *bio, int err)
 
        if (p->is_sync)
                complete(p->wait);
+
+       if (!get_pages(p->sbi, F2FS_WRITEBACK) &&
+                       !list_empty(&p->sbi->cp_wait.task_list))
+               wake_up(&p->sbi->cp_wait);
+
        kfree(p);
        bio_put(bio);
 }
@@ -657,6 +662,7 @@ static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page,
                                block_t blk_addr, enum page_type type)
 {
        struct block_device *bdev = sbi->sb->s_bdev;
+       int bio_blocks;
 
        verify_block_addr(sbi, blk_addr);
 
@@ -676,7 +682,8 @@ retry:
                        goto retry;
                }
 
-               sbi->bio[type] = f2fs_bio_alloc(bdev, max_hw_blocks(sbi));
+               bio_blocks = MAX_BIO_BLOCKS(max_hw_blocks(sbi));
+               sbi->bio[type] = f2fs_bio_alloc(bdev, bio_blocks);
                sbi->bio[type]->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr);
                sbi->bio[type]->bi_private = priv;
                /*
@@ -771,7 +778,7 @@ static int __get_segment_type(struct page *page, enum page_type p_type)
                return __get_segment_type_4(page, p_type);
        }
        /* NR_CURSEG_TYPE(6) logs by default */
-       BUG_ON(sbi->active_logs != NR_CURSEG_TYPE);
+       f2fs_bug_on(sbi->active_logs != NR_CURSEG_TYPE);
        return __get_segment_type_6(page, p_type);
 }
 
@@ -801,9 +808,8 @@ static void do_write_page(struct f2fs_sb_info *sbi, struct page *page,
 
        mutex_lock(&sit_i->sentry_lock);
        __refresh_next_blkoff(sbi, curseg);
-#ifdef CONFIG_F2FS_STAT_FS
-       sbi->block_count[curseg->alloc_type]++;
-#endif
+
+       stat_inc_block_count(sbi, curseg);
 
        /*
         * SIT information should be updated before segment allocation,
@@ -849,7 +855,7 @@ void write_data_page(struct inode *inode, struct page *page,
        struct f2fs_summary sum;
        struct node_info ni;
 
-       BUG_ON(old_blkaddr == NULL_ADDR);
+       f2fs_bug_on(old_blkaddr == NULL_ADDR);
        get_node_info(sbi, dn->nid, &ni);
        set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
 
@@ -1122,8 +1128,6 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr)
                                                SUM_JOURNAL_SIZE);
        written_size += SUM_JOURNAL_SIZE;
 
-       set_page_dirty(page);
-
        /* Step 3: write summary entries */
        for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
                unsigned short blkoff;
@@ -1142,18 +1146,20 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr)
                        summary = (struct f2fs_summary *)(kaddr + written_size);
                        *summary = seg_i->sum_blk->entries[j];
                        written_size += SUMMARY_SIZE;
-                       set_page_dirty(page);
 
                        if (written_size + SUMMARY_SIZE <= PAGE_CACHE_SIZE -
                                                        SUM_FOOTER_SIZE)
                                continue;
 
+                       set_page_dirty(page);
                        f2fs_put_page(page, 1);
                        page = NULL;
                }
        }
-       if (page)
+       if (page) {
+               set_page_dirty(page);
                f2fs_put_page(page, 1);
+       }
 }
 
 static void write_normal_summaries(struct f2fs_sb_info *sbi,
@@ -1239,7 +1245,7 @@ static struct page *get_next_sit_page(struct f2fs_sb_info *sbi,
        /* get current sit block page without lock */
        src_page = get_meta_page(sbi, src_off);
        dst_page = grab_meta_page(sbi, dst_off);
-       BUG_ON(PageDirty(src_page));
+       f2fs_bug_on(PageDirty(src_page));
 
        src_addr = page_address(src_page);
        dst_addr = page_address(dst_page);
@@ -1271,9 +1277,9 @@ static bool flush_sits_in_journal(struct f2fs_sb_info *sbi)
                        __mark_sit_entry_dirty(sbi, segno);
                }
                update_sits_in_cursum(sum, -sits_in_cursum(sum));
-               return 1;
+               return true;
        }
-       return 0;
+       return false;
 }
 
 /*
@@ -1637,6 +1643,7 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
        sm_info->ovp_segments = le32_to_cpu(ckpt->overprov_segment_count);
        sm_info->main_segments = le32_to_cpu(raw_super->segment_count_main);
        sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr);
+       sm_info->rec_prefree_segments = DEF_RECLAIM_PREFREE_SEGMENTS;
 
        err = build_sit_info(sbi);
        if (err)
@@ -1744,6 +1751,8 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi)
 void destroy_segment_manager(struct f2fs_sb_info *sbi)
 {
        struct f2fs_sm_info *sm_info = SM_I(sbi);
+       if (!sm_info)
+               return;
        destroy_dirty_segmap(sbi);
        destroy_curseg(sbi);
        destroy_free_segmap(sbi);
index bdd10eab8c40d7c25fc24eebbeed2a0f705e902b..269f690b4e2492c65bf1a59e9d10302d87725a4e 100644 (file)
@@ -14,6 +14,8 @@
 #define NULL_SEGNO                     ((unsigned int)(~0))
 #define NULL_SECNO                     ((unsigned int)(~0))
 
+#define DEF_RECLAIM_PREFREE_SEGMENTS   100     /* 200MB of prefree segments */
+
 /* L: Logical segment # in volume, R: Relative segment # in main area */
 #define GET_L2R_SEGNO(free_i, segno)   (segno - free_i->start_segno)
 #define GET_R2L_SEGNO(free_i, segno)   (segno + free_i->start_segno)
@@ -90,6 +92,8 @@
        (blk_addr << ((sbi)->log_blocksize - F2FS_LOG_SECTOR_SIZE))
 #define SECTOR_TO_BLOCK(sbi, sectors)                                  \
        (sectors >> ((sbi)->log_blocksize - F2FS_LOG_SECTOR_SIZE))
+#define MAX_BIO_BLOCKS(max_hw_blocks)                                  \
+       (min((int)max_hw_blocks, BIO_MAX_PAGES))
 
 /* during checkpoint, bio_private is used to synchronize the last bio */
 struct bio_private {
@@ -470,6 +474,11 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed)
                                                reserved_sections(sbi)));
 }
 
+static inline bool excess_prefree_segs(struct f2fs_sb_info *sbi)
+{
+       return (prefree_segments(sbi) > SM_I(sbi)->rec_prefree_segments);
+}
+
 static inline int utilization(struct f2fs_sb_info *sbi)
 {
        return div_u64((u64)valid_user_blocks(sbi) * 100, sbi->user_block_count);
@@ -513,16 +522,13 @@ static inline unsigned short curseg_blkoff(struct f2fs_sb_info *sbi, int type)
        return curseg->next_blkoff;
 }
 
+#ifdef CONFIG_F2FS_CHECK_FS
 static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
 {
        unsigned int end_segno = SM_I(sbi)->segment_count - 1;
        BUG_ON(segno > end_segno);
 }
 
-/*
- * This function is used for only debugging.
- * NOTE: In future, we have to remove this function.
- */
 static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
 {
        struct f2fs_sm_info *sm_info = SM_I(sbi);
@@ -541,8 +547,9 @@ static inline void check_block_count(struct f2fs_sb_info *sbi,
 {
        struct f2fs_sm_info *sm_info = SM_I(sbi);
        unsigned int end_segno = sm_info->segment_count - 1;
+       bool is_valid  = test_bit_le(0, raw_sit->valid_map) ? true : false;
        int valid_blocks = 0;
-       int i;
+       int cur_pos = 0, next_pos;
 
        /* check segment usage */
        BUG_ON(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg);
@@ -551,11 +558,26 @@ static inline void check_block_count(struct f2fs_sb_info *sbi,
        BUG_ON(segno > end_segno);
 
        /* check bitmap with valid block count */
-       for (i = 0; i < sbi->blocks_per_seg; i++)
-               if (f2fs_test_bit(i, raw_sit->valid_map))
-                       valid_blocks++;
+       do {
+               if (is_valid) {
+                       next_pos = find_next_zero_bit_le(&raw_sit->valid_map,
+                                       sbi->blocks_per_seg,
+                                       cur_pos);
+                       valid_blocks += next_pos - cur_pos;
+               } else
+                       next_pos = find_next_bit_le(&raw_sit->valid_map,
+                                       sbi->blocks_per_seg,
+                                       cur_pos);
+               cur_pos = next_pos;
+               is_valid = !is_valid;
+       } while (cur_pos < sbi->blocks_per_seg);
        BUG_ON(GET_SIT_VBLOCKS(raw_sit) != valid_blocks);
 }
+#else
+#define check_seg_range(sbi, segno)
+#define verify_block_addr(sbi, blk_addr)
+#define check_block_count(sbi, segno, raw_sit)
+#endif
 
 static inline pgoff_t current_sit_addr(struct f2fs_sb_info *sbi,
                                                unsigned int start)
index 13d0a0fe49dd413ed70d3a10dc864d27bea5c79a..bafff72de8e841afba9d609a8001c71af67f42fc 100644 (file)
@@ -43,7 +43,9 @@ enum {
        Opt_disable_roll_forward,
        Opt_discard,
        Opt_noheap,
+       Opt_user_xattr,
        Opt_nouser_xattr,
+       Opt_acl,
        Opt_noacl,
        Opt_active_logs,
        Opt_disable_ext_identify,
@@ -56,7 +58,9 @@ static match_table_t f2fs_tokens = {
        {Opt_disable_roll_forward, "disable_roll_forward"},
        {Opt_discard, "discard"},
        {Opt_noheap, "no_heap"},
+       {Opt_user_xattr, "user_xattr"},
        {Opt_nouser_xattr, "nouser_xattr"},
+       {Opt_acl, "acl"},
        {Opt_noacl, "noacl"},
        {Opt_active_logs, "active_logs=%u"},
        {Opt_disable_ext_identify, "disable_ext_identify"},
@@ -65,24 +69,40 @@ static match_table_t f2fs_tokens = {
 };
 
 /* Sysfs support for f2fs */
+enum {
+       GC_THREAD,      /* struct f2fs_gc_thread */
+       SM_INFO,        /* struct f2fs_sm_info */
+};
+
 struct f2fs_attr {
        struct attribute attr;
        ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *);
        ssize_t (*store)(struct f2fs_attr *, struct f2fs_sb_info *,
                         const char *, size_t);
+       int struct_type;
        int offset;
 };
 
+static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type)
+{
+       if (struct_type == GC_THREAD)
+               return (unsigned char *)sbi->gc_thread;
+       else if (struct_type == SM_INFO)
+               return (unsigned char *)SM_I(sbi);
+       return NULL;
+}
+
 static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
                        struct f2fs_sb_info *sbi, char *buf)
 {
-       struct f2fs_gc_kthread *gc_kth = sbi->gc_thread;
+       unsigned char *ptr = NULL;
        unsigned int *ui;
 
-       if (!gc_kth)
+       ptr = __struct_ptr(sbi, a->struct_type);
+       if (!ptr)
                return -EINVAL;
 
-       ui = (unsigned int *)(((char *)gc_kth) + a->offset);
+       ui = (unsigned int *)(ptr + a->offset);
 
        return snprintf(buf, PAGE_SIZE, "%u\n", *ui);
 }
@@ -91,15 +111,16 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
                        struct f2fs_sb_info *sbi,
                        const char *buf, size_t count)
 {
-       struct f2fs_gc_kthread *gc_kth = sbi->gc_thread;
+       unsigned char *ptr;
        unsigned long t;
        unsigned int *ui;
        ssize_t ret;
 
-       if (!gc_kth)
+       ptr = __struct_ptr(sbi, a->struct_type);
+       if (!ptr)
                return -EINVAL;
 
-       ui = (unsigned int *)(((char *)gc_kth) + a->offset);
+       ui = (unsigned int *)(ptr + a->offset);
 
        ret = kstrtoul(skip_spaces(buf), 0, &t);
        if (ret < 0)
@@ -135,21 +156,25 @@ static void f2fs_sb_release(struct kobject *kobj)
        complete(&sbi->s_kobj_unregister);
 }
 
-#define F2FS_ATTR_OFFSET(_name, _mode, _show, _store, _elname) \
+#define F2FS_ATTR_OFFSET(_struct_type, _name, _mode, _show, _store, _offset) \
 static struct f2fs_attr f2fs_attr_##_name = {                  \
        .attr = {.name = __stringify(_name), .mode = _mode },   \
        .show   = _show,                                        \
        .store  = _store,                                       \
-       .offset = offsetof(struct f2fs_gc_kthread, _elname),    \
+       .struct_type = _struct_type,                            \
+       .offset = _offset                                       \
 }
 
-#define F2FS_RW_ATTR(name, elname)     \
-       F2FS_ATTR_OFFSET(name, 0644, f2fs_sbi_show, f2fs_sbi_store, elname)
+#define F2FS_RW_ATTR(struct_type, struct_name, name, elname)   \
+       F2FS_ATTR_OFFSET(struct_type, name, 0644,               \
+               f2fs_sbi_show, f2fs_sbi_store,                  \
+               offsetof(struct struct_name, elname))
 
-F2FS_RW_ATTR(gc_min_sleep_time, min_sleep_time);
-F2FS_RW_ATTR(gc_max_sleep_time, max_sleep_time);
-F2FS_RW_ATTR(gc_no_gc_sleep_time, no_gc_sleep_time);
-F2FS_RW_ATTR(gc_idle, gc_idle);
+F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time);
+F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time);
+F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time);
+F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle);
+F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments);
 
 #define ATTR_LIST(name) (&f2fs_attr_##name.attr)
 static struct attribute *f2fs_attrs[] = {
@@ -157,6 +182,7 @@ static struct attribute *f2fs_attrs[] = {
        ATTR_LIST(gc_max_sleep_time),
        ATTR_LIST(gc_no_gc_sleep_time),
        ATTR_LIST(gc_idle),
+       ATTR_LIST(reclaim_segments),
        NULL,
 };
 
@@ -237,6 +263,9 @@ static int parse_options(struct super_block *sb, char *options)
                        set_opt(sbi, NOHEAP);
                        break;
 #ifdef CONFIG_F2FS_FS_XATTR
+               case Opt_user_xattr:
+                       set_opt(sbi, XATTR_USER);
+                       break;
                case Opt_nouser_xattr:
                        clear_opt(sbi, XATTR_USER);
                        break;
@@ -244,6 +273,10 @@ static int parse_options(struct super_block *sb, char *options)
                        set_opt(sbi, INLINE_XATTR);
                        break;
 #else
+               case Opt_user_xattr:
+                       f2fs_msg(sb, KERN_INFO,
+                               "user_xattr options not supported");
+                       break;
                case Opt_nouser_xattr:
                        f2fs_msg(sb, KERN_INFO,
                                "nouser_xattr options not supported");
@@ -254,10 +287,16 @@ static int parse_options(struct super_block *sb, char *options)
                        break;
 #endif
 #ifdef CONFIG_F2FS_FS_POSIX_ACL
+               case Opt_acl:
+                       set_opt(sbi, POSIX_ACL);
+                       break;
                case Opt_noacl:
                        clear_opt(sbi, POSIX_ACL);
                        break;
 #else
+               case Opt_acl:
+                       f2fs_msg(sb, KERN_INFO, "acl options not supported");
+                       break;
                case Opt_noacl:
                        f2fs_msg(sb, KERN_INFO, "noacl options not supported");
                        break;
@@ -355,7 +394,9 @@ static void f2fs_put_super(struct super_block *sb)
        f2fs_destroy_stats(sbi);
        stop_gc_thread(sbi);
 
-       write_checkpoint(sbi, true);
+       /* We don't need to do checkpoint when it's clean */
+       if (sbi->s_dirty && get_pages(sbi, F2FS_DIRTY_NODES))
+               write_checkpoint(sbi, true);
 
        iput(sbi->node_inode);
        iput(sbi->meta_inode);
@@ -727,30 +768,47 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
                atomic_set(&sbi->nr_pages[i], 0);
 }
 
-static int validate_superblock(struct super_block *sb,
-               struct f2fs_super_block **raw_super,
-               struct buffer_head **raw_super_buf, sector_t block)
+/*
+ * Read f2fs raw super block.
+ * Because we have two copies of super block, so read the first one at first,
+ * if the first one is invalid, move to read the second one.
+ */
+static int read_raw_super_block(struct super_block *sb,
+                       struct f2fs_super_block **raw_super,
+                       struct buffer_head **raw_super_buf)
 {
-       const char *super = (block == 0 ? "first" : "second");
+       int block = 0;
 
-       /* read f2fs raw super block */
+retry:
        *raw_super_buf = sb_bread(sb, block);
        if (!*raw_super_buf) {
-               f2fs_msg(sb, KERN_ERR, "unable to read %s superblock",
-                               super);
-               return -EIO;
+               f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock",
+                               block + 1);
+               if (block == 0) {
+                       block++;
+                       goto retry;
+               } else {
+                       return -EIO;
+               }
        }
 
        *raw_super = (struct f2fs_super_block *)
                ((char *)(*raw_super_buf)->b_data + F2FS_SUPER_OFFSET);
 
        /* sanity checking of raw super */
-       if (!sanity_check_raw_super(sb, *raw_super))
-               return 0;
+       if (sanity_check_raw_super(sb, *raw_super)) {
+               brelse(*raw_super_buf);
+               f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem "
+                               "in %dth superblock", block + 1);
+               if(block == 0) {
+                       block++;
+                       goto retry;
+               } else {
+                       return -EINVAL;
+               }
+       }
 
-       f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem "
-                               "in %s superblock", super);
-       return -EINVAL;
+       return 0;
 }
 
 static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
@@ -760,7 +818,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        struct buffer_head *raw_super_buf;
        struct inode *root;
        long err = -EINVAL;
-       int i;
 
        /* allocate memory for f2fs-specific super block info */
        sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL);
@@ -773,14 +830,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
                goto free_sbi;
        }
 
-       err = validate_superblock(sb, &raw_super, &raw_super_buf, 0);
-       if (err) {
-               brelse(raw_super_buf);
-               /* check secondary superblock when primary failed */
-               err = validate_superblock(sb, &raw_super, &raw_super_buf, 1);
-               if (err)
-                       goto free_sb_buf;
-       }
+       err = read_raw_super_block(sb, &raw_super, &raw_super_buf);
+       if (err)
+               goto free_sbi;
+
        sb->s_fs_info = sbi;
        /* init some FS parameters */
        sbi->active_logs = NR_CURSEG_TYPE;
@@ -818,12 +871,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        mutex_init(&sbi->gc_mutex);
        mutex_init(&sbi->writepages);
        mutex_init(&sbi->cp_mutex);
-       for (i = 0; i < NR_GLOBAL_LOCKS; i++)
-               mutex_init(&sbi->fs_lock[i]);
        mutex_init(&sbi->node_write);
-       sbi->por_doing = 0;
+       sbi->por_doing = false;
        spin_lock_init(&sbi->stat_lock);
        init_rwsem(&sbi->bio_sem);
+       init_rwsem(&sbi->cp_rwsem);
+       init_waitqueue_head(&sbi->cp_wait);
        init_sb_info(sbi);
 
        /* get an inode for meta space */
@@ -922,12 +975,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
                /* After POR, we can run background GC thread.*/
                err = start_gc_thread(sbi);
                if (err)
-                       goto fail;
+                       goto free_gc;
        }
 
        err = f2fs_build_stats(sbi);
        if (err)
-               goto fail;
+               goto free_gc;
 
        if (f2fs_proc_root)
                sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root);
@@ -953,6 +1006,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 
        return 0;
 fail:
+       if (sbi->s_proc) {
+               remove_proc_entry("segment_info", sbi->s_proc);
+               remove_proc_entry(sb->s_id, f2fs_proc_root);
+       }
+       f2fs_destroy_stats(sbi);
+free_gc:
        stop_gc_thread(sbi);
 free_root_inode:
        dput(sb->s_root);
index 1ac8a5f6e38096a702c62d2520b5b001a87f9fa2..aa7a3f139fe5336130d10dcfbe9813fa7ca95698 100644 (file)
@@ -154,6 +154,9 @@ static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name,
 }
 
 #ifdef CONFIG_F2FS_FS_SECURITY
+static int __f2fs_setxattr(struct inode *inode, int name_index,
+                       const char *name, const void *value, size_t value_len,
+                       struct page *ipage);
 static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
                void *page)
 {
@@ -161,7 +164,7 @@ static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
        int err = 0;
 
        for (xattr = xattr_array; xattr->name != NULL; xattr++) {
-               err = f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY,
+               err = __f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY,
                                xattr->name, xattr->value,
                                xattr->value_len, (struct page *)page);
                if (err < 0)
@@ -369,7 +372,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
                        alloc_nid_failed(sbi, new_nid);
                        return PTR_ERR(xpage);
                }
-               BUG_ON(new_nid);
+               f2fs_bug_on(new_nid);
        } else {
                struct dnode_of_data dn;
                set_new_dnode(&dn, inode, NULL, NULL, new_nid);
@@ -469,16 +472,15 @@ cleanup:
        return error;
 }
 
-int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
-                       const void *value, size_t value_len, struct page *ipage)
+static int __f2fs_setxattr(struct inode *inode, int name_index,
+                       const char *name, const void *value, size_t value_len,
+                       struct page *ipage)
 {
-       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct f2fs_inode_info *fi = F2FS_I(inode);
        struct f2fs_xattr_entry *here, *last;
        void *base_addr;
        int found, newsize;
        size_t name_len;
-       int ilock;
        __u32 new_hsize;
        int error = -ENOMEM;
 
@@ -493,10 +495,6 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
        if (name_len > F2FS_NAME_LEN || value_len > MAX_VALUE_LEN(inode))
                return -ERANGE;
 
-       f2fs_balance_fs(sbi);
-
-       ilock = mutex_lock_op(sbi);
-
        base_addr = read_all_xattrs(inode, ipage);
        if (!base_addr)
                goto exit;
@@ -522,7 +520,7 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
                 */
                free = MIN_OFFSET(inode) - ((char *)last - (char *)base_addr);
                if (found)
-                       free = free - ENTRY_SIZE(here);
+                       free = free + ENTRY_SIZE(here);
 
                if (free < newsize) {
                        error = -ENOSPC;
@@ -578,7 +576,21 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
        else
                update_inode_page(inode);
 exit:
-       mutex_unlock_op(sbi, ilock);
        kzfree(base_addr);
        return error;
 }
+
+int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
+                       const void *value, size_t value_len, struct page *ipage)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       int err;
+
+       f2fs_balance_fs(sbi);
+
+       f2fs_lock_op(sbi);
+       err = __f2fs_setxattr(inode, name_index, name, value, value_len, ipage);
+       f2fs_unlock_op(sbi);
+
+       return err;
+}
index 52ae54828eda4eb905023124a9b2d4c5cb500226..e0dc355fa3179658a2b99660fd6fca0ca0a80937 100644 (file)
                { CURSEG_COLD_NODE,     "Cold NODE" },                  \
                { NO_CHECK_TYPE,        "No TYPE" })
 
+#define show_file_type(type)                                           \
+       __print_symbolic(type,                                          \
+               { 0,            "FILE" },                               \
+               { 1,            "DIR" })
+
 #define show_gc_type(type)                                             \
        __print_symbolic(type,                                          \
                { FG_GC,        "Foreground GC" },                      \
@@ -623,6 +628,52 @@ TRACE_EVENT(f2fs_do_submit_bio,
                __entry->size)
 );
 
+DECLARE_EVENT_CLASS(f2fs__page,
+
+       TP_PROTO(struct page *page, int type),
+
+       TP_ARGS(page, type),
+
+       TP_STRUCT__entry(
+               __field(dev_t,  dev)
+               __field(ino_t,  ino)
+               __field(int, type)
+               __field(int, dir)
+               __field(pgoff_t, index)
+               __field(int, dirty)
+       ),
+
+       TP_fast_assign(
+               __entry->dev    = page->mapping->host->i_sb->s_dev;
+               __entry->ino    = page->mapping->host->i_ino;
+               __entry->type   = type;
+               __entry->dir    = S_ISDIR(page->mapping->host->i_mode);
+               __entry->index  = page->index;
+               __entry->dirty  = PageDirty(page);
+       ),
+
+       TP_printk("dev = (%d,%d), ino = %lu, %s, %s, index = %lu, dirty = %d",
+               show_dev_ino(__entry),
+               show_block_type(__entry->type),
+               show_file_type(__entry->dir),
+               (unsigned long)__entry->index,
+               __entry->dirty)
+);
+
+DEFINE_EVENT(f2fs__page, f2fs_set_page_dirty,
+
+       TP_PROTO(struct page *page, int type),
+
+       TP_ARGS(page, type)
+);
+
+DEFINE_EVENT(f2fs__page, f2fs_vm_page_mkwrite,
+
+       TP_PROTO(struct page *page, int type),
+
+       TP_ARGS(page, type)
+);
+
 TRACE_EVENT(f2fs_submit_write_page,
 
        TP_PROTO(struct page *page, block_t blk_addr, int type),