• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * fs/hmdfs/server_writeback.c
4  *
5  * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
6  */
7 
8 #include <linux/slab.h>
9 #include <linux/fs.h>
10 #include <linux/backing-dev.h>
11 
12 #include "hmdfs.h"
13 #include "hmdfs_trace.h"
14 #include "server_writeback.h"
15 
16 #define HMDFS_SRV_WB_DEF_DIRTY_THRESH	50UL
17 
hmdfs_srv_wb_handler(struct work_struct * work)18 static void hmdfs_srv_wb_handler(struct work_struct *work)
19 {
20 	struct hmdfs_server_writeback *hswb = container_of(work,
21 					      struct hmdfs_server_writeback,
22 					      dirty_sb_writeback_work);
23 	struct super_block *lower_sb = hswb->sbi->lower_sb;
24 	int dirty_pages;
25 
26 	if (writeback_in_progress(&lower_sb->s_bdi->wb) ||
27 	    !down_read_trylock(&lower_sb->s_umount))
28 		return;
29 
30 	dirty_pages = hswb->dirty_nr_pages_to_wb;
31 	writeback_inodes_sb_nr(lower_sb, dirty_pages, WB_REASON_FS_FREE_SPACE);
32 	up_read(&lower_sb->s_umount);
33 
34 	trace_hmdfs_start_srv_wb(hswb->sbi, dirty_pages, hswb->dirty_thresh_pg);
35 }
36 
hmdfs_server_check_writeback(struct hmdfs_server_writeback * hswb)37 void hmdfs_server_check_writeback(struct hmdfs_server_writeback *hswb)
38 {
39 	unsigned long old_time, now;
40 	int dirty_nr_pages;
41 
42 	old_time = hswb->last_reset_time;
43 	now = jiffies;
44 	dirty_nr_pages = atomic_inc_return(&hswb->dirty_nr_pages);
45 	if (time_after(now, old_time + HZ) &&
46 	    cmpxchg(&hswb->last_reset_time, old_time, now) == old_time) {
47 		/*
48 		 * We calculate the speed of page dirting to handle
49 		 * following situations:
50 		 *
51 		 * 1. Dense writing, average page writing speed
52 		 *    exceeds @hswb->dirty_thresh_pg:
53 		 *    0-1s 100MB
54 		 * 2. Sporadic writing, average page writing speed
55 		 *    belows @hswb->dirty_thresh_pg:
56 		 *    0-0.1s	40MB
57 		 *    3.1-3.2	20MB
58 		 */
59 		unsigned int writepage_speed;
60 
61 		writepage_speed = dirty_nr_pages / ((now - old_time) / HZ);
62 		if (writepage_speed >= hswb->dirty_thresh_pg) {
63 			/*
64 			 * Writeback @hswb->dirty_nr_pages_to_wb pages in
65 			 * server-writeback work. If work is delayed after
66 			 * 1s, @hswb->dirty_nr_pages_to_wb could be assigned
67 			 * another new value (eg. 60MB), the old value (eg.
68 			 * 80MB) will be overwritten, which means 80MB data
69 			 * will be omitted to writeback. We can tolerate this
70 			 * situation, The writeback pressure is too high if
71 			 * the previous work is not completed, so it's
72 			 * meaningless to continue subsequent work.
73 			 */
74 			hswb->dirty_nr_pages_to_wb = dirty_nr_pages;
75 			/*
76 			 * There are 3 conditions to trigger queuing work:
77 			 *
78 			 * A. Server successfully handles writepage for client
79 			 * B. Every 1 second interval
80 			 * C. Speed for page dirting exceeds @dirty_thresh_pg
81 			 */
82 			queue_work(hswb->dirty_writeback_wq,
83 				   &hswb->dirty_sb_writeback_work);
84 		}
85 
86 		/*
87 		 * There is no need to account the number of dirty pages
88 		 * from remote client very accurately. Allow the missing
89 		 * count to increase by other process in the gap between
90 		 * increment and zero out.
91 		 */
92 		atomic_set(&hswb->dirty_nr_pages, 0);
93 	}
94 }
95 
hmdfs_destroy_server_writeback(struct hmdfs_sb_info * sbi)96 void hmdfs_destroy_server_writeback(struct hmdfs_sb_info *sbi)
97 {
98 	if (!sbi->h_swb)
99 		return;
100 
101 	flush_work(&sbi->h_swb->dirty_sb_writeback_work);
102 	destroy_workqueue(sbi->h_swb->dirty_writeback_wq);
103 	kfree(sbi->h_swb);
104 	sbi->h_swb = NULL;
105 }
106 
hmdfs_init_server_writeback(struct hmdfs_sb_info * sbi)107 int hmdfs_init_server_writeback(struct hmdfs_sb_info *sbi)
108 {
109 	struct hmdfs_server_writeback *hswb;
110 	char name[HMDFS_WQ_NAME_LEN];
111 
112 	hswb = kzalloc(sizeof(struct hmdfs_server_writeback), GFP_KERNEL);
113 	if (!hswb)
114 		return -ENOMEM;
115 
116 	hswb->sbi = sbi;
117 	hswb->dirty_writeback_control = true;
118 	hswb->dirty_thresh_pg = HMDFS_SRV_WB_DEF_DIRTY_THRESH <<
119 				HMDFS_MB_TO_PAGE_SHIFT;
120 	atomic_set(&hswb->dirty_nr_pages, 0);
121 	hswb->last_reset_time = jiffies;
122 
123 	snprintf(name, sizeof(name), "dfs_srv_wb%u", sbi->seq);
124 	hswb->dirty_writeback_wq = create_singlethread_workqueue(name);
125 	if (!hswb->dirty_writeback_wq) {
126 		hmdfs_err("Failed to create server writeback workqueue!");
127 		kfree(hswb);
128 		return -ENOMEM;
129 	}
130 	INIT_WORK(&hswb->dirty_sb_writeback_work, hmdfs_srv_wb_handler);
131 	sbi->h_swb = hswb;
132 
133 	return 0;
134 }
135 
136