读书人

linux内核源码翻阅之facebook硬盘加速

发布时间: 2013-09-23 11:26:10 作者: rapoo

linux内核源码阅读之facebook硬盘加速flashcache之八

前面我们的分析中重点关注正常的数据流程,这一小节关注如果有异常,那么流程是怎么走完的呢?1)创建新任务时kcached_job申请不到2)读写命中时cache块为忙3)系统关机时处理,系统开机时处理,系统异常掉电后的处理首先来看第1种情况,申请kcached_job是在函数flashcache_lookup中,

294static void295flashcache_do_pending_noerror(struct kcached_job *job)296{297     struct cache_c *dmc = job->dmc;298     int index = job->index;299     unsigned long flags;300     struct pending_job *pending_job;301     int queued;302     struct cacheblock *cacheblk = &dmc->cache[index];303304     spin_lock_irqsave(&dmc->cache_spin_lock, flags);305     if (cacheblk->cache_state & DIRTY) {306          cacheblk->cache_state &= ~(BLOCK_IO_INPROG);307          cacheblk->cache_state |= DISKWRITEINPROG;308          spin_unlock_irqrestore(&dmc->cache_spin_lock, flags);309          flashcache_dirty_writeback(dmc, index);310          goto out;311     }312     DPRINTK("flashcache_do_pending: Index %d %lx",313          index, cacheblk->cache_state);314     VERIFY(cacheblk->cache_state & VALID);315     dmc->cached_blocks--;316     dmc->pending_inval++;317     cacheblk->cache_state &= ~VALID;318     cacheblk->cache_state |= INVALID;319     while (cacheblk->head) {320          VERIFY(!(cacheblk->cache_state & DIRTY));321          pending_job = cacheblk->head;322          cacheblk->head = pending_job->next;323          VERIFY(cacheblk->nr_queued > 0);324          cacheblk->nr_queued--;325          if (pending_job->action == INVALIDATE) {326               DPRINTK("flashcache_do_pending: INVALIDATE  %llu",327                    next_job->bio->bi_sector);328               VERIFY(pending_job->bio != NULL);329               queued = flashcache_inval_blocks(dmc, pending_job->bio);330               if (queued) {331                    if (unlikely(queued < 0)) {332                         /*333                         * Memory allocation failure inside inval_blocks.334                         * Fail this io.335                         */336                         flashcache_bio_endio(pending_job->bio, -EIO);337                    }338                    flashcache_free_pending_job(pending_job);339                    continue;340               }341          }342          spin_unlock_irqrestore(&dmc->cache_spin_lock, flags);343          DPRINTK("flashcache_do_pending: Sending down IO %llu",344               pending_job->bio->bi_sector);345          /* Start uncached IO */346          flashcache_start_uncached_io(dmc, pending_job->bio);347          flashcache_free_pending_job(pending_job);348          spin_lock_irqsave(&dmc->cache_spin_lock, flags);349     }350     VERIFY(cacheblk->nr_queued == 0);351     cacheblk->cache_state &= ~(BLOCK_IO_INPROG);352     spin_unlock_irqrestore(&dmc->cache_spin_lock, flags);353out:354     flashcache_free_cache_job(job);355     if (atomic_dec_and_test(&dmc->nr_jobs))356          wake_up(&dmc->destroyq);357}

这个函数分为两部分,第一部分是如果cache块为脏,则下发后立即返回,等待第二次调用,第二次调用才真正到处理pending_job,记得我们在上文中插入的pending_job是INVALIDATE的,那么这里也正如前面注释里所说下发了两次IO,一次是写回脏块,后一次是下发uncached IO。319行,取出invalid的pending_job320行,确认非dirty,因为第一次调用的时候已经写回了325行,if语句成立,329行,因为cache块已写回,就不脏不忙了,flashcache_inval_blocks只要设置invalid就可以返回成功346行,下发uncached IO至此uncached IO之旅告一个段落了。接下来讲第2种情况读写命中但cache块忙的情况下是怎么处理的。读写IO在cache块忙的情况下做出的表现是惊人的一致,那就是创建pending_job并挂入cache块队列中。这对我们来说已经是轻车熟路,不过我们这一次要跟踪的是读写IO的情况。经过前面的分析我们知道,pending_job是在flashcache_do_pending_noerror函数中处理的。同样如果为脏块要刷一次脏块,第二次进入到319行循环,由于Action为READCACHE或者WRITECACHE,直接到346行下发uncached IO。第2种情况的处理也就宣告结束了。似乎显得仓促,现实就是这样的,永远别想像电影里那样大起大落,只要你内心够从容,平平淡淡才是真。第3种情况就留给大家自己分析,如果对这几个小节都已经熟悉,那就已经是小case了。至此,flashcache源码的分析也就结束了,我也非常高兴能够坚持写完,因为这确实是一个非常耗时间的过程。如果你阅读之后能有所收获,那将是我最大的欢喜了。

读书人网 >Flash

热点推荐