Loading fs/nfsd/filecache.c +31 −13 Original line number Diff line number Diff line Loading @@ -261,6 +261,18 @@ nfsd_file_flush(struct nfsd_file *nf) nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); } static void nfsd_file_lru_add(struct nfsd_file *nf) { if (list_lru_add(&nfsd_file_lru, &nf->nf_lru)) trace_nfsd_file_lru_add(nf); } static void nfsd_file_lru_remove(struct nfsd_file *nf) { if (list_lru_del(&nfsd_file_lru, &nf->nf_lru)) trace_nfsd_file_lru_del(nf); } static void nfsd_file_do_unhash(struct nfsd_file *nf) { Loading @@ -280,8 +292,7 @@ nfsd_file_unhash(struct nfsd_file *nf) { if (test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { nfsd_file_do_unhash(nf); if (!list_empty(&nf->nf_lru)) list_lru_del(&nfsd_file_lru, &nf->nf_lru); nfsd_file_lru_remove(nf); return true; } return false; Loading Loading @@ -444,27 +455,34 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru, * counter. Here we check the counter and then test and clear the flag. * That order is deliberate to ensure that we can do this locklessly. */ if (refcount_read(&nf->nf_ref) > 1) goto out_skip; if (refcount_read(&nf->nf_ref) > 1) { trace_nfsd_file_gc_in_use(nf); return LRU_SKIP; } /* * Don't throw out files that are still undergoing I/O or * that have uncleared errors pending. */ if (nfsd_file_check_writeback(nf)) goto out_skip; if (nfsd_file_check_writeback(nf)) { trace_nfsd_file_gc_writeback(nf); return LRU_SKIP; } if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags)) goto out_skip; if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags)) { trace_nfsd_file_gc_referenced(nf); return LRU_SKIP; } if (!test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) goto out_skip; if (!test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { trace_nfsd_file_gc_hashed(nf); return LRU_SKIP; } list_lru_isolate_move(lru, &nf->nf_lru, head); this_cpu_inc(nfsd_file_evictions); trace_nfsd_file_gc_disposed(nf); return LRU_REMOVED; out_skip: return LRU_SKIP; } /* Loading Loading @@ -1017,7 +1035,7 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, refcount_inc(&nf->nf_ref); __set_bit(NFSD_FILE_HASHED, &nf->nf_flags); __set_bit(NFSD_FILE_PENDING, &nf->nf_flags); list_lru_add(&nfsd_file_lru, &nf->nf_lru); nfsd_file_lru_add(nf); hlist_add_head_rcu(&nf->nf_node, &nfsd_file_hashtbl[hashval].nfb_head); ++nfsd_file_hashtbl[hashval].nfb_count; nfsd_file_hashtbl[hashval].nfb_maxcount = max(nfsd_file_hashtbl[hashval].nfb_maxcount, Loading fs/nfsd/trace.h +39 −0 Original line number Diff line number Diff line Loading @@ -895,6 +895,45 @@ TRACE_EVENT(nfsd_file_fsnotify_handle_event, __entry->nlink, __entry->mode, __entry->mask) ); DECLARE_EVENT_CLASS(nfsd_file_gc_class, TP_PROTO( const struct nfsd_file *nf ), TP_ARGS(nf), TP_STRUCT__entry( __field(void *, nf_inode) __field(void *, nf_file) __field(int, nf_ref) __field(unsigned long, nf_flags) ), TP_fast_assign( __entry->nf_inode = nf->nf_inode; __entry->nf_file = nf->nf_file; __entry->nf_ref = refcount_read(&nf->nf_ref); __entry->nf_flags = nf->nf_flags; ), TP_printk("inode=%p ref=%d nf_flags=%s nf_file=%p", __entry->nf_inode, __entry->nf_ref, show_nf_flags(__entry->nf_flags), __entry->nf_file ) ); #define DEFINE_NFSD_FILE_GC_EVENT(name) \ DEFINE_EVENT(nfsd_file_gc_class, name, \ TP_PROTO( \ const struct nfsd_file *nf \ ), \ TP_ARGS(nf)) DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_add); DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_del); DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_in_use); DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_writeback); DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_referenced); DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_hashed); DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_disposed); DECLARE_EVENT_CLASS(nfsd_file_lruwalk_class, TP_PROTO( unsigned long removed, Loading Loading
fs/nfsd/filecache.c +31 −13 Original line number Diff line number Diff line Loading @@ -261,6 +261,18 @@ nfsd_file_flush(struct nfsd_file *nf) nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); } static void nfsd_file_lru_add(struct nfsd_file *nf) { if (list_lru_add(&nfsd_file_lru, &nf->nf_lru)) trace_nfsd_file_lru_add(nf); } static void nfsd_file_lru_remove(struct nfsd_file *nf) { if (list_lru_del(&nfsd_file_lru, &nf->nf_lru)) trace_nfsd_file_lru_del(nf); } static void nfsd_file_do_unhash(struct nfsd_file *nf) { Loading @@ -280,8 +292,7 @@ nfsd_file_unhash(struct nfsd_file *nf) { if (test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { nfsd_file_do_unhash(nf); if (!list_empty(&nf->nf_lru)) list_lru_del(&nfsd_file_lru, &nf->nf_lru); nfsd_file_lru_remove(nf); return true; } return false; Loading Loading @@ -444,27 +455,34 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru, * counter. Here we check the counter and then test and clear the flag. * That order is deliberate to ensure that we can do this locklessly. */ if (refcount_read(&nf->nf_ref) > 1) goto out_skip; if (refcount_read(&nf->nf_ref) > 1) { trace_nfsd_file_gc_in_use(nf); return LRU_SKIP; } /* * Don't throw out files that are still undergoing I/O or * that have uncleared errors pending. */ if (nfsd_file_check_writeback(nf)) goto out_skip; if (nfsd_file_check_writeback(nf)) { trace_nfsd_file_gc_writeback(nf); return LRU_SKIP; } if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags)) goto out_skip; if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags)) { trace_nfsd_file_gc_referenced(nf); return LRU_SKIP; } if (!test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) goto out_skip; if (!test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { trace_nfsd_file_gc_hashed(nf); return LRU_SKIP; } list_lru_isolate_move(lru, &nf->nf_lru, head); this_cpu_inc(nfsd_file_evictions); trace_nfsd_file_gc_disposed(nf); return LRU_REMOVED; out_skip: return LRU_SKIP; } /* Loading Loading @@ -1017,7 +1035,7 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, refcount_inc(&nf->nf_ref); __set_bit(NFSD_FILE_HASHED, &nf->nf_flags); __set_bit(NFSD_FILE_PENDING, &nf->nf_flags); list_lru_add(&nfsd_file_lru, &nf->nf_lru); nfsd_file_lru_add(nf); hlist_add_head_rcu(&nf->nf_node, &nfsd_file_hashtbl[hashval].nfb_head); ++nfsd_file_hashtbl[hashval].nfb_count; nfsd_file_hashtbl[hashval].nfb_maxcount = max(nfsd_file_hashtbl[hashval].nfb_maxcount, Loading
fs/nfsd/trace.h +39 −0 Original line number Diff line number Diff line Loading @@ -895,6 +895,45 @@ TRACE_EVENT(nfsd_file_fsnotify_handle_event, __entry->nlink, __entry->mode, __entry->mask) ); DECLARE_EVENT_CLASS(nfsd_file_gc_class, TP_PROTO( const struct nfsd_file *nf ), TP_ARGS(nf), TP_STRUCT__entry( __field(void *, nf_inode) __field(void *, nf_file) __field(int, nf_ref) __field(unsigned long, nf_flags) ), TP_fast_assign( __entry->nf_inode = nf->nf_inode; __entry->nf_file = nf->nf_file; __entry->nf_ref = refcount_read(&nf->nf_ref); __entry->nf_flags = nf->nf_flags; ), TP_printk("inode=%p ref=%d nf_flags=%s nf_file=%p", __entry->nf_inode, __entry->nf_ref, show_nf_flags(__entry->nf_flags), __entry->nf_file ) ); #define DEFINE_NFSD_FILE_GC_EVENT(name) \ DEFINE_EVENT(nfsd_file_gc_class, name, \ TP_PROTO( \ const struct nfsd_file *nf \ ), \ TP_ARGS(nf)) DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_add); DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_del); DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_in_use); DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_writeback); DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_referenced); DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_hashed); DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_disposed); DECLARE_EVENT_CLASS(nfsd_file_lruwalk_class, TP_PROTO( unsigned long removed, Loading