]> 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 3fe8b05e3de01b886c54c0b19e09459250dc943f..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,11 +94,6 @@ 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 buffer completion context */
@@ -106,6 +111,13 @@ struct pblk_g_ctx {
        void *private;
 };
 
+/* Pad context */
+struct pblk_pad_rq {
+       struct pblk *pblk;
+       struct completion wait;
+       struct kref ref;
+};
+
 /* Recovery context */
 struct pblk_rec_ctx {
        struct pblk *pblk;
@@ -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;
@@ -428,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 */
@@ -512,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;
@@ -529,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
@@ -570,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.
@@ -588,7 +625,9 @@ struct pblk {
        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;
@@ -621,6 +660,7 @@ 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 nvm_rq *rqd,
@@ -630,7 +670,7 @@ 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);
@@ -641,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);
@@ -656,7 +697,7 @@ 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);
@@ -665,10 +706,10 @@ 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);
@@ -678,10 +719,13 @@ int pblk_line_is_full(struct pblk_line *line);
 void pblk_line_free(struct pblk *pblk, struct pblk_line *line);
 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,
@@ -759,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,
@@ -768,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
@@ -837,6 +888,17 @@ static inline void *emeta_to_vsc(struct pblk *pblk, struct line_emeta *emeta)
        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)
 
 static inline int pblk_pad_distance(struct pblk *pblk)
@@ -975,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);