162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * fs/hmdfs/server_writeback.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <linux/fs.h> 1062306a36Sopenharmony_ci#include <linux/backing-dev.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "hmdfs.h" 1362306a36Sopenharmony_ci#include "hmdfs_trace.h" 1462306a36Sopenharmony_ci#include "server_writeback.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define HMDFS_SRV_WB_DEF_DIRTY_THRESH 50UL 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic void hmdfs_srv_wb_handler(struct work_struct *work) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci struct hmdfs_server_writeback *hswb = container_of(work, 2162306a36Sopenharmony_ci struct hmdfs_server_writeback, 2262306a36Sopenharmony_ci dirty_sb_writeback_work); 2362306a36Sopenharmony_ci struct super_block *lower_sb = hswb->sbi->lower_sb; 2462306a36Sopenharmony_ci int dirty_pages; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci if (writeback_in_progress(&lower_sb->s_bdi->wb) || 2762306a36Sopenharmony_ci !down_read_trylock(&lower_sb->s_umount)) 2862306a36Sopenharmony_ci return; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci dirty_pages = hswb->dirty_nr_pages_to_wb; 3162306a36Sopenharmony_ci writeback_inodes_sb_nr(lower_sb, dirty_pages, WB_REASON_FS_FREE_SPACE); 3262306a36Sopenharmony_ci up_read(&lower_sb->s_umount); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci trace_hmdfs_start_srv_wb(hswb->sbi, dirty_pages, hswb->dirty_thresh_pg); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_civoid hmdfs_server_check_writeback(struct hmdfs_server_writeback *hswb) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci unsigned long old_time, now; 4062306a36Sopenharmony_ci int dirty_nr_pages; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci old_time = hswb->last_reset_time; 4362306a36Sopenharmony_ci now = jiffies; 4462306a36Sopenharmony_ci dirty_nr_pages = atomic_inc_return(&hswb->dirty_nr_pages); 4562306a36Sopenharmony_ci if (time_after(now, old_time + HZ) && 4662306a36Sopenharmony_ci cmpxchg(&hswb->last_reset_time, old_time, now) == old_time) { 4762306a36Sopenharmony_ci /* 4862306a36Sopenharmony_ci * We calculate the speed of page dirting to handle 4962306a36Sopenharmony_ci * following situations: 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci * 1. Dense writing, average page writing speed 5262306a36Sopenharmony_ci * exceeds @hswb->dirty_thresh_pg: 5362306a36Sopenharmony_ci * 0-1s 100MB 5462306a36Sopenharmony_ci * 2. Sporadic writing, average page writing speed 5562306a36Sopenharmony_ci * belows @hswb->dirty_thresh_pg: 5662306a36Sopenharmony_ci * 0-0.1s 40MB 5762306a36Sopenharmony_ci * 3.1-3.2 20MB 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_ci unsigned int writepage_speed; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci writepage_speed = dirty_nr_pages / ((now - old_time) / HZ); 6262306a36Sopenharmony_ci if (writepage_speed >= hswb->dirty_thresh_pg) { 6362306a36Sopenharmony_ci /* 6462306a36Sopenharmony_ci * Writeback @hswb->dirty_nr_pages_to_wb pages in 6562306a36Sopenharmony_ci * server-writeback work. If work is delayed after 6662306a36Sopenharmony_ci * 1s, @hswb->dirty_nr_pages_to_wb could be assigned 6762306a36Sopenharmony_ci * another new value (eg. 60MB), the old value (eg. 6862306a36Sopenharmony_ci * 80MB) will be overwritten, which means 80MB data 6962306a36Sopenharmony_ci * will be omitted to writeback. We can tolerate this 7062306a36Sopenharmony_ci * situation, The writeback pressure is too high if 7162306a36Sopenharmony_ci * the previous work is not completed, so it's 7262306a36Sopenharmony_ci * meaningless to continue subsequent work. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci hswb->dirty_nr_pages_to_wb = dirty_nr_pages; 7562306a36Sopenharmony_ci /* 7662306a36Sopenharmony_ci * There are 3 conditions to trigger queuing work: 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * A. Server successfully handles writepage for client 7962306a36Sopenharmony_ci * B. Every 1 second interval 8062306a36Sopenharmony_ci * C. Speed for page dirting exceeds @dirty_thresh_pg 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ci queue_work(hswb->dirty_writeback_wq, 8362306a36Sopenharmony_ci &hswb->dirty_sb_writeback_work); 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * There is no need to account the number of dirty pages 8862306a36Sopenharmony_ci * from remote client very accurately. Allow the missing 8962306a36Sopenharmony_ci * count to increase by other process in the gap between 9062306a36Sopenharmony_ci * increment and zero out. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci atomic_set(&hswb->dirty_nr_pages, 0); 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_civoid hmdfs_destroy_server_writeback(struct hmdfs_sb_info *sbi) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci if (!sbi->h_swb) 9962306a36Sopenharmony_ci return; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci flush_work(&sbi->h_swb->dirty_sb_writeback_work); 10262306a36Sopenharmony_ci destroy_workqueue(sbi->h_swb->dirty_writeback_wq); 10362306a36Sopenharmony_ci kfree(sbi->h_swb); 10462306a36Sopenharmony_ci sbi->h_swb = NULL; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ciint hmdfs_init_server_writeback(struct hmdfs_sb_info *sbi) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct hmdfs_server_writeback *hswb; 11062306a36Sopenharmony_ci char name[HMDFS_WQ_NAME_LEN]; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci hswb = kzalloc(sizeof(struct hmdfs_server_writeback), GFP_KERNEL); 11362306a36Sopenharmony_ci if (!hswb) 11462306a36Sopenharmony_ci return -ENOMEM; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci hswb->sbi = sbi; 11762306a36Sopenharmony_ci hswb->dirty_writeback_control = true; 11862306a36Sopenharmony_ci hswb->dirty_thresh_pg = HMDFS_SRV_WB_DEF_DIRTY_THRESH << 11962306a36Sopenharmony_ci HMDFS_MB_TO_PAGE_SHIFT; 12062306a36Sopenharmony_ci atomic_set(&hswb->dirty_nr_pages, 0); 12162306a36Sopenharmony_ci hswb->last_reset_time = jiffies; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci snprintf(name, sizeof(name), "dfs_srv_wb%u", sbi->seq); 12462306a36Sopenharmony_ci hswb->dirty_writeback_wq = create_singlethread_workqueue(name); 12562306a36Sopenharmony_ci if (!hswb->dirty_writeback_wq) { 12662306a36Sopenharmony_ci hmdfs_err("Failed to create server writeback workqueue!"); 12762306a36Sopenharmony_ci kfree(hswb); 12862306a36Sopenharmony_ci return -ENOMEM; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci INIT_WORK(&hswb->dirty_sb_writeback_work, hmdfs_srv_wb_handler); 13162306a36Sopenharmony_ci sbi->h_swb = hswb; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci return 0; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 136