]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/lightnvm/pblk.h
lightnvm: pblk: verify that cache read is still valid
[karo-tx-linux.git] / drivers / lightnvm / pblk.h
index 99f3186b5288b64f19ee46b67fb9bb3190311f40..15931381348c70c255f4d6d38ab00fe143dc8554 100644 (file)
 #define PBLK_MAX_REQ_ADDRS (64)
 #define PBLK_MAX_REQ_ADDRS_PW (6)
 
+#define PBLK_WS_POOL_SIZE (128)
+#define PBLK_META_POOL_SIZE (128)
+#define PBLK_READ_REQ_POOL_SIZE (1024)
+
+#define PBLK_NR_CLOSE_JOBS (4)
+
 #define PBLK_CACHE_NAME_LEN (DISK_NAME_LEN + 16)
 
 #define PBLK_COMMAND_TIMEOUT_MS 30000
@@ -72,11 +78,15 @@ enum {
        PBLK_BLK_ST_CLOSED =    0x2,
 };
 
+struct pblk_sec_meta {
+       u64 reserved;
+       __le64 lba;
+};
+
 /* The number of GC lists and the rate-limiter states go together. This way the
  * rate-limiter can dictate how much GC is needed based on resource utilization.
  */
-#define PBLK_NR_GC_LISTS 3
-#define PBLK_MAX_GC_JOBS 32
+#define PBLK_GC_NR_LISTS 3
 
 enum {
        PBLK_RL_HIGH = 1,
@@ -84,14 +94,9 @@ enum {
        PBLK_RL_LOW = 3,
 };
 
-struct pblk_sec_meta {
-       u64 reserved;
-       __le64 lba;
-};
-
 #define pblk_dma_meta_size (sizeof(struct pblk_sec_meta) * PBLK_MAX_REQ_ADDRS)
 
-/* write completion context */
+/* write buffer completion context */
 struct pblk_c_ctx {
        struct list_head list;          /* Head for out-of-order completion */
 
@@ -101,9 +106,16 @@ struct pblk_c_ctx {
        unsigned int nr_padded;
 };
 
-/* Read context */
-struct pblk_r_ctx {
-       struct bio *orig_bio;
+/* generic context */
+struct pblk_g_ctx {
+       void *private;
+};
+
+/* Pad context */
+struct pblk_pad_rq {
+       struct pblk *pblk;
+       struct completion wait;
+       struct kref ref;
 };
 
 /* Recovery context */
@@ -195,29 +207,39 @@ struct pblk_lun {
 struct pblk_gc_rq {
        struct pblk_line *line;
        void *data;
-       u64 *lba_list;
+       u64 lba_list[PBLK_MAX_REQ_ADDRS];
        int nr_secs;
        int secs_to_gc;
        struct list_head list;
 };
 
 struct pblk_gc {
+       /* These states are not protected by a lock since (i) they are in the
+        * fast path, and (ii) they are not critical.
+        */
        int gc_active;
        int gc_enabled;
        int gc_forced;
-       int gc_jobs_active;
-       atomic_t inflight_gc;
 
        struct task_struct *gc_ts;
        struct task_struct *gc_writer_ts;
+       struct task_struct *gc_reader_ts;
+
+       struct workqueue_struct *gc_line_reader_wq;
        struct workqueue_struct *gc_reader_wq;
+
        struct timer_list gc_timer;
 
+       struct semaphore gc_sem;
+       atomic_t inflight_gc;
        int w_entries;
+
        struct list_head w_list;
+       struct list_head r_list;
 
        spinlock_t lock;
        spinlock_t w_lock;
+       spinlock_t r_lock;
 };
 
 struct pblk_rl {
@@ -229,10 +251,8 @@ struct pblk_rl {
                                 */
        unsigned int high_pw;   /* High rounded up as a power of 2 */
 
-#define PBLK_USER_HIGH_THRS 2  /* Begin write limit at 50 percent
-                                * available blks
-                                */
-#define PBLK_USER_LOW_THRS 20  /* Aggressive GC at 5% available blocks */
+#define PBLK_USER_HIGH_THRS 8  /* Begin write limit at 12% available blks */
+#define PBLK_USER_LOW_THRS 10  /* Aggressive GC at 10% available blocks */
 
        int rb_windows_pw;      /* Number of rate windows in the write buffer
                                 * given as a power-of-2. This guarantees that
@@ -244,13 +264,19 @@ struct pblk_rl {
                                 */
        int rb_budget;          /* Total number of entries available for I/O */
        int rb_user_max;        /* Max buffer entries available for user I/O */
-       atomic_t rb_user_cnt;   /* User I/O buffer counter */
        int rb_gc_max;          /* Max buffer entries available for GC I/O */
        int rb_gc_rsv;          /* Reserved buffer entries for GC I/O */
        int rb_state;           /* Rate-limiter current state */
+
+       atomic_t rb_user_cnt;   /* User I/O buffer counter */
        atomic_t rb_gc_cnt;     /* GC I/O buffer counter */
+       atomic_t rb_space;      /* Space limit in case of reaching capacity */
+
+       int rsv_blocks;         /* Reserved blocks for GC */
 
        int rb_user_active;
+       int rb_gc_active;
+
        struct timer_list u_timer;
 
        unsigned long long nr_secs;
@@ -258,8 +284,6 @@ struct pblk_rl {
        atomic_t free_blocks;
 };
 
-#define PBLK_LINE_NR_LUN_BITMAP 2
-#define PBLK_LINE_NR_SEC_BITMAP 2
 #define PBLK_LINE_EMPTY (~0U)
 
 enum {
@@ -310,16 +334,19 @@ struct line_smeta {
        __le32 window_wr_lun;   /* Number of parallel LUNs to write */
 
        __le32 rsvd[2];
+
+       __le64 lun_bitmap[];
 };
 
 /*
- * Metadata Layout:
- *     1. struct pblk_emeta
- *     2. nr_lbas u64 forming lba list
- *     3. nr_lines (all) u32 valid sector count (vsc) (~0U: non-alloc line)
- *     4. nr_luns bits (u64 format) forming line bad block bitmap
- *
- *     3. and 4. will be part of FTL log
+ * Metadata layout in media:
+ *     First sector:
+ *             1. struct line_emeta
+ *             2. bad block bitmap (u64 * window_wr_lun)
+ *     Mid sectors (start at lbas_sector):
+ *             3. nr_lbas (u64) forming lba list
+ *     Last sectors (start at vsc_sector):
+ *             4. u32 valid sector count (vsc) for all lines (~0U: free line)
  */
 struct line_emeta {
        struct line_header header;
@@ -339,6 +366,23 @@ struct line_emeta {
        __le32 next_id;         /* Line id for next line */
        __le64 nr_lbas;         /* Number of lbas mapped in line */
        __le64 nr_valid_lbas;   /* Number of valid lbas mapped in line */
+       __le64 bb_bitmap[];     /* Updated bad block bitmap for line */
+};
+
+struct pblk_emeta {
+       struct line_emeta *buf;         /* emeta buffer in media format */
+       int mem;                        /* Write offset - points to next
+                                        * writable entry in memory
+                                        */
+       atomic_t sync;                  /* Synced - backpointer that signals the
+                                        * last entry that has been successfully
+                                        * persisted to media
+                                        */
+       unsigned int nr_entries;        /* Number of emeta entries */
+};
+
+struct pblk_smeta {
+       struct line_smeta *buf;         /* smeta buffer in persistent format */
 };
 
 struct pblk_line {
@@ -355,9 +399,12 @@ struct pblk_line {
 
        unsigned long *lun_bitmap;      /* Bitmap for LUNs mapped in line */
 
-       struct line_smeta *smeta;       /* Start metadata */
-       struct line_emeta *emeta;       /* End metadata */
+       struct pblk_smeta *smeta;       /* Start metadata */
+       struct pblk_emeta *emeta;       /* End medatada */
+
        int meta_line;                  /* Metadata line id */
+       int meta_distance;              /* Distance between data and metadata */
+
        u64 smeta_ssec;                 /* Sector where smeta starts */
        u64 emeta_ssec;                 /* Sector where emeta starts */
 
@@ -374,9 +421,10 @@ struct pblk_line {
        atomic_t left_seblks;           /* Blocks left for sync erasing */
 
        int left_msecs;                 /* Sectors left for mapping */
-       int left_ssecs;                 /* Sectors left to sync */
        unsigned int cur_sec;           /* Sector map pointer */
-       unsigned int vsc;               /* Valid sector count in line */
+       unsigned int nr_valid_lbas;     /* Number of valid lbas in line */
+
+       __le32 *vsc;                    /* Valid sector count in line */
 
        struct kref ref;                /* Write buffer L2P references */
 
@@ -385,13 +433,15 @@ struct pblk_line {
 
 #define PBLK_DATA_LINES 4
 
-enum{
+enum {
        PBLK_KMALLOC_META = 1,
        PBLK_VMALLOC_META = 2,
 };
 
-struct pblk_line_metadata {
-       void *meta;
+enum {
+       PBLK_EMETA_TYPE_HEADER = 1,     /* struct line_emeta first sector */
+       PBLK_EMETA_TYPE_LLBA = 2,       /* lba list - type: __le64 */
+       PBLK_EMETA_TYPE_VSC = 3,        /* vsc list - type: __le32 */
 };
 
 struct pblk_line_mgmt {
@@ -404,7 +454,7 @@ struct pblk_line_mgmt {
        struct list_head bad_list;      /* Full lines bad */
 
        /* GC lists - use gc_lock */
-       struct list_head *gc_lists[PBLK_NR_GC_LISTS];
+       struct list_head *gc_lists[PBLK_GC_NR_LISTS];
        struct list_head gc_high_list;  /* Full lines ready to GC, high isc */
        struct list_head gc_mid_list;   /* Full lines ready to GC, mid isc */
        struct list_head gc_low_list;   /* Full lines ready to GC, low isc */
@@ -417,13 +467,16 @@ struct pblk_line_mgmt {
        struct pblk_line *log_next;     /* Next FTL log line */
        struct pblk_line *data_next;    /* Next data line */
 
+       struct list_head emeta_list;    /* Lines queued to schedule emeta */
+
+       __le32 *vsc_list;               /* Valid sector counts for all lines */
+
        /* Metadata allocation type: VMALLOC | KMALLOC */
-       int smeta_alloc_type;
        int emeta_alloc_type;
 
        /* Pre-allocated metadata for data lines */
-       struct pblk_line_metadata sline_meta[PBLK_DATA_LINES];
-       struct pblk_line_metadata eline_meta[PBLK_DATA_LINES];
+       struct pblk_smeta *sline_meta[PBLK_DATA_LINES];
+       struct pblk_emeta *eline_meta[PBLK_DATA_LINES];
        unsigned long meta_bitmap;
 
        /* Helpers for fast bitmap calculations */
@@ -434,25 +487,40 @@ struct pblk_line_mgmt {
        unsigned long l_seq_nr;         /* Log line unique sequence number */
 
        spinlock_t free_lock;
+       spinlock_t close_lock;
        spinlock_t gc_lock;
 };
 
 struct pblk_line_meta {
        unsigned int smeta_len;         /* Total length for smeta */
-       unsigned int smeta_sec;         /* Sectors needed for smeta*/
-       unsigned int emeta_len;         /* Total length for emeta */
-       unsigned int emeta_sec;         /* Sectors needed for emeta*/
+       unsigned int smeta_sec;         /* Sectors needed for smeta */
+
+       unsigned int emeta_len[4];      /* Lengths for emeta:
+                                        *  [0]: Total length
+                                        *  [1]: struct line_emeta length
+                                        *  [2]: L2P portion length
+                                        *  [3]: vsc list length
+                                        */
+       unsigned int emeta_sec[4];      /* Sectors needed for emeta. Same layout
+                                        * as emeta_len
+                                        */
+
        unsigned int emeta_bb;          /* Boundary for bb that affects emeta */
+
+       unsigned int vsc_list_len;      /* Length for vsc list */
        unsigned int sec_bitmap_len;    /* Length for sector bitmap in line */
        unsigned int blk_bitmap_len;    /* Length for block bitmap in line */
        unsigned int lun_bitmap_len;    /* Length for lun bitmap in line */
 
        unsigned int blk_per_line;      /* Number of blocks in a full line */
        unsigned int sec_per_line;      /* Number of sectors in a line */
+       unsigned int dsec_per_line;     /* Number of data sectors in a line */
        unsigned int min_blk_line;      /* Min. number of good blocks in line */
 
        unsigned int mid_thrs;          /* Threshold for GC mid list */
        unsigned int high_thrs;         /* Threshold for GC high list */
+
+       unsigned int meta_distance;     /* Distance between data and metadata */
 };
 
 struct pblk_addr_format {
@@ -470,6 +538,13 @@ struct pblk_addr_format {
        u8      sec_offset;
 };
 
+enum {
+       PBLK_STATE_RUNNING = 0,
+       PBLK_STATE_STOPPING = 1,
+       PBLK_STATE_RECOVERING = 2,
+       PBLK_STATE_STOPPED = 3,
+};
+
 struct pblk {
        struct nvm_tgt_dev *dev;
        struct gendisk *disk;
@@ -487,6 +562,8 @@ struct pblk {
 
        struct pblk_rb rwb;
 
+       int state;                      /* pblk line state */
+
        int min_write_pgs; /* Minimum amount of pages required by controller */
        int max_write_pgs; /* Maximum amount of pages supported by controller */
        int pgs_in_buffer; /* Number of pages that need to be held in buffer to
@@ -499,7 +576,7 @@ struct pblk {
        /* pblk provisioning values. Used by rate limiter */
        struct pblk_rl rl;
 
-       struct semaphore erase_sem;
+       int sec_per_write;
 
        unsigned char instance_uuid[16];
 #ifdef CONFIG_NVM_DEBUG
@@ -511,8 +588,8 @@ struct pblk {
        atomic_long_t req_writes;       /* Sectors stored on write buffer */
        atomic_long_t sub_writes;       /* Sectors submitted from buffer */
        atomic_long_t sync_writes;      /* Sectors synced to media */
-       atomic_long_t compl_writes;     /* Sectors completed in write bio */
        atomic_long_t inflight_reads;   /* Inflight sector read requests */
+       atomic_long_t cache_reads;      /* Read requests that hit the cache */
        atomic_long_t sync_reads;       /* Completed sector read requests */
        atomic_long_t recov_writes;     /* Sectors submitted from recovery */
        atomic_long_t recov_gc_writes;  /* Sectors submitted from write GC */
@@ -528,6 +605,8 @@ struct pblk {
        atomic_long_t write_failed;
        atomic_long_t erase_failed;
 
+       atomic_t inflight_io;           /* General inflight I/O counter */
+
        struct task_struct *writer_ts;
 
        /* Simple translation map of logical addresses to physical addresses.
@@ -542,11 +621,13 @@ struct pblk {
        mempool_t *page_pool;
        mempool_t *line_ws_pool;
        mempool_t *rec_pool;
-       mempool_t *r_rq_pool;
+       mempool_t *g_rq_pool;
        mempool_t *w_rq_pool;
        mempool_t *line_meta_pool;
 
-       struct workqueue_struct *kw_wq;
+       struct workqueue_struct *close_wq;
+       struct workqueue_struct *bb_wq;
+
        struct timer_list wtimer;
 
        struct pblk_gc gc;
@@ -559,7 +640,7 @@ struct pblk_line_ws {
        struct work_struct ws;
 };
 
-#define pblk_r_rq_size (sizeof(struct nvm_rq) + sizeof(struct pblk_r_ctx))
+#define pblk_g_rq_size (sizeof(struct nvm_rq) + sizeof(struct pblk_g_ctx))
 #define pblk_w_rq_size (sizeof(struct nvm_rq) + sizeof(struct pblk_c_ctx))
 
 /*
@@ -579,18 +660,17 @@ void pblk_rb_write_entry_gc(struct pblk_rb *rb, void *data,
                            struct pblk_w_ctx w_ctx, struct pblk_line *gc_line,
                            unsigned int pos);
 struct pblk_w_ctx *pblk_rb_w_ctx(struct pblk_rb *rb, unsigned int pos);
+void pblk_rb_flush(struct pblk_rb *rb);
 
 void pblk_rb_sync_l2p(struct pblk_rb *rb);
-unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct bio *bio,
-                                struct pblk_c_ctx *c_ctx,
-                                unsigned int pos,
-                                unsigned int nr_entries,
-                                unsigned int count);
+unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct nvm_rq *rqd,
+                                struct bio *bio, unsigned int pos,
+                                unsigned int nr_entries, unsigned int count);
 unsigned int pblk_rb_read_to_bio_list(struct pblk_rb *rb, struct bio *bio,
                                      struct list_head *list,
                                      unsigned int max);
 int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba,
-                       u64 pos, int bio_iter);
+                       struct ppa_addr ppa, int bio_iter);
 unsigned int pblk_rb_read_commit(struct pblk_rb *rb, unsigned int entries);
 
 unsigned int pblk_rb_sync_init(struct pblk_rb *rb, unsigned long *flags);
@@ -601,6 +681,7 @@ void pblk_rb_sync_end(struct pblk_rb *rb, unsigned long *flags);
 unsigned int pblk_rb_sync_point_count(struct pblk_rb *rb);
 
 unsigned int pblk_rb_read_count(struct pblk_rb *rb);
+unsigned int pblk_rb_sync_count(struct pblk_rb *rb);
 unsigned int pblk_rb_wrap_pos(struct pblk_rb *rb, unsigned int pos);
 
 int pblk_rb_tear_down_check(struct pblk_rb *rb);
@@ -612,40 +693,50 @@ ssize_t pblk_rb_sysfs(struct pblk_rb *rb, char *buf);
  * pblk core
  */
 struct nvm_rq *pblk_alloc_rqd(struct pblk *pblk, int rw);
+void pblk_set_sec_per_write(struct pblk *pblk, int sec_per_write);
 int pblk_setup_w_rec_rq(struct pblk *pblk, struct nvm_rq *rqd,
                        struct pblk_c_ctx *c_ctx);
 void pblk_free_rqd(struct pblk *pblk, struct nvm_rq *rqd, int rw);
-void pblk_flush_writer(struct pblk *pblk);
+void pblk_wait_for_meta(struct pblk *pblk);
 struct ppa_addr pblk_get_lba_map(struct pblk *pblk, sector_t lba);
 void pblk_discard(struct pblk *pblk, struct bio *bio);
 void pblk_log_write_err(struct pblk *pblk, struct nvm_rq *rqd);
 void pblk_log_read_err(struct pblk *pblk, struct nvm_rq *rqd);
 int pblk_submit_io(struct pblk *pblk, struct nvm_rq *rqd);
+int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line);
 struct bio *pblk_bio_map_addr(struct pblk *pblk, void *data,
                              unsigned int nr_secs, unsigned int len,
-                             gfp_t gfp_mask);
+                             int alloc_type, gfp_t gfp_mask);
 struct pblk_line *pblk_line_get(struct pblk *pblk);
 struct pblk_line *pblk_line_get_first_data(struct pblk *pblk);
-struct pblk_line *pblk_line_replace_data(struct pblk *pblk);
+void pblk_line_replace_data(struct pblk *pblk);
 int pblk_line_recov_alloc(struct pblk *pblk, struct pblk_line *line);
 void pblk_line_recov_close(struct pblk *pblk, struct pblk_line *line);
 struct pblk_line *pblk_line_get_data(struct pblk *pblk);
-struct pblk_line *pblk_line_get_data_next(struct pblk *pblk);
+struct pblk_line *pblk_line_get_erase(struct pblk *pblk);
 int pblk_line_erase(struct pblk *pblk, struct pblk_line *line);
 int pblk_line_is_full(struct pblk_line *line);
 void pblk_line_free(struct pblk *pblk, struct pblk_line *line);
-void pblk_line_close_ws(struct work_struct *work);
+void pblk_line_close_meta(struct pblk *pblk, struct pblk_line *line);
 void pblk_line_close(struct pblk *pblk, struct pblk_line *line);
+void pblk_line_close_meta_sync(struct pblk *pblk);
+void pblk_line_close_ws(struct work_struct *work);
+void pblk_pipeline_stop(struct pblk *pblk);
 void pblk_line_mark_bb(struct work_struct *work);
 void pblk_line_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv,
-                     void (*work)(struct work_struct *));
+                     void (*work)(struct work_struct *),
+                     struct workqueue_struct *wq);
 u64 pblk_line_smeta_start(struct pblk *pblk, struct pblk_line *line);
 int pblk_line_read_smeta(struct pblk *pblk, struct pblk_line *line);
-int pblk_line_read_emeta(struct pblk *pblk, struct pblk_line *line);
+int pblk_line_read_emeta(struct pblk *pblk, struct pblk_line *line,
+                        void *emeta_buf);
 int pblk_blk_erase_async(struct pblk *pblk, struct ppa_addr erase_ppa);
 void pblk_line_put(struct kref *ref);
 struct list_head *pblk_line_gc_list(struct pblk *pblk, struct pblk_line *line);
+u64 pblk_lookup_page(struct pblk *pblk, struct pblk_line *line);
+void pblk_dealloc_page(struct pblk *pblk, struct pblk_line *line, int nr_secs);
 u64 pblk_alloc_page(struct pblk *pblk, struct pblk_line *line, int nr_secs);
+u64 __pblk_alloc_page(struct pblk *pblk, struct pblk_line *line, int nr_secs);
 int pblk_calc_secs(struct pblk *pblk, unsigned long secs_avail,
                   unsigned long secs_to_flush);
 void pblk_down_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas,
@@ -656,11 +747,11 @@ void pblk_end_bio_sync(struct bio *bio);
 void pblk_end_io_sync(struct nvm_rq *rqd);
 int pblk_bio_add_pages(struct pblk *pblk, struct bio *bio, gfp_t flags,
                       int nr_pages);
-void pblk_map_pad_invalidate(struct pblk *pblk, struct pblk_line *line,
-                            u64 paddr);
 void pblk_bio_free_pages(struct pblk *pblk, struct bio *bio, int off,
                         int nr_pages);
 void pblk_map_invalidate(struct pblk *pblk, struct ppa_addr ppa);
+void __pblk_map_invalidate(struct pblk *pblk, struct pblk_line *line,
+                          u64 paddr);
 void pblk_update_map(struct pblk *pblk, sector_t lba, struct ppa_addr ppa);
 void pblk_update_map_cache(struct pblk *pblk, sector_t lba,
                           struct ppa_addr ppa);
@@ -702,6 +793,7 @@ void pblk_write_should_kick(struct pblk *pblk);
 /*
  * pblk read path
  */
+extern struct bio_set *pblk_bio_set;
 int pblk_submit_read(struct pblk *pblk, struct bio *bio);
 int pblk_submit_read_gc(struct pblk *pblk, u64 *lba_list, void *data,
                        unsigned int nr_secs, unsigned int *secs_to_gc,
@@ -711,7 +803,7 @@ int pblk_submit_read_gc(struct pblk *pblk, u64 *lba_list, void *data,
  */
 void pblk_submit_rec(struct work_struct *work);
 struct pblk_line *pblk_recov_l2p(struct pblk *pblk);
-void pblk_recov_pad(struct pblk *pblk);
+int pblk_recov_pad(struct pblk *pblk);
 __le64 *pblk_recov_get_lba_list(struct pblk *pblk, struct line_emeta *emeta);
 int pblk_recov_setup_rq(struct pblk *pblk, struct pblk_c_ctx *c_ctx,
                        struct pblk_rec_ctx *recovery, u64 *comp_bits,
@@ -720,33 +812,40 @@ int pblk_recov_setup_rq(struct pblk *pblk, struct pblk_c_ctx *c_ctx,
 /*
  * pblk gc
  */
-#define PBLK_GC_TRIES 3
+#define PBLK_GC_MAX_READERS 8  /* Max number of outstanding GC reader jobs */
+#define PBLK_GC_W_QD 128       /* Queue depth for inflight GC write I/Os */
+#define PBLK_GC_L_QD 4         /* Queue depth for inflight GC lines */
+#define PBLK_GC_RSV_LINE 1     /* Reserved lines for GC */
 
 int pblk_gc_init(struct pblk *pblk);
 void pblk_gc_exit(struct pblk *pblk);
 void pblk_gc_should_start(struct pblk *pblk);
 void pblk_gc_should_stop(struct pblk *pblk);
-int pblk_gc_status(struct pblk *pblk);
+void pblk_gc_should_kick(struct pblk *pblk);
+void pblk_gc_kick(struct pblk *pblk);
 void pblk_gc_sysfs_state_show(struct pblk *pblk, int *gc_enabled,
                              int *gc_active);
-void pblk_gc_sysfs_force(struct pblk *pblk, int force);
+int pblk_gc_sysfs_force(struct pblk *pblk, int force);
 
 /*
  * pblk rate limiter
  */
 void pblk_rl_init(struct pblk_rl *rl, int budget);
 void pblk_rl_free(struct pblk_rl *rl);
-int pblk_rl_gc_thrs(struct pblk_rl *rl);
+int pblk_rl_high_thrs(struct pblk_rl *rl);
+int pblk_rl_low_thrs(struct pblk_rl *rl);
 unsigned long pblk_rl_nr_free_blks(struct pblk_rl *rl);
 int pblk_rl_user_may_insert(struct pblk_rl *rl, int nr_entries);
+void pblk_rl_inserted(struct pblk_rl *rl, int nr_entries);
 void pblk_rl_user_in(struct pblk_rl *rl, int nr_entries);
 int pblk_rl_gc_may_insert(struct pblk_rl *rl, int nr_entries);
 void pblk_rl_gc_in(struct pblk_rl *rl, int nr_entries);
 void pblk_rl_out(struct pblk_rl *rl, int nr_user, int nr_gc);
-void pblk_rl_set_gc_rsc(struct pblk_rl *rl, int rsv);
 int pblk_rl_sysfs_rate_show(struct pblk_rl *rl);
 void pblk_rl_free_lines_inc(struct pblk_rl *rl, struct pblk_line *line);
 void pblk_rl_free_lines_dec(struct pblk_rl *rl, struct pblk_line *line);
+void pblk_rl_set_space_limit(struct pblk_rl *rl, int entries_left);
+int pblk_rl_is_limit(struct pblk_rl *rl);
 
 /*
  * pblk sysfs
@@ -774,9 +873,30 @@ static inline struct nvm_rq *nvm_rq_from_c_ctx(void *c_ctx)
        return c_ctx - sizeof(struct nvm_rq);
 }
 
-static inline void *pblk_line_emeta_to_lbas(struct line_emeta *emeta)
+static inline void *emeta_to_bb(struct line_emeta *emeta)
+{
+       return emeta->bb_bitmap;
+}
+
+static inline void *emeta_to_lbas(struct pblk *pblk, struct line_emeta *emeta)
+{
+       return ((void *)emeta + pblk->lm.emeta_len[1]);
+}
+
+static inline void *emeta_to_vsc(struct pblk *pblk, struct line_emeta *emeta)
 {
-       return (emeta) + 1;
+       return (emeta_to_lbas(pblk, emeta) + pblk->lm.emeta_len[2]);
+}
+
+static inline int pblk_line_vsc(struct pblk_line *line)
+{
+       int vsc;
+
+       spin_lock(&line->lock);
+       vsc = le32_to_cpu(*line->vsc);
+       spin_unlock(&line->lock);
+
+       return vsc;
 }
 
 #define NVM_MEM_PAGE_WRITE (8)
@@ -917,6 +1037,14 @@ static inline void pblk_ppa_set_empty(struct ppa_addr *ppa_addr)
        ppa_addr->ppa = ADDR_EMPTY;
 }
 
+static inline bool pblk_ppa_comp(struct ppa_addr lppa, struct ppa_addr rppa)
+{
+       if (lppa.ppa == rppa.ppa)
+               return true;
+
+       return false;
+}
+
 static inline int pblk_addr_in_cache(struct ppa_addr ppa)
 {
        return (ppa.ppa != ADDR_EMPTY && ppa.c.is_cached);
@@ -964,11 +1092,11 @@ static inline struct ppa_addr addr_to_pblk_ppa(struct pblk *pblk, u64 paddr,
 }
 
 static inline u32 pblk_calc_meta_header_crc(struct pblk *pblk,
-                                           struct line_smeta *smeta)
+                                           struct line_header *header)
 {
        u32 crc = ~(u32)0;
 
-       crc = crc32_le(crc, (unsigned char *)smeta + sizeof(crc),
+       crc = crc32_le(crc, (unsigned char *)header + sizeof(crc),
                                sizeof(struct line_header) - sizeof(crc));
 
        return crc;
@@ -996,7 +1124,7 @@ static inline u32 pblk_calc_emeta_crc(struct pblk *pblk,
 
        crc = crc32_le(crc, (unsigned char *)emeta +
                                sizeof(struct line_header) + sizeof(crc),
-                               lm->emeta_len -
+                               lm->emeta_len[0] -
                                sizeof(struct line_header) - sizeof(crc));
 
        return crc;
@@ -1016,9 +1144,27 @@ static inline int pblk_set_progr_mode(struct pblk *pblk, int type)
        return flags;
 }
 
-static inline int pblk_set_read_mode(struct pblk *pblk)
+enum {
+       PBLK_READ_RANDOM        = 0,
+       PBLK_READ_SEQUENTIAL    = 1,
+};
+
+static inline int pblk_set_read_mode(struct pblk *pblk, int type)
+{
+       struct nvm_tgt_dev *dev = pblk->dev;
+       struct nvm_geo *geo = &dev->geo;
+       int flags;
+
+       flags = NVM_IO_SUSPEND | NVM_IO_SCRAMBLE_ENABLE;
+       if (type == PBLK_READ_SEQUENTIAL)
+               flags |= geo->plane_mode >> 1;
+
+       return flags;
+}
+
+static inline int pblk_io_aligned(struct pblk *pblk, int nr_secs)
 {
-       return NVM_IO_SNGL_ACCESS | NVM_IO_SUSPEND | NVM_IO_SCRAMBLE_ENABLE;
+       return !(nr_secs % pblk->min_write_pgs);
 }
 
 #ifdef CONFIG_NVM_DEBUG