18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* -*- mode: c; c-basic-offset: 8; -*- 38c2ecf20Sopenharmony_ci * vim: noexpandtab sw=8 ts=8 sts=0: 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * filecheck.c 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Code which implements online file check. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (C) 2016 SuSE. All rights reserved. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/list.h> 138c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/kmod.h> 178c2ecf20Sopenharmony_ci#include <linux/fs.h> 188c2ecf20Sopenharmony_ci#include <linux/kobject.h> 198c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 208c2ecf20Sopenharmony_ci#include <linux/sysctl.h> 218c2ecf20Sopenharmony_ci#include <cluster/masklog.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "ocfs2.h" 248c2ecf20Sopenharmony_ci#include "ocfs2_fs.h" 258c2ecf20Sopenharmony_ci#include "stackglue.h" 268c2ecf20Sopenharmony_ci#include "inode.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "filecheck.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* File check error strings, 328c2ecf20Sopenharmony_ci * must correspond with error number in header file. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_cistatic const char * const ocfs2_filecheck_errs[] = { 358c2ecf20Sopenharmony_ci "SUCCESS", 368c2ecf20Sopenharmony_ci "FAILED", 378c2ecf20Sopenharmony_ci "INPROGRESS", 388c2ecf20Sopenharmony_ci "READONLY", 398c2ecf20Sopenharmony_ci "INJBD", 408c2ecf20Sopenharmony_ci "INVALIDINO", 418c2ecf20Sopenharmony_ci "BLOCKECC", 428c2ecf20Sopenharmony_ci "BLOCKNO", 438c2ecf20Sopenharmony_ci "VALIDFLAG", 448c2ecf20Sopenharmony_ci "GENERATION", 458c2ecf20Sopenharmony_ci "UNSUPPORTED" 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistruct ocfs2_filecheck_entry { 498c2ecf20Sopenharmony_ci struct list_head fe_list; 508c2ecf20Sopenharmony_ci unsigned long fe_ino; 518c2ecf20Sopenharmony_ci unsigned int fe_type; 528c2ecf20Sopenharmony_ci unsigned int fe_done:1; 538c2ecf20Sopenharmony_ci unsigned int fe_status:31; 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistruct ocfs2_filecheck_args { 578c2ecf20Sopenharmony_ci unsigned int fa_type; 588c2ecf20Sopenharmony_ci union { 598c2ecf20Sopenharmony_ci unsigned long fa_ino; 608c2ecf20Sopenharmony_ci unsigned int fa_len; 618c2ecf20Sopenharmony_ci }; 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic const char * 658c2ecf20Sopenharmony_ciocfs2_filecheck_error(int errno) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci if (!errno) 688c2ecf20Sopenharmony_ci return ocfs2_filecheck_errs[errno]; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci BUG_ON(errno < OCFS2_FILECHECK_ERR_START || 718c2ecf20Sopenharmony_ci errno > OCFS2_FILECHECK_ERR_END); 728c2ecf20Sopenharmony_ci return ocfs2_filecheck_errs[errno - OCFS2_FILECHECK_ERR_START + 1]; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic ssize_t ocfs2_filecheck_attr_show(struct kobject *kobj, 768c2ecf20Sopenharmony_ci struct kobj_attribute *attr, 778c2ecf20Sopenharmony_ci char *buf); 788c2ecf20Sopenharmony_cistatic ssize_t ocfs2_filecheck_attr_store(struct kobject *kobj, 798c2ecf20Sopenharmony_ci struct kobj_attribute *attr, 808c2ecf20Sopenharmony_ci const char *buf, size_t count); 818c2ecf20Sopenharmony_cistatic struct kobj_attribute ocfs2_filecheck_attr_chk = 828c2ecf20Sopenharmony_ci __ATTR(check, S_IRUSR | S_IWUSR, 838c2ecf20Sopenharmony_ci ocfs2_filecheck_attr_show, 848c2ecf20Sopenharmony_ci ocfs2_filecheck_attr_store); 858c2ecf20Sopenharmony_cistatic struct kobj_attribute ocfs2_filecheck_attr_fix = 868c2ecf20Sopenharmony_ci __ATTR(fix, S_IRUSR | S_IWUSR, 878c2ecf20Sopenharmony_ci ocfs2_filecheck_attr_show, 888c2ecf20Sopenharmony_ci ocfs2_filecheck_attr_store); 898c2ecf20Sopenharmony_cistatic struct kobj_attribute ocfs2_filecheck_attr_set = 908c2ecf20Sopenharmony_ci __ATTR(set, S_IRUSR | S_IWUSR, 918c2ecf20Sopenharmony_ci ocfs2_filecheck_attr_show, 928c2ecf20Sopenharmony_ci ocfs2_filecheck_attr_store); 938c2ecf20Sopenharmony_cistatic struct attribute *ocfs2_filecheck_attrs[] = { 948c2ecf20Sopenharmony_ci &ocfs2_filecheck_attr_chk.attr, 958c2ecf20Sopenharmony_ci &ocfs2_filecheck_attr_fix.attr, 968c2ecf20Sopenharmony_ci &ocfs2_filecheck_attr_set.attr, 978c2ecf20Sopenharmony_ci NULL 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic void ocfs2_filecheck_release(struct kobject *kobj) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct ocfs2_filecheck_sysfs_entry *entry = container_of(kobj, 1038c2ecf20Sopenharmony_ci struct ocfs2_filecheck_sysfs_entry, fs_kobj); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci complete(&entry->fs_kobj_unregister); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic ssize_t 1098c2ecf20Sopenharmony_ciocfs2_filecheck_show(struct kobject *kobj, struct attribute *attr, char *buf) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci ssize_t ret = -EIO; 1128c2ecf20Sopenharmony_ci struct kobj_attribute *kattr = container_of(attr, 1138c2ecf20Sopenharmony_ci struct kobj_attribute, attr); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci kobject_get(kobj); 1168c2ecf20Sopenharmony_ci if (kattr->show) 1178c2ecf20Sopenharmony_ci ret = kattr->show(kobj, kattr, buf); 1188c2ecf20Sopenharmony_ci kobject_put(kobj); 1198c2ecf20Sopenharmony_ci return ret; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic ssize_t 1238c2ecf20Sopenharmony_ciocfs2_filecheck_store(struct kobject *kobj, struct attribute *attr, 1248c2ecf20Sopenharmony_ci const char *buf, size_t count) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci ssize_t ret = -EIO; 1278c2ecf20Sopenharmony_ci struct kobj_attribute *kattr = container_of(attr, 1288c2ecf20Sopenharmony_ci struct kobj_attribute, attr); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci kobject_get(kobj); 1318c2ecf20Sopenharmony_ci if (kattr->store) 1328c2ecf20Sopenharmony_ci ret = kattr->store(kobj, kattr, buf, count); 1338c2ecf20Sopenharmony_ci kobject_put(kobj); 1348c2ecf20Sopenharmony_ci return ret; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic const struct sysfs_ops ocfs2_filecheck_ops = { 1388c2ecf20Sopenharmony_ci .show = ocfs2_filecheck_show, 1398c2ecf20Sopenharmony_ci .store = ocfs2_filecheck_store, 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic struct kobj_type ocfs2_ktype_filecheck = { 1438c2ecf20Sopenharmony_ci .default_attrs = ocfs2_filecheck_attrs, 1448c2ecf20Sopenharmony_ci .sysfs_ops = &ocfs2_filecheck_ops, 1458c2ecf20Sopenharmony_ci .release = ocfs2_filecheck_release, 1468c2ecf20Sopenharmony_ci}; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic void 1498c2ecf20Sopenharmony_ciocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry *entry) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct ocfs2_filecheck_entry *p; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci spin_lock(&entry->fs_fcheck->fc_lock); 1548c2ecf20Sopenharmony_ci while (!list_empty(&entry->fs_fcheck->fc_head)) { 1558c2ecf20Sopenharmony_ci p = list_first_entry(&entry->fs_fcheck->fc_head, 1568c2ecf20Sopenharmony_ci struct ocfs2_filecheck_entry, fe_list); 1578c2ecf20Sopenharmony_ci list_del(&p->fe_list); 1588c2ecf20Sopenharmony_ci BUG_ON(!p->fe_done); /* To free a undone file check entry */ 1598c2ecf20Sopenharmony_ci kfree(p); 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci spin_unlock(&entry->fs_fcheck->fc_lock); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci kfree(entry->fs_fcheck); 1648c2ecf20Sopenharmony_ci entry->fs_fcheck = NULL; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ciint ocfs2_filecheck_create_sysfs(struct ocfs2_super *osb) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci int ret; 1708c2ecf20Sopenharmony_ci struct ocfs2_filecheck *fcheck; 1718c2ecf20Sopenharmony_ci struct ocfs2_filecheck_sysfs_entry *entry = &osb->osb_fc_ent; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci fcheck = kmalloc(sizeof(struct ocfs2_filecheck), GFP_NOFS); 1748c2ecf20Sopenharmony_ci if (!fcheck) 1758c2ecf20Sopenharmony_ci return -ENOMEM; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&fcheck->fc_head); 1788c2ecf20Sopenharmony_ci spin_lock_init(&fcheck->fc_lock); 1798c2ecf20Sopenharmony_ci fcheck->fc_max = OCFS2_FILECHECK_MINSIZE; 1808c2ecf20Sopenharmony_ci fcheck->fc_size = 0; 1818c2ecf20Sopenharmony_ci fcheck->fc_done = 0; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci entry->fs_kobj.kset = osb->osb_dev_kset; 1848c2ecf20Sopenharmony_ci init_completion(&entry->fs_kobj_unregister); 1858c2ecf20Sopenharmony_ci ret = kobject_init_and_add(&entry->fs_kobj, &ocfs2_ktype_filecheck, 1868c2ecf20Sopenharmony_ci NULL, "filecheck"); 1878c2ecf20Sopenharmony_ci if (ret) { 1888c2ecf20Sopenharmony_ci kobject_put(&entry->fs_kobj); 1898c2ecf20Sopenharmony_ci kfree(fcheck); 1908c2ecf20Sopenharmony_ci return ret; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci entry->fs_fcheck = fcheck; 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_civoid ocfs2_filecheck_remove_sysfs(struct ocfs2_super *osb) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci if (!osb->osb_fc_ent.fs_fcheck) 2008c2ecf20Sopenharmony_ci return; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci kobject_del(&osb->osb_fc_ent.fs_kobj); 2038c2ecf20Sopenharmony_ci kobject_put(&osb->osb_fc_ent.fs_kobj); 2048c2ecf20Sopenharmony_ci wait_for_completion(&osb->osb_fc_ent.fs_kobj_unregister); 2058c2ecf20Sopenharmony_ci ocfs2_filecheck_sysfs_free(&osb->osb_fc_ent); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int 2098c2ecf20Sopenharmony_ciocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent, 2108c2ecf20Sopenharmony_ci unsigned int count); 2118c2ecf20Sopenharmony_cistatic int 2128c2ecf20Sopenharmony_ciocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent, 2138c2ecf20Sopenharmony_ci unsigned int len) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci int ret; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if ((len < OCFS2_FILECHECK_MINSIZE) || (len > OCFS2_FILECHECK_MAXSIZE)) 2188c2ecf20Sopenharmony_ci return -EINVAL; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci spin_lock(&ent->fs_fcheck->fc_lock); 2218c2ecf20Sopenharmony_ci if (len < (ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done)) { 2228c2ecf20Sopenharmony_ci mlog(ML_NOTICE, 2238c2ecf20Sopenharmony_ci "Cannot set online file check maximum entry number " 2248c2ecf20Sopenharmony_ci "to %u due to too many pending entries(%u)\n", 2258c2ecf20Sopenharmony_ci len, ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done); 2268c2ecf20Sopenharmony_ci ret = -EBUSY; 2278c2ecf20Sopenharmony_ci } else { 2288c2ecf20Sopenharmony_ci if (len < ent->fs_fcheck->fc_size) 2298c2ecf20Sopenharmony_ci BUG_ON(!ocfs2_filecheck_erase_entries(ent, 2308c2ecf20Sopenharmony_ci ent->fs_fcheck->fc_size - len)); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci ent->fs_fcheck->fc_max = len; 2338c2ecf20Sopenharmony_ci ret = 0; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci spin_unlock(&ent->fs_fcheck->fc_lock); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return ret; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#define OCFS2_FILECHECK_ARGS_LEN 24 2418c2ecf20Sopenharmony_cistatic int 2428c2ecf20Sopenharmony_ciocfs2_filecheck_args_get_long(const char *buf, size_t count, 2438c2ecf20Sopenharmony_ci unsigned long *val) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci char buffer[OCFS2_FILECHECK_ARGS_LEN]; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci memcpy(buffer, buf, count); 2488c2ecf20Sopenharmony_ci buffer[count] = '\0'; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (kstrtoul(buffer, 0, val)) 2518c2ecf20Sopenharmony_ci return 1; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic int 2578c2ecf20Sopenharmony_ciocfs2_filecheck_type_parse(const char *name, unsigned int *type) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci if (!strncmp(name, "fix", 4)) 2608c2ecf20Sopenharmony_ci *type = OCFS2_FILECHECK_TYPE_FIX; 2618c2ecf20Sopenharmony_ci else if (!strncmp(name, "check", 6)) 2628c2ecf20Sopenharmony_ci *type = OCFS2_FILECHECK_TYPE_CHK; 2638c2ecf20Sopenharmony_ci else if (!strncmp(name, "set", 4)) 2648c2ecf20Sopenharmony_ci *type = OCFS2_FILECHECK_TYPE_SET; 2658c2ecf20Sopenharmony_ci else 2668c2ecf20Sopenharmony_ci return 1; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic int 2728c2ecf20Sopenharmony_ciocfs2_filecheck_args_parse(const char *name, const char *buf, size_t count, 2738c2ecf20Sopenharmony_ci struct ocfs2_filecheck_args *args) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci unsigned long val = 0; 2768c2ecf20Sopenharmony_ci unsigned int type; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* too short/long args length */ 2798c2ecf20Sopenharmony_ci if ((count < 1) || (count >= OCFS2_FILECHECK_ARGS_LEN)) 2808c2ecf20Sopenharmony_ci return 1; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (ocfs2_filecheck_type_parse(name, &type)) 2838c2ecf20Sopenharmony_ci return 1; 2848c2ecf20Sopenharmony_ci if (ocfs2_filecheck_args_get_long(buf, count, &val)) 2858c2ecf20Sopenharmony_ci return 1; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (val <= 0) 2888c2ecf20Sopenharmony_ci return 1; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci args->fa_type = type; 2918c2ecf20Sopenharmony_ci if (type == OCFS2_FILECHECK_TYPE_SET) 2928c2ecf20Sopenharmony_ci args->fa_len = (unsigned int)val; 2938c2ecf20Sopenharmony_ci else 2948c2ecf20Sopenharmony_ci args->fa_ino = val; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return 0; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic ssize_t ocfs2_filecheck_attr_show(struct kobject *kobj, 3008c2ecf20Sopenharmony_ci struct kobj_attribute *attr, 3018c2ecf20Sopenharmony_ci char *buf) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci ssize_t ret = 0, total = 0, remain = PAGE_SIZE; 3058c2ecf20Sopenharmony_ci unsigned int type; 3068c2ecf20Sopenharmony_ci struct ocfs2_filecheck_entry *p; 3078c2ecf20Sopenharmony_ci struct ocfs2_filecheck_sysfs_entry *ent = container_of(kobj, 3088c2ecf20Sopenharmony_ci struct ocfs2_filecheck_sysfs_entry, fs_kobj); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (ocfs2_filecheck_type_parse(attr->attr.name, &type)) 3118c2ecf20Sopenharmony_ci return -EINVAL; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (type == OCFS2_FILECHECK_TYPE_SET) { 3148c2ecf20Sopenharmony_ci spin_lock(&ent->fs_fcheck->fc_lock); 3158c2ecf20Sopenharmony_ci total = snprintf(buf, remain, "%u\n", ent->fs_fcheck->fc_max); 3168c2ecf20Sopenharmony_ci spin_unlock(&ent->fs_fcheck->fc_lock); 3178c2ecf20Sopenharmony_ci goto exit; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci ret = snprintf(buf, remain, "INO\t\tDONE\tERROR\n"); 3218c2ecf20Sopenharmony_ci total += ret; 3228c2ecf20Sopenharmony_ci remain -= ret; 3238c2ecf20Sopenharmony_ci spin_lock(&ent->fs_fcheck->fc_lock); 3248c2ecf20Sopenharmony_ci list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) { 3258c2ecf20Sopenharmony_ci if (p->fe_type != type) 3268c2ecf20Sopenharmony_ci continue; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci ret = snprintf(buf + total, remain, "%lu\t\t%u\t%s\n", 3298c2ecf20Sopenharmony_ci p->fe_ino, p->fe_done, 3308c2ecf20Sopenharmony_ci ocfs2_filecheck_error(p->fe_status)); 3318c2ecf20Sopenharmony_ci if (ret >= remain) { 3328c2ecf20Sopenharmony_ci /* snprintf() didn't fit */ 3338c2ecf20Sopenharmony_ci total = -E2BIG; 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci total += ret; 3378c2ecf20Sopenharmony_ci remain -= ret; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci spin_unlock(&ent->fs_fcheck->fc_lock); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ciexit: 3428c2ecf20Sopenharmony_ci return total; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic inline int 3468c2ecf20Sopenharmony_ciocfs2_filecheck_is_dup_entry(struct ocfs2_filecheck_sysfs_entry *ent, 3478c2ecf20Sopenharmony_ci unsigned long ino) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci struct ocfs2_filecheck_entry *p; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) { 3528c2ecf20Sopenharmony_ci if (!p->fe_done) { 3538c2ecf20Sopenharmony_ci if (p->fe_ino == ino) 3548c2ecf20Sopenharmony_ci return 1; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci return 0; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic inline int 3628c2ecf20Sopenharmony_ciocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci struct ocfs2_filecheck_entry *p; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) { 3678c2ecf20Sopenharmony_ci if (p->fe_done) { 3688c2ecf20Sopenharmony_ci list_del(&p->fe_list); 3698c2ecf20Sopenharmony_ci kfree(p); 3708c2ecf20Sopenharmony_ci ent->fs_fcheck->fc_size--; 3718c2ecf20Sopenharmony_ci ent->fs_fcheck->fc_done--; 3728c2ecf20Sopenharmony_ci return 1; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return 0; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic int 3808c2ecf20Sopenharmony_ciocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent, 3818c2ecf20Sopenharmony_ci unsigned int count) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci unsigned int i = 0; 3848c2ecf20Sopenharmony_ci unsigned int ret = 0; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci while (i++ < count) { 3878c2ecf20Sopenharmony_ci if (ocfs2_filecheck_erase_entry(ent)) 3888c2ecf20Sopenharmony_ci ret++; 3898c2ecf20Sopenharmony_ci else 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return (ret == count ? 1 : 0); 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic void 3978c2ecf20Sopenharmony_ciocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent, 3988c2ecf20Sopenharmony_ci struct ocfs2_filecheck_entry *entry) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci spin_lock(&ent->fs_fcheck->fc_lock); 4018c2ecf20Sopenharmony_ci entry->fe_done = 1; 4028c2ecf20Sopenharmony_ci ent->fs_fcheck->fc_done++; 4038c2ecf20Sopenharmony_ci spin_unlock(&ent->fs_fcheck->fc_lock); 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic unsigned int 4078c2ecf20Sopenharmony_ciocfs2_filecheck_handle(struct ocfs2_super *osb, 4088c2ecf20Sopenharmony_ci unsigned long ino, unsigned int flags) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci unsigned int ret = OCFS2_FILECHECK_ERR_SUCCESS; 4118c2ecf20Sopenharmony_ci struct inode *inode = NULL; 4128c2ecf20Sopenharmony_ci int rc; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci inode = ocfs2_iget(osb, ino, flags, 0); 4158c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 4168c2ecf20Sopenharmony_ci rc = (int)(-(long)inode); 4178c2ecf20Sopenharmony_ci if (rc >= OCFS2_FILECHECK_ERR_START && 4188c2ecf20Sopenharmony_ci rc < OCFS2_FILECHECK_ERR_END) 4198c2ecf20Sopenharmony_ci ret = rc; 4208c2ecf20Sopenharmony_ci else 4218c2ecf20Sopenharmony_ci ret = OCFS2_FILECHECK_ERR_FAILED; 4228c2ecf20Sopenharmony_ci } else 4238c2ecf20Sopenharmony_ci iput(inode); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci return ret; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic void 4298c2ecf20Sopenharmony_ciocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent, 4308c2ecf20Sopenharmony_ci struct ocfs2_filecheck_entry *entry) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci struct ocfs2_super *osb = container_of(ent, struct ocfs2_super, 4338c2ecf20Sopenharmony_ci osb_fc_ent); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK) 4368c2ecf20Sopenharmony_ci entry->fe_status = ocfs2_filecheck_handle(osb, 4378c2ecf20Sopenharmony_ci entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK); 4388c2ecf20Sopenharmony_ci else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX) 4398c2ecf20Sopenharmony_ci entry->fe_status = ocfs2_filecheck_handle(osb, 4408c2ecf20Sopenharmony_ci entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX); 4418c2ecf20Sopenharmony_ci else 4428c2ecf20Sopenharmony_ci entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci ocfs2_filecheck_done_entry(ent, entry); 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic ssize_t ocfs2_filecheck_attr_store(struct kobject *kobj, 4488c2ecf20Sopenharmony_ci struct kobj_attribute *attr, 4498c2ecf20Sopenharmony_ci const char *buf, size_t count) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci ssize_t ret = 0; 4528c2ecf20Sopenharmony_ci struct ocfs2_filecheck_args args; 4538c2ecf20Sopenharmony_ci struct ocfs2_filecheck_entry *entry; 4548c2ecf20Sopenharmony_ci struct ocfs2_filecheck_sysfs_entry *ent = container_of(kobj, 4558c2ecf20Sopenharmony_ci struct ocfs2_filecheck_sysfs_entry, fs_kobj); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (count == 0) 4588c2ecf20Sopenharmony_ci return count; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args)) 4618c2ecf20Sopenharmony_ci return -EINVAL; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (args.fa_type == OCFS2_FILECHECK_TYPE_SET) { 4648c2ecf20Sopenharmony_ci ret = ocfs2_filecheck_adjust_max(ent, args.fa_len); 4658c2ecf20Sopenharmony_ci goto exit; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS); 4698c2ecf20Sopenharmony_ci if (!entry) { 4708c2ecf20Sopenharmony_ci ret = -ENOMEM; 4718c2ecf20Sopenharmony_ci goto exit; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci spin_lock(&ent->fs_fcheck->fc_lock); 4758c2ecf20Sopenharmony_ci if (ocfs2_filecheck_is_dup_entry(ent, args.fa_ino)) { 4768c2ecf20Sopenharmony_ci ret = -EEXIST; 4778c2ecf20Sopenharmony_ci kfree(entry); 4788c2ecf20Sopenharmony_ci } else if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) && 4798c2ecf20Sopenharmony_ci (ent->fs_fcheck->fc_done == 0)) { 4808c2ecf20Sopenharmony_ci mlog(ML_NOTICE, 4818c2ecf20Sopenharmony_ci "Cannot do more file check " 4828c2ecf20Sopenharmony_ci "since file check queue(%u) is full now\n", 4838c2ecf20Sopenharmony_ci ent->fs_fcheck->fc_max); 4848c2ecf20Sopenharmony_ci ret = -EAGAIN; 4858c2ecf20Sopenharmony_ci kfree(entry); 4868c2ecf20Sopenharmony_ci } else { 4878c2ecf20Sopenharmony_ci if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) && 4888c2ecf20Sopenharmony_ci (ent->fs_fcheck->fc_done > 0)) { 4898c2ecf20Sopenharmony_ci /* Delete the oldest entry which was done, 4908c2ecf20Sopenharmony_ci * make sure the entry size in list does 4918c2ecf20Sopenharmony_ci * not exceed maximum value 4928c2ecf20Sopenharmony_ci */ 4938c2ecf20Sopenharmony_ci BUG_ON(!ocfs2_filecheck_erase_entry(ent)); 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci entry->fe_ino = args.fa_ino; 4978c2ecf20Sopenharmony_ci entry->fe_type = args.fa_type; 4988c2ecf20Sopenharmony_ci entry->fe_done = 0; 4998c2ecf20Sopenharmony_ci entry->fe_status = OCFS2_FILECHECK_ERR_INPROGRESS; 5008c2ecf20Sopenharmony_ci list_add_tail(&entry->fe_list, &ent->fs_fcheck->fc_head); 5018c2ecf20Sopenharmony_ci ent->fs_fcheck->fc_size++; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci spin_unlock(&ent->fs_fcheck->fc_lock); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (!ret) 5068c2ecf20Sopenharmony_ci ocfs2_filecheck_handle_entry(ent, entry); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ciexit: 5098c2ecf20Sopenharmony_ci return (!ret ? count : ret); 5108c2ecf20Sopenharmony_ci} 511