1a860f6ebSGang He /* -*- mode: c; c-basic-offset: 8; -*- 2a860f6ebSGang He * vim: noexpandtab sw=8 ts=8 sts=0: 3a860f6ebSGang He * 4a860f6ebSGang He * filecheck.c 5a860f6ebSGang He * 6a860f6ebSGang He * Code which implements online file check. 7a860f6ebSGang He * 8a860f6ebSGang He * Copyright (C) 2016 SuSE. All rights reserved. 9a860f6ebSGang He * 10a860f6ebSGang He * This program is free software; you can redistribute it and/or 11a860f6ebSGang He * modify it under the terms of the GNU General Public 12a860f6ebSGang He * License as published by the Free Software Foundation, version 2. 13a860f6ebSGang He * 14a860f6ebSGang He * This program is distributed in the hope that it will be useful, 15a860f6ebSGang He * but WITHOUT ANY WARRANTY; without even the implied warranty of 16a860f6ebSGang He * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17a860f6ebSGang He * General Public License for more details. 18a860f6ebSGang He */ 19a860f6ebSGang He 20a860f6ebSGang He #include <linux/list.h> 21a860f6ebSGang He #include <linux/spinlock.h> 22a860f6ebSGang He #include <linux/module.h> 23a860f6ebSGang He #include <linux/slab.h> 24a860f6ebSGang He #include <linux/kmod.h> 25a860f6ebSGang He #include <linux/fs.h> 26a860f6ebSGang He #include <linux/kobject.h> 27a860f6ebSGang He #include <linux/sysfs.h> 28a860f6ebSGang He #include <linux/sysctl.h> 29a860f6ebSGang He #include <cluster/masklog.h> 30a860f6ebSGang He 31a860f6ebSGang He #include "ocfs2.h" 32a860f6ebSGang He #include "ocfs2_fs.h" 33a860f6ebSGang He #include "stackglue.h" 34a860f6ebSGang He #include "inode.h" 35a860f6ebSGang He 36a860f6ebSGang He #include "filecheck.h" 37a860f6ebSGang He 38a860f6ebSGang He 39a860f6ebSGang He /* File check error strings, 40a860f6ebSGang He * must correspond with error number in header file. 41a860f6ebSGang He */ 42a860f6ebSGang He static const char * const ocfs2_filecheck_errs[] = { 43a860f6ebSGang He "SUCCESS", 44a860f6ebSGang He "FAILED", 45a860f6ebSGang He "INPROGRESS", 46a860f6ebSGang He "READONLY", 47a860f6ebSGang He "INJBD", 48a860f6ebSGang He "INVALIDINO", 49a860f6ebSGang He "BLOCKECC", 50a860f6ebSGang He "BLOCKNO", 51a860f6ebSGang He "VALIDFLAG", 52a860f6ebSGang He "GENERATION", 53a860f6ebSGang He "UNSUPPORTED" 54a860f6ebSGang He }; 55a860f6ebSGang He 56a860f6ebSGang He struct ocfs2_filecheck_entry { 57a860f6ebSGang He struct list_head fe_list; 58a860f6ebSGang He unsigned long fe_ino; 59a860f6ebSGang He unsigned int fe_type; 60a860f6ebSGang He unsigned int fe_done:1; 61a860f6ebSGang He unsigned int fe_status:31; 62a860f6ebSGang He }; 63a860f6ebSGang He 64a860f6ebSGang He struct ocfs2_filecheck_args { 65a860f6ebSGang He unsigned int fa_type; 66a860f6ebSGang He union { 67a860f6ebSGang He unsigned long fa_ino; 68a860f6ebSGang He unsigned int fa_len; 69a860f6ebSGang He }; 70a860f6ebSGang He }; 71a860f6ebSGang He 72a860f6ebSGang He static const char * 73a860f6ebSGang He ocfs2_filecheck_error(int errno) 74a860f6ebSGang He { 75a860f6ebSGang He if (!errno) 76a860f6ebSGang He return ocfs2_filecheck_errs[errno]; 77a860f6ebSGang He 78a860f6ebSGang He BUG_ON(errno < OCFS2_FILECHECK_ERR_START || 79a860f6ebSGang He errno > OCFS2_FILECHECK_ERR_END); 80a860f6ebSGang He return ocfs2_filecheck_errs[errno - OCFS2_FILECHECK_ERR_START + 1]; 81a860f6ebSGang He } 82a860f6ebSGang He 83*5f483c4aSGang He static ssize_t ocfs2_filecheck_attr_show(struct kobject *kobj, 84a860f6ebSGang He struct kobj_attribute *attr, 85a860f6ebSGang He char *buf); 86*5f483c4aSGang He static ssize_t ocfs2_filecheck_attr_store(struct kobject *kobj, 87a860f6ebSGang He struct kobj_attribute *attr, 88a860f6ebSGang He const char *buf, size_t count); 89*5f483c4aSGang He static struct kobj_attribute ocfs2_filecheck_attr_chk = 90a860f6ebSGang He __ATTR(check, S_IRUSR | S_IWUSR, 91*5f483c4aSGang He ocfs2_filecheck_attr_show, 92*5f483c4aSGang He ocfs2_filecheck_attr_store); 93*5f483c4aSGang He static struct kobj_attribute ocfs2_filecheck_attr_fix = 94a860f6ebSGang He __ATTR(fix, S_IRUSR | S_IWUSR, 95*5f483c4aSGang He ocfs2_filecheck_attr_show, 96*5f483c4aSGang He ocfs2_filecheck_attr_store); 97*5f483c4aSGang He static struct kobj_attribute ocfs2_filecheck_attr_set = 98a860f6ebSGang He __ATTR(set, S_IRUSR | S_IWUSR, 99*5f483c4aSGang He ocfs2_filecheck_attr_show, 100*5f483c4aSGang He ocfs2_filecheck_attr_store); 101*5f483c4aSGang He static struct attribute *ocfs2_filecheck_attrs[] = { 102*5f483c4aSGang He &ocfs2_filecheck_attr_chk.attr, 103*5f483c4aSGang He &ocfs2_filecheck_attr_fix.attr, 104*5f483c4aSGang He &ocfs2_filecheck_attr_set.attr, 105*5f483c4aSGang He NULL 106*5f483c4aSGang He }; 107*5f483c4aSGang He 108*5f483c4aSGang He static void ocfs2_filecheck_release(struct kobject *kobj) 109*5f483c4aSGang He { 110*5f483c4aSGang He struct ocfs2_filecheck_sysfs_entry *entry = container_of(kobj, 111*5f483c4aSGang He struct ocfs2_filecheck_sysfs_entry, fs_kobj); 112*5f483c4aSGang He 113*5f483c4aSGang He complete(&entry->fs_kobj_unregister); 114*5f483c4aSGang He } 115*5f483c4aSGang He 116*5f483c4aSGang He static ssize_t 117*5f483c4aSGang He ocfs2_filecheck_show(struct kobject *kobj, struct attribute *attr, char *buf) 118*5f483c4aSGang He { 119*5f483c4aSGang He ssize_t ret = -EIO; 120*5f483c4aSGang He struct kobj_attribute *kattr = container_of(attr, 121*5f483c4aSGang He struct kobj_attribute, attr); 122*5f483c4aSGang He 123*5f483c4aSGang He kobject_get(kobj); 124*5f483c4aSGang He if (kattr->show) 125*5f483c4aSGang He ret = kattr->show(kobj, kattr, buf); 126*5f483c4aSGang He kobject_put(kobj); 127*5f483c4aSGang He return ret; 128*5f483c4aSGang He } 129*5f483c4aSGang He 130*5f483c4aSGang He static ssize_t 131*5f483c4aSGang He ocfs2_filecheck_store(struct kobject *kobj, struct attribute *attr, 132*5f483c4aSGang He const char *buf, size_t count) 133*5f483c4aSGang He { 134*5f483c4aSGang He ssize_t ret = -EIO; 135*5f483c4aSGang He struct kobj_attribute *kattr = container_of(attr, 136*5f483c4aSGang He struct kobj_attribute, attr); 137*5f483c4aSGang He 138*5f483c4aSGang He kobject_get(kobj); 139*5f483c4aSGang He if (kattr->store) 140*5f483c4aSGang He ret = kattr->store(kobj, kattr, buf, count); 141*5f483c4aSGang He kobject_put(kobj); 142*5f483c4aSGang He return ret; 143*5f483c4aSGang He } 144*5f483c4aSGang He 145*5f483c4aSGang He static const struct sysfs_ops ocfs2_filecheck_ops = { 146*5f483c4aSGang He .show = ocfs2_filecheck_show, 147*5f483c4aSGang He .store = ocfs2_filecheck_store, 148*5f483c4aSGang He }; 149*5f483c4aSGang He 150*5f483c4aSGang He static struct kobj_type ocfs2_ktype_filecheck = { 151*5f483c4aSGang He .default_attrs = ocfs2_filecheck_attrs, 152*5f483c4aSGang He .sysfs_ops = &ocfs2_filecheck_ops, 153*5f483c4aSGang He .release = ocfs2_filecheck_release, 154*5f483c4aSGang He }; 155a860f6ebSGang He 156a860f6ebSGang He static void 157a860f6ebSGang He ocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry *entry) 158a860f6ebSGang He { 159a860f6ebSGang He struct ocfs2_filecheck_entry *p; 160a860f6ebSGang He 161a860f6ebSGang He spin_lock(&entry->fs_fcheck->fc_lock); 162a860f6ebSGang He while (!list_empty(&entry->fs_fcheck->fc_head)) { 163a860f6ebSGang He p = list_first_entry(&entry->fs_fcheck->fc_head, 164a860f6ebSGang He struct ocfs2_filecheck_entry, fe_list); 165a860f6ebSGang He list_del(&p->fe_list); 166a860f6ebSGang He BUG_ON(!p->fe_done); /* To free a undone file check entry */ 167a860f6ebSGang He kfree(p); 168a860f6ebSGang He } 169a860f6ebSGang He spin_unlock(&entry->fs_fcheck->fc_lock); 170a860f6ebSGang He 171a860f6ebSGang He kfree(entry->fs_fcheck); 172*5f483c4aSGang He entry->fs_fcheck = NULL; 173a860f6ebSGang He } 174a860f6ebSGang He 175*5f483c4aSGang He int ocfs2_filecheck_create_sysfs(struct ocfs2_super *osb) 176a860f6ebSGang He { 177*5f483c4aSGang He int ret; 178*5f483c4aSGang He struct ocfs2_filecheck *fcheck; 179*5f483c4aSGang He struct ocfs2_filecheck_sysfs_entry *entry = &osb->osb_fc_ent; 180a860f6ebSGang He 181a860f6ebSGang He fcheck = kmalloc(sizeof(struct ocfs2_filecheck), GFP_NOFS); 182*5f483c4aSGang He if (!fcheck) 183*5f483c4aSGang He return -ENOMEM; 184*5f483c4aSGang He 185a860f6ebSGang He INIT_LIST_HEAD(&fcheck->fc_head); 186a860f6ebSGang He spin_lock_init(&fcheck->fc_lock); 187a860f6ebSGang He fcheck->fc_max = OCFS2_FILECHECK_MINSIZE; 188a860f6ebSGang He fcheck->fc_size = 0; 189a860f6ebSGang He fcheck->fc_done = 0; 190a860f6ebSGang He 191*5f483c4aSGang He entry->fs_kobj.kset = osb->osb_dev_kset; 192*5f483c4aSGang He init_completion(&entry->fs_kobj_unregister); 193*5f483c4aSGang He ret = kobject_init_and_add(&entry->fs_kobj, &ocfs2_ktype_filecheck, 194*5f483c4aSGang He NULL, "filecheck"); 195*5f483c4aSGang He if (ret) { 196a860f6ebSGang He kfree(fcheck); 197a860f6ebSGang He return ret; 198a860f6ebSGang He } 199a860f6ebSGang He 200*5f483c4aSGang He entry->fs_fcheck = fcheck; 201*5f483c4aSGang He return 0; 202*5f483c4aSGang He } 203*5f483c4aSGang He 204*5f483c4aSGang He void ocfs2_filecheck_remove_sysfs(struct ocfs2_super *osb) 205a860f6ebSGang He { 206*5f483c4aSGang He if (!osb->osb_fc_ent.fs_fcheck) 207*5f483c4aSGang He return; 208*5f483c4aSGang He 209*5f483c4aSGang He kobject_del(&osb->osb_fc_ent.fs_kobj); 210*5f483c4aSGang He kobject_put(&osb->osb_fc_ent.fs_kobj); 211*5f483c4aSGang He wait_for_completion(&osb->osb_fc_ent.fs_kobj_unregister); 212*5f483c4aSGang He ocfs2_filecheck_sysfs_free(&osb->osb_fc_ent); 213a860f6ebSGang He } 214a860f6ebSGang He 215a860f6ebSGang He static int 216a860f6ebSGang He ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent, 217a860f6ebSGang He unsigned int count); 218a860f6ebSGang He static int 219a860f6ebSGang He ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent, 220a860f6ebSGang He unsigned int len) 221a860f6ebSGang He { 222a860f6ebSGang He int ret; 223a860f6ebSGang He 224a860f6ebSGang He if ((len < OCFS2_FILECHECK_MINSIZE) || (len > OCFS2_FILECHECK_MAXSIZE)) 225a860f6ebSGang He return -EINVAL; 226a860f6ebSGang He 227a860f6ebSGang He spin_lock(&ent->fs_fcheck->fc_lock); 228a860f6ebSGang He if (len < (ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done)) { 2298fc2cb4bSGang He mlog(ML_NOTICE, 230a860f6ebSGang He "Cannot set online file check maximum entry number " 231a860f6ebSGang He "to %u due to too many pending entries(%u)\n", 232a860f6ebSGang He len, ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done); 233a860f6ebSGang He ret = -EBUSY; 234a860f6ebSGang He } else { 235a860f6ebSGang He if (len < ent->fs_fcheck->fc_size) 236a860f6ebSGang He BUG_ON(!ocfs2_filecheck_erase_entries(ent, 237a860f6ebSGang He ent->fs_fcheck->fc_size - len)); 238a860f6ebSGang He 239a860f6ebSGang He ent->fs_fcheck->fc_max = len; 240a860f6ebSGang He ret = 0; 241a860f6ebSGang He } 242a860f6ebSGang He spin_unlock(&ent->fs_fcheck->fc_lock); 243a860f6ebSGang He 244a860f6ebSGang He return ret; 245a860f6ebSGang He } 246a860f6ebSGang He 247a860f6ebSGang He #define OCFS2_FILECHECK_ARGS_LEN 24 248a860f6ebSGang He static int 249a860f6ebSGang He ocfs2_filecheck_args_get_long(const char *buf, size_t count, 250a860f6ebSGang He unsigned long *val) 251a860f6ebSGang He { 252a860f6ebSGang He char buffer[OCFS2_FILECHECK_ARGS_LEN]; 253a860f6ebSGang He 254a860f6ebSGang He memcpy(buffer, buf, count); 255a860f6ebSGang He buffer[count] = '\0'; 256a860f6ebSGang He 257a860f6ebSGang He if (kstrtoul(buffer, 0, val)) 258a860f6ebSGang He return 1; 259a860f6ebSGang He 260a860f6ebSGang He return 0; 261a860f6ebSGang He } 262a860f6ebSGang He 263a860f6ebSGang He static int 264a860f6ebSGang He ocfs2_filecheck_type_parse(const char *name, unsigned int *type) 265a860f6ebSGang He { 266a860f6ebSGang He if (!strncmp(name, "fix", 4)) 267a860f6ebSGang He *type = OCFS2_FILECHECK_TYPE_FIX; 268a860f6ebSGang He else if (!strncmp(name, "check", 6)) 269a860f6ebSGang He *type = OCFS2_FILECHECK_TYPE_CHK; 270a860f6ebSGang He else if (!strncmp(name, "set", 4)) 271a860f6ebSGang He *type = OCFS2_FILECHECK_TYPE_SET; 272a860f6ebSGang He else 273a860f6ebSGang He return 1; 274a860f6ebSGang He 275a860f6ebSGang He return 0; 276a860f6ebSGang He } 277a860f6ebSGang He 278a860f6ebSGang He static int 279a860f6ebSGang He ocfs2_filecheck_args_parse(const char *name, const char *buf, size_t count, 280a860f6ebSGang He struct ocfs2_filecheck_args *args) 281a860f6ebSGang He { 282a860f6ebSGang He unsigned long val = 0; 283a860f6ebSGang He unsigned int type; 284a860f6ebSGang He 285a860f6ebSGang He /* too short/long args length */ 286a860f6ebSGang He if ((count < 1) || (count >= OCFS2_FILECHECK_ARGS_LEN)) 287a860f6ebSGang He return 1; 288a860f6ebSGang He 289a860f6ebSGang He if (ocfs2_filecheck_type_parse(name, &type)) 290a860f6ebSGang He return 1; 291a860f6ebSGang He if (ocfs2_filecheck_args_get_long(buf, count, &val)) 292a860f6ebSGang He return 1; 293a860f6ebSGang He 294a860f6ebSGang He if (val <= 0) 295a860f6ebSGang He return 1; 296a860f6ebSGang He 297a860f6ebSGang He args->fa_type = type; 298a860f6ebSGang He if (type == OCFS2_FILECHECK_TYPE_SET) 299a860f6ebSGang He args->fa_len = (unsigned int)val; 300a860f6ebSGang He else 301a860f6ebSGang He args->fa_ino = val; 302a860f6ebSGang He 303a860f6ebSGang He return 0; 304a860f6ebSGang He } 305a860f6ebSGang He 306*5f483c4aSGang He static ssize_t ocfs2_filecheck_attr_show(struct kobject *kobj, 307a860f6ebSGang He struct kobj_attribute *attr, 308a860f6ebSGang He char *buf) 309a860f6ebSGang He { 310a860f6ebSGang He 311a860f6ebSGang He ssize_t ret = 0, total = 0, remain = PAGE_SIZE; 312a860f6ebSGang He unsigned int type; 313a860f6ebSGang He struct ocfs2_filecheck_entry *p; 314*5f483c4aSGang He struct ocfs2_filecheck_sysfs_entry *ent = container_of(kobj, 315*5f483c4aSGang He struct ocfs2_filecheck_sysfs_entry, fs_kobj); 316a860f6ebSGang He 317a860f6ebSGang He if (ocfs2_filecheck_type_parse(attr->attr.name, &type)) 318a860f6ebSGang He return -EINVAL; 319a860f6ebSGang He 320a860f6ebSGang He if (type == OCFS2_FILECHECK_TYPE_SET) { 321a860f6ebSGang He spin_lock(&ent->fs_fcheck->fc_lock); 322a860f6ebSGang He total = snprintf(buf, remain, "%u\n", ent->fs_fcheck->fc_max); 323a860f6ebSGang He spin_unlock(&ent->fs_fcheck->fc_lock); 324a860f6ebSGang He goto exit; 325a860f6ebSGang He } 326a860f6ebSGang He 327a860f6ebSGang He ret = snprintf(buf, remain, "INO\t\tDONE\tERROR\n"); 328a860f6ebSGang He total += ret; 329a860f6ebSGang He remain -= ret; 330a860f6ebSGang He spin_lock(&ent->fs_fcheck->fc_lock); 331a860f6ebSGang He list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) { 332a860f6ebSGang He if (p->fe_type != type) 333a860f6ebSGang He continue; 334a860f6ebSGang He 335a860f6ebSGang He ret = snprintf(buf + total, remain, "%lu\t\t%u\t%s\n", 336a860f6ebSGang He p->fe_ino, p->fe_done, 337a860f6ebSGang He ocfs2_filecheck_error(p->fe_status)); 338a860f6ebSGang He if (ret < 0) { 339a860f6ebSGang He total = ret; 340a860f6ebSGang He break; 341a860f6ebSGang He } 342a860f6ebSGang He if (ret == remain) { 343a860f6ebSGang He /* snprintf() didn't fit */ 344a860f6ebSGang He total = -E2BIG; 345a860f6ebSGang He break; 346a860f6ebSGang He } 347a860f6ebSGang He total += ret; 348a860f6ebSGang He remain -= ret; 349a860f6ebSGang He } 350a860f6ebSGang He spin_unlock(&ent->fs_fcheck->fc_lock); 351a860f6ebSGang He 352a860f6ebSGang He exit: 353a860f6ebSGang He return total; 354a860f6ebSGang He } 355a860f6ebSGang He 356*5f483c4aSGang He static inline int 357a860f6ebSGang He ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent) 358a860f6ebSGang He { 359a860f6ebSGang He struct ocfs2_filecheck_entry *p; 360a860f6ebSGang He 361a860f6ebSGang He list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) { 362a860f6ebSGang He if (p->fe_done) { 363a860f6ebSGang He list_del(&p->fe_list); 364a860f6ebSGang He kfree(p); 365a860f6ebSGang He ent->fs_fcheck->fc_size--; 366a860f6ebSGang He ent->fs_fcheck->fc_done--; 367a860f6ebSGang He return 1; 368a860f6ebSGang He } 369a860f6ebSGang He } 370a860f6ebSGang He 371a860f6ebSGang He return 0; 372a860f6ebSGang He } 373a860f6ebSGang He 374a860f6ebSGang He static int 375a860f6ebSGang He ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent, 376a860f6ebSGang He unsigned int count) 377a860f6ebSGang He { 378a860f6ebSGang He unsigned int i = 0; 379a860f6ebSGang He unsigned int ret = 0; 380a860f6ebSGang He 381a860f6ebSGang He while (i++ < count) { 382a860f6ebSGang He if (ocfs2_filecheck_erase_entry(ent)) 383a860f6ebSGang He ret++; 384a860f6ebSGang He else 385a860f6ebSGang He break; 386a860f6ebSGang He } 387a860f6ebSGang He 388a860f6ebSGang He return (ret == count ? 1 : 0); 389a860f6ebSGang He } 390a860f6ebSGang He 391a860f6ebSGang He static void 392a860f6ebSGang He ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent, 393a860f6ebSGang He struct ocfs2_filecheck_entry *entry) 394a860f6ebSGang He { 395a860f6ebSGang He spin_lock(&ent->fs_fcheck->fc_lock); 3968fc2cb4bSGang He entry->fe_done = 1; 397a860f6ebSGang He ent->fs_fcheck->fc_done++; 398a860f6ebSGang He spin_unlock(&ent->fs_fcheck->fc_lock); 399a860f6ebSGang He } 400a860f6ebSGang He 401a860f6ebSGang He static unsigned int 402*5f483c4aSGang He ocfs2_filecheck_handle(struct ocfs2_super *osb, 403a860f6ebSGang He unsigned long ino, unsigned int flags) 404a860f6ebSGang He { 405a860f6ebSGang He unsigned int ret = OCFS2_FILECHECK_ERR_SUCCESS; 406a860f6ebSGang He struct inode *inode = NULL; 407a860f6ebSGang He int rc; 408a860f6ebSGang He 409*5f483c4aSGang He inode = ocfs2_iget(osb, ino, flags, 0); 410a860f6ebSGang He if (IS_ERR(inode)) { 411a860f6ebSGang He rc = (int)(-(long)inode); 412a860f6ebSGang He if (rc >= OCFS2_FILECHECK_ERR_START && 413a860f6ebSGang He rc < OCFS2_FILECHECK_ERR_END) 414a860f6ebSGang He ret = rc; 415a860f6ebSGang He else 416a860f6ebSGang He ret = OCFS2_FILECHECK_ERR_FAILED; 417a860f6ebSGang He } else 418a860f6ebSGang He iput(inode); 419a860f6ebSGang He 420a860f6ebSGang He return ret; 421a860f6ebSGang He } 422a860f6ebSGang He 423a860f6ebSGang He static void 424a860f6ebSGang He ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent, 425a860f6ebSGang He struct ocfs2_filecheck_entry *entry) 426a860f6ebSGang He { 427*5f483c4aSGang He struct ocfs2_super *osb = container_of(ent, struct ocfs2_super, 428*5f483c4aSGang He osb_fc_ent); 429*5f483c4aSGang He 430a860f6ebSGang He if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK) 431*5f483c4aSGang He entry->fe_status = ocfs2_filecheck_handle(osb, 432a860f6ebSGang He entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK); 433a860f6ebSGang He else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX) 434*5f483c4aSGang He entry->fe_status = ocfs2_filecheck_handle(osb, 435a860f6ebSGang He entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX); 436a860f6ebSGang He else 437a860f6ebSGang He entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED; 438a860f6ebSGang He 439a860f6ebSGang He ocfs2_filecheck_done_entry(ent, entry); 440a860f6ebSGang He } 441a860f6ebSGang He 442*5f483c4aSGang He static ssize_t ocfs2_filecheck_attr_store(struct kobject *kobj, 443a860f6ebSGang He struct kobj_attribute *attr, 444a860f6ebSGang He const char *buf, size_t count) 445a860f6ebSGang He { 446*5f483c4aSGang He ssize_t ret = 0; 447a860f6ebSGang He struct ocfs2_filecheck_args args; 448a860f6ebSGang He struct ocfs2_filecheck_entry *entry; 449*5f483c4aSGang He struct ocfs2_filecheck_sysfs_entry *ent = container_of(kobj, 450*5f483c4aSGang He struct ocfs2_filecheck_sysfs_entry, fs_kobj); 451a860f6ebSGang He 452a860f6ebSGang He if (count == 0) 453a860f6ebSGang He return count; 454a860f6ebSGang He 455*5f483c4aSGang He if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args)) 456a860f6ebSGang He return -EINVAL; 457a860f6ebSGang He 458a860f6ebSGang He if (args.fa_type == OCFS2_FILECHECK_TYPE_SET) { 459a860f6ebSGang He ret = ocfs2_filecheck_adjust_max(ent, args.fa_len); 460a860f6ebSGang He goto exit; 461a860f6ebSGang He } 462a860f6ebSGang He 463a860f6ebSGang He entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS); 464a860f6ebSGang He if (!entry) { 465a860f6ebSGang He ret = -ENOMEM; 466a860f6ebSGang He goto exit; 467a860f6ebSGang He } 468a860f6ebSGang He 469a860f6ebSGang He spin_lock(&ent->fs_fcheck->fc_lock); 470a860f6ebSGang He if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) && 471a860f6ebSGang He (ent->fs_fcheck->fc_done == 0)) { 4728fc2cb4bSGang He mlog(ML_NOTICE, 473a860f6ebSGang He "Cannot do more file check " 474a860f6ebSGang He "since file check queue(%u) is full now\n", 475a860f6ebSGang He ent->fs_fcheck->fc_max); 4768fc2cb4bSGang He ret = -EAGAIN; 477a860f6ebSGang He kfree(entry); 478a860f6ebSGang He } else { 479a860f6ebSGang He if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) && 480a860f6ebSGang He (ent->fs_fcheck->fc_done > 0)) { 481a860f6ebSGang He /* Delete the oldest entry which was done, 482a860f6ebSGang He * make sure the entry size in list does 483a860f6ebSGang He * not exceed maximum value 484a860f6ebSGang He */ 485a860f6ebSGang He BUG_ON(!ocfs2_filecheck_erase_entry(ent)); 486a860f6ebSGang He } 487a860f6ebSGang He 488a860f6ebSGang He entry->fe_ino = args.fa_ino; 489a860f6ebSGang He entry->fe_type = args.fa_type; 490a860f6ebSGang He entry->fe_done = 0; 491a860f6ebSGang He entry->fe_status = OCFS2_FILECHECK_ERR_INPROGRESS; 492a860f6ebSGang He list_add_tail(&entry->fe_list, &ent->fs_fcheck->fc_head); 493a860f6ebSGang He ent->fs_fcheck->fc_size++; 494a860f6ebSGang He } 495a860f6ebSGang He spin_unlock(&ent->fs_fcheck->fc_lock); 496a860f6ebSGang He 497a860f6ebSGang He if (!ret) 498a860f6ebSGang He ocfs2_filecheck_handle_entry(ent, entry); 499a860f6ebSGang He 500a860f6ebSGang He exit: 501a860f6ebSGang He return (!ret ? count : ret); 502a860f6ebSGang He } 503