150acfb2bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2*fa60ce2cSMasahiro Yamada /* 3a860f6ebSGang He * filecheck.c 4a860f6ebSGang He * 5a860f6ebSGang He * Code which implements online file check. 6a860f6ebSGang He * 7a860f6ebSGang He * Copyright (C) 2016 SuSE. All rights reserved. 8a860f6ebSGang He */ 9a860f6ebSGang He 10a860f6ebSGang He #include <linux/list.h> 11a860f6ebSGang He #include <linux/spinlock.h> 12a860f6ebSGang He #include <linux/module.h> 13a860f6ebSGang He #include <linux/slab.h> 14a860f6ebSGang He #include <linux/kmod.h> 15a860f6ebSGang He #include <linux/fs.h> 16a860f6ebSGang He #include <linux/kobject.h> 17a860f6ebSGang He #include <linux/sysfs.h> 18a860f6ebSGang He #include <linux/sysctl.h> 19a860f6ebSGang He #include <cluster/masklog.h> 20a860f6ebSGang He 21a860f6ebSGang He #include "ocfs2.h" 22a860f6ebSGang He #include "ocfs2_fs.h" 23a860f6ebSGang He #include "stackglue.h" 24a860f6ebSGang He #include "inode.h" 25a860f6ebSGang He 26a860f6ebSGang He #include "filecheck.h" 27a860f6ebSGang He 28a860f6ebSGang He 29a860f6ebSGang He /* File check error strings, 30a860f6ebSGang He * must correspond with error number in header file. 31a860f6ebSGang He */ 32a860f6ebSGang He static const char * const ocfs2_filecheck_errs[] = { 33a860f6ebSGang He "SUCCESS", 34a860f6ebSGang He "FAILED", 35a860f6ebSGang He "INPROGRESS", 36a860f6ebSGang He "READONLY", 37a860f6ebSGang He "INJBD", 38a860f6ebSGang He "INVALIDINO", 39a860f6ebSGang He "BLOCKECC", 40a860f6ebSGang He "BLOCKNO", 41a860f6ebSGang He "VALIDFLAG", 42a860f6ebSGang He "GENERATION", 43a860f6ebSGang He "UNSUPPORTED" 44a860f6ebSGang He }; 45a860f6ebSGang He 46a860f6ebSGang He struct ocfs2_filecheck_entry { 47a860f6ebSGang He struct list_head fe_list; 48a860f6ebSGang He unsigned long fe_ino; 49a860f6ebSGang He unsigned int fe_type; 50a860f6ebSGang He unsigned int fe_done:1; 51a860f6ebSGang He unsigned int fe_status:31; 52a860f6ebSGang He }; 53a860f6ebSGang He 54a860f6ebSGang He struct ocfs2_filecheck_args { 55a860f6ebSGang He unsigned int fa_type; 56a860f6ebSGang He union { 57a860f6ebSGang He unsigned long fa_ino; 58a860f6ebSGang He unsigned int fa_len; 59a860f6ebSGang He }; 60a860f6ebSGang He }; 61a860f6ebSGang He 62a860f6ebSGang He static const char * 63a860f6ebSGang He ocfs2_filecheck_error(int errno) 64a860f6ebSGang He { 65a860f6ebSGang He if (!errno) 66a860f6ebSGang He return ocfs2_filecheck_errs[errno]; 67a860f6ebSGang He 68a860f6ebSGang He BUG_ON(errno < OCFS2_FILECHECK_ERR_START || 69a860f6ebSGang He errno > OCFS2_FILECHECK_ERR_END); 70a860f6ebSGang He return ocfs2_filecheck_errs[errno - OCFS2_FILECHECK_ERR_START + 1]; 71a860f6ebSGang He } 72a860f6ebSGang He 735f483c4aSGang He static ssize_t ocfs2_filecheck_attr_show(struct kobject *kobj, 74a860f6ebSGang He struct kobj_attribute *attr, 75a860f6ebSGang He char *buf); 765f483c4aSGang He static ssize_t ocfs2_filecheck_attr_store(struct kobject *kobj, 77a860f6ebSGang He struct kobj_attribute *attr, 78a860f6ebSGang He const char *buf, size_t count); 795f483c4aSGang He static struct kobj_attribute ocfs2_filecheck_attr_chk = 80a860f6ebSGang He __ATTR(check, S_IRUSR | S_IWUSR, 815f483c4aSGang He ocfs2_filecheck_attr_show, 825f483c4aSGang He ocfs2_filecheck_attr_store); 835f483c4aSGang He static struct kobj_attribute ocfs2_filecheck_attr_fix = 84a860f6ebSGang He __ATTR(fix, S_IRUSR | S_IWUSR, 855f483c4aSGang He ocfs2_filecheck_attr_show, 865f483c4aSGang He ocfs2_filecheck_attr_store); 875f483c4aSGang He static struct kobj_attribute ocfs2_filecheck_attr_set = 88a860f6ebSGang He __ATTR(set, S_IRUSR | S_IWUSR, 895f483c4aSGang He ocfs2_filecheck_attr_show, 905f483c4aSGang He ocfs2_filecheck_attr_store); 915f483c4aSGang He static struct attribute *ocfs2_filecheck_attrs[] = { 925f483c4aSGang He &ocfs2_filecheck_attr_chk.attr, 935f483c4aSGang He &ocfs2_filecheck_attr_fix.attr, 945f483c4aSGang He &ocfs2_filecheck_attr_set.attr, 955f483c4aSGang He NULL 965f483c4aSGang He }; 975f483c4aSGang He 985f483c4aSGang He static void ocfs2_filecheck_release(struct kobject *kobj) 995f483c4aSGang He { 1005f483c4aSGang He struct ocfs2_filecheck_sysfs_entry *entry = container_of(kobj, 1015f483c4aSGang He struct ocfs2_filecheck_sysfs_entry, fs_kobj); 1025f483c4aSGang He 1035f483c4aSGang He complete(&entry->fs_kobj_unregister); 1045f483c4aSGang He } 1055f483c4aSGang He 1065f483c4aSGang He static ssize_t 1075f483c4aSGang He ocfs2_filecheck_show(struct kobject *kobj, struct attribute *attr, char *buf) 1085f483c4aSGang He { 1095f483c4aSGang He ssize_t ret = -EIO; 1105f483c4aSGang He struct kobj_attribute *kattr = container_of(attr, 1115f483c4aSGang He struct kobj_attribute, attr); 1125f483c4aSGang He 1135f483c4aSGang He kobject_get(kobj); 1145f483c4aSGang He if (kattr->show) 1155f483c4aSGang He ret = kattr->show(kobj, kattr, buf); 1165f483c4aSGang He kobject_put(kobj); 1175f483c4aSGang He return ret; 1185f483c4aSGang He } 1195f483c4aSGang He 1205f483c4aSGang He static ssize_t 1215f483c4aSGang He ocfs2_filecheck_store(struct kobject *kobj, struct attribute *attr, 1225f483c4aSGang He const char *buf, size_t count) 1235f483c4aSGang He { 1245f483c4aSGang He ssize_t ret = -EIO; 1255f483c4aSGang He struct kobj_attribute *kattr = container_of(attr, 1265f483c4aSGang He struct kobj_attribute, attr); 1275f483c4aSGang He 1285f483c4aSGang He kobject_get(kobj); 1295f483c4aSGang He if (kattr->store) 1305f483c4aSGang He ret = kattr->store(kobj, kattr, buf, count); 1315f483c4aSGang He kobject_put(kobj); 1325f483c4aSGang He return ret; 1335f483c4aSGang He } 1345f483c4aSGang He 1355f483c4aSGang He static const struct sysfs_ops ocfs2_filecheck_ops = { 1365f483c4aSGang He .show = ocfs2_filecheck_show, 1375f483c4aSGang He .store = ocfs2_filecheck_store, 1385f483c4aSGang He }; 1395f483c4aSGang He 1405f483c4aSGang He static struct kobj_type ocfs2_ktype_filecheck = { 1415f483c4aSGang He .default_attrs = ocfs2_filecheck_attrs, 1425f483c4aSGang He .sysfs_ops = &ocfs2_filecheck_ops, 1435f483c4aSGang He .release = ocfs2_filecheck_release, 1445f483c4aSGang He }; 145a860f6ebSGang He 146a860f6ebSGang He static void 147a860f6ebSGang He ocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry *entry) 148a860f6ebSGang He { 149a860f6ebSGang He struct ocfs2_filecheck_entry *p; 150a860f6ebSGang He 151a860f6ebSGang He spin_lock(&entry->fs_fcheck->fc_lock); 152a860f6ebSGang He while (!list_empty(&entry->fs_fcheck->fc_head)) { 153a860f6ebSGang He p = list_first_entry(&entry->fs_fcheck->fc_head, 154a860f6ebSGang He struct ocfs2_filecheck_entry, fe_list); 155a860f6ebSGang He list_del(&p->fe_list); 156a860f6ebSGang He BUG_ON(!p->fe_done); /* To free a undone file check entry */ 157a860f6ebSGang He kfree(p); 158a860f6ebSGang He } 159a860f6ebSGang He spin_unlock(&entry->fs_fcheck->fc_lock); 160a860f6ebSGang He 161a860f6ebSGang He kfree(entry->fs_fcheck); 1625f483c4aSGang He entry->fs_fcheck = NULL; 163a860f6ebSGang He } 164a860f6ebSGang He 1655f483c4aSGang He int ocfs2_filecheck_create_sysfs(struct ocfs2_super *osb) 166a860f6ebSGang He { 1675f483c4aSGang He int ret; 1685f483c4aSGang He struct ocfs2_filecheck *fcheck; 1695f483c4aSGang He struct ocfs2_filecheck_sysfs_entry *entry = &osb->osb_fc_ent; 170a860f6ebSGang He 171a860f6ebSGang He fcheck = kmalloc(sizeof(struct ocfs2_filecheck), GFP_NOFS); 1725f483c4aSGang He if (!fcheck) 1735f483c4aSGang He return -ENOMEM; 1745f483c4aSGang He 175a860f6ebSGang He INIT_LIST_HEAD(&fcheck->fc_head); 176a860f6ebSGang He spin_lock_init(&fcheck->fc_lock); 177a860f6ebSGang He fcheck->fc_max = OCFS2_FILECHECK_MINSIZE; 178a860f6ebSGang He fcheck->fc_size = 0; 179a860f6ebSGang He fcheck->fc_done = 0; 180a860f6ebSGang He 1815f483c4aSGang He entry->fs_kobj.kset = osb->osb_dev_kset; 1825f483c4aSGang He init_completion(&entry->fs_kobj_unregister); 1835f483c4aSGang He ret = kobject_init_and_add(&entry->fs_kobj, &ocfs2_ktype_filecheck, 1845f483c4aSGang He NULL, "filecheck"); 1855f483c4aSGang He if (ret) { 186b9fba67bSTobin C. Harding kobject_put(&entry->fs_kobj); 187a860f6ebSGang He kfree(fcheck); 188a860f6ebSGang He return ret; 189a860f6ebSGang He } 190a860f6ebSGang He 1915f483c4aSGang He entry->fs_fcheck = fcheck; 1925f483c4aSGang He return 0; 1935f483c4aSGang He } 1945f483c4aSGang He 1955f483c4aSGang He void ocfs2_filecheck_remove_sysfs(struct ocfs2_super *osb) 196a860f6ebSGang He { 1975f483c4aSGang He if (!osb->osb_fc_ent.fs_fcheck) 1985f483c4aSGang He return; 1995f483c4aSGang He 2005f483c4aSGang He kobject_del(&osb->osb_fc_ent.fs_kobj); 2015f483c4aSGang He kobject_put(&osb->osb_fc_ent.fs_kobj); 2025f483c4aSGang He wait_for_completion(&osb->osb_fc_ent.fs_kobj_unregister); 2035f483c4aSGang He ocfs2_filecheck_sysfs_free(&osb->osb_fc_ent); 204a860f6ebSGang He } 205a860f6ebSGang He 206a860f6ebSGang He static int 207a860f6ebSGang He ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent, 208a860f6ebSGang He unsigned int count); 209a860f6ebSGang He static int 210a860f6ebSGang He ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent, 211a860f6ebSGang He unsigned int len) 212a860f6ebSGang He { 213a860f6ebSGang He int ret; 214a860f6ebSGang He 215a860f6ebSGang He if ((len < OCFS2_FILECHECK_MINSIZE) || (len > OCFS2_FILECHECK_MAXSIZE)) 216a860f6ebSGang He return -EINVAL; 217a860f6ebSGang He 218a860f6ebSGang He spin_lock(&ent->fs_fcheck->fc_lock); 219a860f6ebSGang He if (len < (ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done)) { 2208fc2cb4bSGang He mlog(ML_NOTICE, 221a860f6ebSGang He "Cannot set online file check maximum entry number " 222a860f6ebSGang He "to %u due to too many pending entries(%u)\n", 223a860f6ebSGang He len, ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done); 224a860f6ebSGang He ret = -EBUSY; 225a860f6ebSGang He } else { 226a860f6ebSGang He if (len < ent->fs_fcheck->fc_size) 227a860f6ebSGang He BUG_ON(!ocfs2_filecheck_erase_entries(ent, 228a860f6ebSGang He ent->fs_fcheck->fc_size - len)); 229a860f6ebSGang He 230a860f6ebSGang He ent->fs_fcheck->fc_max = len; 231a860f6ebSGang He ret = 0; 232a860f6ebSGang He } 233a860f6ebSGang He spin_unlock(&ent->fs_fcheck->fc_lock); 234a860f6ebSGang He 235a860f6ebSGang He return ret; 236a860f6ebSGang He } 237a860f6ebSGang He 238a860f6ebSGang He #define OCFS2_FILECHECK_ARGS_LEN 24 239a860f6ebSGang He static int 240a860f6ebSGang He ocfs2_filecheck_args_get_long(const char *buf, size_t count, 241a860f6ebSGang He unsigned long *val) 242a860f6ebSGang He { 243a860f6ebSGang He char buffer[OCFS2_FILECHECK_ARGS_LEN]; 244a860f6ebSGang He 245a860f6ebSGang He memcpy(buffer, buf, count); 246a860f6ebSGang He buffer[count] = '\0'; 247a860f6ebSGang He 248a860f6ebSGang He if (kstrtoul(buffer, 0, val)) 249a860f6ebSGang He return 1; 250a860f6ebSGang He 251a860f6ebSGang He return 0; 252a860f6ebSGang He } 253a860f6ebSGang He 254a860f6ebSGang He static int 255a860f6ebSGang He ocfs2_filecheck_type_parse(const char *name, unsigned int *type) 256a860f6ebSGang He { 257a860f6ebSGang He if (!strncmp(name, "fix", 4)) 258a860f6ebSGang He *type = OCFS2_FILECHECK_TYPE_FIX; 259a860f6ebSGang He else if (!strncmp(name, "check", 6)) 260a860f6ebSGang He *type = OCFS2_FILECHECK_TYPE_CHK; 261a860f6ebSGang He else if (!strncmp(name, "set", 4)) 262a860f6ebSGang He *type = OCFS2_FILECHECK_TYPE_SET; 263a860f6ebSGang He else 264a860f6ebSGang He return 1; 265a860f6ebSGang He 266a860f6ebSGang He return 0; 267a860f6ebSGang He } 268a860f6ebSGang He 269a860f6ebSGang He static int 270a860f6ebSGang He ocfs2_filecheck_args_parse(const char *name, const char *buf, size_t count, 271a860f6ebSGang He struct ocfs2_filecheck_args *args) 272a860f6ebSGang He { 273a860f6ebSGang He unsigned long val = 0; 274a860f6ebSGang He unsigned int type; 275a860f6ebSGang He 276a860f6ebSGang He /* too short/long args length */ 277a860f6ebSGang He if ((count < 1) || (count >= OCFS2_FILECHECK_ARGS_LEN)) 278a860f6ebSGang He return 1; 279a860f6ebSGang He 280a860f6ebSGang He if (ocfs2_filecheck_type_parse(name, &type)) 281a860f6ebSGang He return 1; 282a860f6ebSGang He if (ocfs2_filecheck_args_get_long(buf, count, &val)) 283a860f6ebSGang He return 1; 284a860f6ebSGang He 285a860f6ebSGang He if (val <= 0) 286a860f6ebSGang He return 1; 287a860f6ebSGang He 288a860f6ebSGang He args->fa_type = type; 289a860f6ebSGang He if (type == OCFS2_FILECHECK_TYPE_SET) 290a860f6ebSGang He args->fa_len = (unsigned int)val; 291a860f6ebSGang He else 292a860f6ebSGang He args->fa_ino = val; 293a860f6ebSGang He 294a860f6ebSGang He return 0; 295a860f6ebSGang He } 296a860f6ebSGang He 2975f483c4aSGang He static ssize_t ocfs2_filecheck_attr_show(struct kobject *kobj, 298a860f6ebSGang He struct kobj_attribute *attr, 299a860f6ebSGang He char *buf) 300a860f6ebSGang He { 301a860f6ebSGang He 302a860f6ebSGang He ssize_t ret = 0, total = 0, remain = PAGE_SIZE; 303a860f6ebSGang He unsigned int type; 304a860f6ebSGang He struct ocfs2_filecheck_entry *p; 3055f483c4aSGang He struct ocfs2_filecheck_sysfs_entry *ent = container_of(kobj, 3065f483c4aSGang He struct ocfs2_filecheck_sysfs_entry, fs_kobj); 307a860f6ebSGang He 308a860f6ebSGang He if (ocfs2_filecheck_type_parse(attr->attr.name, &type)) 309a860f6ebSGang He return -EINVAL; 310a860f6ebSGang He 311a860f6ebSGang He if (type == OCFS2_FILECHECK_TYPE_SET) { 312a860f6ebSGang He spin_lock(&ent->fs_fcheck->fc_lock); 313a860f6ebSGang He total = snprintf(buf, remain, "%u\n", ent->fs_fcheck->fc_max); 314a860f6ebSGang He spin_unlock(&ent->fs_fcheck->fc_lock); 315a860f6ebSGang He goto exit; 316a860f6ebSGang He } 317a860f6ebSGang He 318a860f6ebSGang He ret = snprintf(buf, remain, "INO\t\tDONE\tERROR\n"); 319a860f6ebSGang He total += ret; 320a860f6ebSGang He remain -= ret; 321a860f6ebSGang He spin_lock(&ent->fs_fcheck->fc_lock); 322a860f6ebSGang He list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) { 323a860f6ebSGang He if (p->fe_type != type) 324a860f6ebSGang He continue; 325a860f6ebSGang He 326a860f6ebSGang He ret = snprintf(buf + total, remain, "%lu\t\t%u\t%s\n", 327a860f6ebSGang He p->fe_ino, p->fe_done, 328a860f6ebSGang He ocfs2_filecheck_error(p->fe_status)); 329a860f6ebSGang He if (ret < 0) { 330a860f6ebSGang He total = ret; 331a860f6ebSGang He break; 332a860f6ebSGang He } 333a860f6ebSGang He if (ret == remain) { 334a860f6ebSGang He /* snprintf() didn't fit */ 335a860f6ebSGang He total = -E2BIG; 336a860f6ebSGang He break; 337a860f6ebSGang He } 338a860f6ebSGang He total += ret; 339a860f6ebSGang He remain -= ret; 340a860f6ebSGang He } 341a860f6ebSGang He spin_unlock(&ent->fs_fcheck->fc_lock); 342a860f6ebSGang He 343a860f6ebSGang He exit: 344a860f6ebSGang He return total; 345a860f6ebSGang He } 346a860f6ebSGang He 3475f483c4aSGang He static inline int 34839ec3774SGang He ocfs2_filecheck_is_dup_entry(struct ocfs2_filecheck_sysfs_entry *ent, 34939ec3774SGang He unsigned long ino) 35039ec3774SGang He { 35139ec3774SGang He struct ocfs2_filecheck_entry *p; 35239ec3774SGang He 35339ec3774SGang He list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) { 35439ec3774SGang He if (!p->fe_done) { 35539ec3774SGang He if (p->fe_ino == ino) 35639ec3774SGang He return 1; 35739ec3774SGang He } 35839ec3774SGang He } 35939ec3774SGang He 36039ec3774SGang He return 0; 36139ec3774SGang He } 36239ec3774SGang He 36339ec3774SGang He static inline int 364a860f6ebSGang He ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent) 365a860f6ebSGang He { 366a860f6ebSGang He struct ocfs2_filecheck_entry *p; 367a860f6ebSGang He 368a860f6ebSGang He list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) { 369a860f6ebSGang He if (p->fe_done) { 370a860f6ebSGang He list_del(&p->fe_list); 371a860f6ebSGang He kfree(p); 372a860f6ebSGang He ent->fs_fcheck->fc_size--; 373a860f6ebSGang He ent->fs_fcheck->fc_done--; 374a860f6ebSGang He return 1; 375a860f6ebSGang He } 376a860f6ebSGang He } 377a860f6ebSGang He 378a860f6ebSGang He return 0; 379a860f6ebSGang He } 380a860f6ebSGang He 381a860f6ebSGang He static int 382a860f6ebSGang He ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent, 383a860f6ebSGang He unsigned int count) 384a860f6ebSGang He { 385a860f6ebSGang He unsigned int i = 0; 386a860f6ebSGang He unsigned int ret = 0; 387a860f6ebSGang He 388a860f6ebSGang He while (i++ < count) { 389a860f6ebSGang He if (ocfs2_filecheck_erase_entry(ent)) 390a860f6ebSGang He ret++; 391a860f6ebSGang He else 392a860f6ebSGang He break; 393a860f6ebSGang He } 394a860f6ebSGang He 395a860f6ebSGang He return (ret == count ? 1 : 0); 396a860f6ebSGang He } 397a860f6ebSGang He 398a860f6ebSGang He static void 399a860f6ebSGang He ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent, 400a860f6ebSGang He struct ocfs2_filecheck_entry *entry) 401a860f6ebSGang He { 402a860f6ebSGang He spin_lock(&ent->fs_fcheck->fc_lock); 4038fc2cb4bSGang He entry->fe_done = 1; 404a860f6ebSGang He ent->fs_fcheck->fc_done++; 405a860f6ebSGang He spin_unlock(&ent->fs_fcheck->fc_lock); 406a860f6ebSGang He } 407a860f6ebSGang He 408a860f6ebSGang He static unsigned int 4095f483c4aSGang He ocfs2_filecheck_handle(struct ocfs2_super *osb, 410a860f6ebSGang He unsigned long ino, unsigned int flags) 411a860f6ebSGang He { 412a860f6ebSGang He unsigned int ret = OCFS2_FILECHECK_ERR_SUCCESS; 413a860f6ebSGang He struct inode *inode = NULL; 414a860f6ebSGang He int rc; 415a860f6ebSGang He 4165f483c4aSGang He inode = ocfs2_iget(osb, ino, flags, 0); 417a860f6ebSGang He if (IS_ERR(inode)) { 418a860f6ebSGang He rc = (int)(-(long)inode); 419a860f6ebSGang He if (rc >= OCFS2_FILECHECK_ERR_START && 420a860f6ebSGang He rc < OCFS2_FILECHECK_ERR_END) 421a860f6ebSGang He ret = rc; 422a860f6ebSGang He else 423a860f6ebSGang He ret = OCFS2_FILECHECK_ERR_FAILED; 424a860f6ebSGang He } else 425a860f6ebSGang He iput(inode); 426a860f6ebSGang He 427a860f6ebSGang He return ret; 428a860f6ebSGang He } 429a860f6ebSGang He 430a860f6ebSGang He static void 431a860f6ebSGang He ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent, 432a860f6ebSGang He struct ocfs2_filecheck_entry *entry) 433a860f6ebSGang He { 4345f483c4aSGang He struct ocfs2_super *osb = container_of(ent, struct ocfs2_super, 4355f483c4aSGang He osb_fc_ent); 4365f483c4aSGang He 437a860f6ebSGang He if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK) 4385f483c4aSGang He entry->fe_status = ocfs2_filecheck_handle(osb, 439a860f6ebSGang He entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK); 440a860f6ebSGang He else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX) 4415f483c4aSGang He entry->fe_status = ocfs2_filecheck_handle(osb, 442a860f6ebSGang He entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX); 443a860f6ebSGang He else 444a860f6ebSGang He entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED; 445a860f6ebSGang He 446a860f6ebSGang He ocfs2_filecheck_done_entry(ent, entry); 447a860f6ebSGang He } 448a860f6ebSGang He 4495f483c4aSGang He static ssize_t ocfs2_filecheck_attr_store(struct kobject *kobj, 450a860f6ebSGang He struct kobj_attribute *attr, 451a860f6ebSGang He const char *buf, size_t count) 452a860f6ebSGang He { 4535f483c4aSGang He ssize_t ret = 0; 454a860f6ebSGang He struct ocfs2_filecheck_args args; 455a860f6ebSGang He struct ocfs2_filecheck_entry *entry; 4565f483c4aSGang He struct ocfs2_filecheck_sysfs_entry *ent = container_of(kobj, 4575f483c4aSGang He struct ocfs2_filecheck_sysfs_entry, fs_kobj); 458a860f6ebSGang He 459a860f6ebSGang He if (count == 0) 460a860f6ebSGang He return count; 461a860f6ebSGang He 4625f483c4aSGang He if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args)) 463a860f6ebSGang He return -EINVAL; 464a860f6ebSGang He 465a860f6ebSGang He if (args.fa_type == OCFS2_FILECHECK_TYPE_SET) { 466a860f6ebSGang He ret = ocfs2_filecheck_adjust_max(ent, args.fa_len); 467a860f6ebSGang He goto exit; 468a860f6ebSGang He } 469a860f6ebSGang He 470a860f6ebSGang He entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS); 471a860f6ebSGang He if (!entry) { 472a860f6ebSGang He ret = -ENOMEM; 473a860f6ebSGang He goto exit; 474a860f6ebSGang He } 475a860f6ebSGang He 476a860f6ebSGang He spin_lock(&ent->fs_fcheck->fc_lock); 47739ec3774SGang He if (ocfs2_filecheck_is_dup_entry(ent, args.fa_ino)) { 47839ec3774SGang He ret = -EEXIST; 47939ec3774SGang He kfree(entry); 48039ec3774SGang He } else if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) && 481a860f6ebSGang He (ent->fs_fcheck->fc_done == 0)) { 4828fc2cb4bSGang He mlog(ML_NOTICE, 483a860f6ebSGang He "Cannot do more file check " 484a860f6ebSGang He "since file check queue(%u) is full now\n", 485a860f6ebSGang He ent->fs_fcheck->fc_max); 4868fc2cb4bSGang He ret = -EAGAIN; 487a860f6ebSGang He kfree(entry); 488a860f6ebSGang He } else { 489a860f6ebSGang He if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) && 490a860f6ebSGang He (ent->fs_fcheck->fc_done > 0)) { 491a860f6ebSGang He /* Delete the oldest entry which was done, 492a860f6ebSGang He * make sure the entry size in list does 493a860f6ebSGang He * not exceed maximum value 494a860f6ebSGang He */ 495a860f6ebSGang He BUG_ON(!ocfs2_filecheck_erase_entry(ent)); 496a860f6ebSGang He } 497a860f6ebSGang He 498a860f6ebSGang He entry->fe_ino = args.fa_ino; 499a860f6ebSGang He entry->fe_type = args.fa_type; 500a860f6ebSGang He entry->fe_done = 0; 501a860f6ebSGang He entry->fe_status = OCFS2_FILECHECK_ERR_INPROGRESS; 502a860f6ebSGang He list_add_tail(&entry->fe_list, &ent->fs_fcheck->fc_head); 503a860f6ebSGang He ent->fs_fcheck->fc_size++; 504a860f6ebSGang He } 505a860f6ebSGang He spin_unlock(&ent->fs_fcheck->fc_lock); 506a860f6ebSGang He 507a860f6ebSGang He if (!ret) 508a860f6ebSGang He ocfs2_filecheck_handle_entry(ent, entry); 509a860f6ebSGang He 510a860f6ebSGang He exit: 511a860f6ebSGang He return (!ret ? count : ret); 512a860f6ebSGang He } 513