1*a860f6ebSGang He /* -*- mode: c; c-basic-offset: 8; -*- 2*a860f6ebSGang He * vim: noexpandtab sw=8 ts=8 sts=0: 3*a860f6ebSGang He * 4*a860f6ebSGang He * filecheck.c 5*a860f6ebSGang He * 6*a860f6ebSGang He * Code which implements online file check. 7*a860f6ebSGang He * 8*a860f6ebSGang He * Copyright (C) 2016 SuSE. All rights reserved. 9*a860f6ebSGang He * 10*a860f6ebSGang He * This program is free software; you can redistribute it and/or 11*a860f6ebSGang He * modify it under the terms of the GNU General Public 12*a860f6ebSGang He * License as published by the Free Software Foundation, version 2. 13*a860f6ebSGang He * 14*a860f6ebSGang He * This program is distributed in the hope that it will be useful, 15*a860f6ebSGang He * but WITHOUT ANY WARRANTY; without even the implied warranty of 16*a860f6ebSGang He * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17*a860f6ebSGang He * General Public License for more details. 18*a860f6ebSGang He */ 19*a860f6ebSGang He 20*a860f6ebSGang He #include <linux/list.h> 21*a860f6ebSGang He #include <linux/spinlock.h> 22*a860f6ebSGang He #include <linux/module.h> 23*a860f6ebSGang He #include <linux/slab.h> 24*a860f6ebSGang He #include <linux/kmod.h> 25*a860f6ebSGang He #include <linux/fs.h> 26*a860f6ebSGang He #include <linux/kobject.h> 27*a860f6ebSGang He #include <linux/sysfs.h> 28*a860f6ebSGang He #include <linux/sysctl.h> 29*a860f6ebSGang He #include <cluster/masklog.h> 30*a860f6ebSGang He 31*a860f6ebSGang He #include "ocfs2.h" 32*a860f6ebSGang He #include "ocfs2_fs.h" 33*a860f6ebSGang He #include "stackglue.h" 34*a860f6ebSGang He #include "inode.h" 35*a860f6ebSGang He 36*a860f6ebSGang He #include "filecheck.h" 37*a860f6ebSGang He 38*a860f6ebSGang He 39*a860f6ebSGang He /* File check error strings, 40*a860f6ebSGang He * must correspond with error number in header file. 41*a860f6ebSGang He */ 42*a860f6ebSGang He static const char * const ocfs2_filecheck_errs[] = { 43*a860f6ebSGang He "SUCCESS", 44*a860f6ebSGang He "FAILED", 45*a860f6ebSGang He "INPROGRESS", 46*a860f6ebSGang He "READONLY", 47*a860f6ebSGang He "INJBD", 48*a860f6ebSGang He "INVALIDINO", 49*a860f6ebSGang He "BLOCKECC", 50*a860f6ebSGang He "BLOCKNO", 51*a860f6ebSGang He "VALIDFLAG", 52*a860f6ebSGang He "GENERATION", 53*a860f6ebSGang He "UNSUPPORTED" 54*a860f6ebSGang He }; 55*a860f6ebSGang He 56*a860f6ebSGang He static DEFINE_SPINLOCK(ocfs2_filecheck_sysfs_lock); 57*a860f6ebSGang He static LIST_HEAD(ocfs2_filecheck_sysfs_list); 58*a860f6ebSGang He 59*a860f6ebSGang He struct ocfs2_filecheck { 60*a860f6ebSGang He struct list_head fc_head; /* File check entry list head */ 61*a860f6ebSGang He spinlock_t fc_lock; 62*a860f6ebSGang He unsigned int fc_max; /* Maximum number of entry in list */ 63*a860f6ebSGang He unsigned int fc_size; /* Current entry count in list */ 64*a860f6ebSGang He unsigned int fc_done; /* Finished entry count in list */ 65*a860f6ebSGang He }; 66*a860f6ebSGang He 67*a860f6ebSGang He struct ocfs2_filecheck_sysfs_entry { /* sysfs entry per mounting */ 68*a860f6ebSGang He struct list_head fs_list; 69*a860f6ebSGang He atomic_t fs_count; 70*a860f6ebSGang He struct super_block *fs_sb; 71*a860f6ebSGang He struct kset *fs_devicekset; 72*a860f6ebSGang He struct kset *fs_fcheckkset; 73*a860f6ebSGang He struct ocfs2_filecheck *fs_fcheck; 74*a860f6ebSGang He }; 75*a860f6ebSGang He 76*a860f6ebSGang He #define OCFS2_FILECHECK_MAXSIZE 100 77*a860f6ebSGang He #define OCFS2_FILECHECK_MINSIZE 10 78*a860f6ebSGang He 79*a860f6ebSGang He /* File check operation type */ 80*a860f6ebSGang He enum { 81*a860f6ebSGang He OCFS2_FILECHECK_TYPE_CHK = 0, /* Check a file(inode) */ 82*a860f6ebSGang He OCFS2_FILECHECK_TYPE_FIX, /* Fix a file(inode) */ 83*a860f6ebSGang He OCFS2_FILECHECK_TYPE_SET = 100 /* Set entry list maximum size */ 84*a860f6ebSGang He }; 85*a860f6ebSGang He 86*a860f6ebSGang He struct ocfs2_filecheck_entry { 87*a860f6ebSGang He struct list_head fe_list; 88*a860f6ebSGang He unsigned long fe_ino; 89*a860f6ebSGang He unsigned int fe_type; 90*a860f6ebSGang He unsigned int fe_done:1; 91*a860f6ebSGang He unsigned int fe_status:31; 92*a860f6ebSGang He }; 93*a860f6ebSGang He 94*a860f6ebSGang He struct ocfs2_filecheck_args { 95*a860f6ebSGang He unsigned int fa_type; 96*a860f6ebSGang He union { 97*a860f6ebSGang He unsigned long fa_ino; 98*a860f6ebSGang He unsigned int fa_len; 99*a860f6ebSGang He }; 100*a860f6ebSGang He }; 101*a860f6ebSGang He 102*a860f6ebSGang He static const char * 103*a860f6ebSGang He ocfs2_filecheck_error(int errno) 104*a860f6ebSGang He { 105*a860f6ebSGang He if (!errno) 106*a860f6ebSGang He return ocfs2_filecheck_errs[errno]; 107*a860f6ebSGang He 108*a860f6ebSGang He BUG_ON(errno < OCFS2_FILECHECK_ERR_START || 109*a860f6ebSGang He errno > OCFS2_FILECHECK_ERR_END); 110*a860f6ebSGang He return ocfs2_filecheck_errs[errno - OCFS2_FILECHECK_ERR_START + 1]; 111*a860f6ebSGang He } 112*a860f6ebSGang He 113*a860f6ebSGang He static ssize_t ocfs2_filecheck_show(struct kobject *kobj, 114*a860f6ebSGang He struct kobj_attribute *attr, 115*a860f6ebSGang He char *buf); 116*a860f6ebSGang He static ssize_t ocfs2_filecheck_store(struct kobject *kobj, 117*a860f6ebSGang He struct kobj_attribute *attr, 118*a860f6ebSGang He const char *buf, size_t count); 119*a860f6ebSGang He static struct kobj_attribute ocfs2_attr_filecheck_chk = 120*a860f6ebSGang He __ATTR(check, S_IRUSR | S_IWUSR, 121*a860f6ebSGang He ocfs2_filecheck_show, 122*a860f6ebSGang He ocfs2_filecheck_store); 123*a860f6ebSGang He static struct kobj_attribute ocfs2_attr_filecheck_fix = 124*a860f6ebSGang He __ATTR(fix, S_IRUSR | S_IWUSR, 125*a860f6ebSGang He ocfs2_filecheck_show, 126*a860f6ebSGang He ocfs2_filecheck_store); 127*a860f6ebSGang He static struct kobj_attribute ocfs2_attr_filecheck_set = 128*a860f6ebSGang He __ATTR(set, S_IRUSR | S_IWUSR, 129*a860f6ebSGang He ocfs2_filecheck_show, 130*a860f6ebSGang He ocfs2_filecheck_store); 131*a860f6ebSGang He 132*a860f6ebSGang He static int ocfs2_filecheck_sysfs_wait(atomic_t *p) 133*a860f6ebSGang He { 134*a860f6ebSGang He schedule(); 135*a860f6ebSGang He return 0; 136*a860f6ebSGang He } 137*a860f6ebSGang He 138*a860f6ebSGang He static void 139*a860f6ebSGang He ocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry *entry) 140*a860f6ebSGang He { 141*a860f6ebSGang He struct ocfs2_filecheck_entry *p; 142*a860f6ebSGang He 143*a860f6ebSGang He if (!atomic_dec_and_test(&entry->fs_count)) 144*a860f6ebSGang He wait_on_atomic_t(&entry->fs_count, ocfs2_filecheck_sysfs_wait, 145*a860f6ebSGang He TASK_UNINTERRUPTIBLE); 146*a860f6ebSGang He 147*a860f6ebSGang He spin_lock(&entry->fs_fcheck->fc_lock); 148*a860f6ebSGang He while (!list_empty(&entry->fs_fcheck->fc_head)) { 149*a860f6ebSGang He p = list_first_entry(&entry->fs_fcheck->fc_head, 150*a860f6ebSGang He struct ocfs2_filecheck_entry, fe_list); 151*a860f6ebSGang He list_del(&p->fe_list); 152*a860f6ebSGang He BUG_ON(!p->fe_done); /* To free a undone file check entry */ 153*a860f6ebSGang He kfree(p); 154*a860f6ebSGang He } 155*a860f6ebSGang He spin_unlock(&entry->fs_fcheck->fc_lock); 156*a860f6ebSGang He 157*a860f6ebSGang He kset_unregister(entry->fs_fcheckkset); 158*a860f6ebSGang He kset_unregister(entry->fs_devicekset); 159*a860f6ebSGang He kfree(entry->fs_fcheck); 160*a860f6ebSGang He kfree(entry); 161*a860f6ebSGang He } 162*a860f6ebSGang He 163*a860f6ebSGang He static void 164*a860f6ebSGang He ocfs2_filecheck_sysfs_add(struct ocfs2_filecheck_sysfs_entry *entry) 165*a860f6ebSGang He { 166*a860f6ebSGang He spin_lock(&ocfs2_filecheck_sysfs_lock); 167*a860f6ebSGang He list_add_tail(&entry->fs_list, &ocfs2_filecheck_sysfs_list); 168*a860f6ebSGang He spin_unlock(&ocfs2_filecheck_sysfs_lock); 169*a860f6ebSGang He } 170*a860f6ebSGang He 171*a860f6ebSGang He static int ocfs2_filecheck_sysfs_del(const char *devname) 172*a860f6ebSGang He { 173*a860f6ebSGang He struct ocfs2_filecheck_sysfs_entry *p; 174*a860f6ebSGang He 175*a860f6ebSGang He spin_lock(&ocfs2_filecheck_sysfs_lock); 176*a860f6ebSGang He list_for_each_entry(p, &ocfs2_filecheck_sysfs_list, fs_list) { 177*a860f6ebSGang He if (!strcmp(p->fs_sb->s_id, devname)) { 178*a860f6ebSGang He list_del(&p->fs_list); 179*a860f6ebSGang He spin_unlock(&ocfs2_filecheck_sysfs_lock); 180*a860f6ebSGang He ocfs2_filecheck_sysfs_free(p); 181*a860f6ebSGang He return 0; 182*a860f6ebSGang He } 183*a860f6ebSGang He } 184*a860f6ebSGang He spin_unlock(&ocfs2_filecheck_sysfs_lock); 185*a860f6ebSGang He return 1; 186*a860f6ebSGang He } 187*a860f6ebSGang He 188*a860f6ebSGang He static void 189*a860f6ebSGang He ocfs2_filecheck_sysfs_put(struct ocfs2_filecheck_sysfs_entry *entry) 190*a860f6ebSGang He { 191*a860f6ebSGang He if (atomic_dec_and_test(&entry->fs_count)) 192*a860f6ebSGang He wake_up_atomic_t(&entry->fs_count); 193*a860f6ebSGang He } 194*a860f6ebSGang He 195*a860f6ebSGang He static struct ocfs2_filecheck_sysfs_entry * 196*a860f6ebSGang He ocfs2_filecheck_sysfs_get(const char *devname) 197*a860f6ebSGang He { 198*a860f6ebSGang He struct ocfs2_filecheck_sysfs_entry *p = NULL; 199*a860f6ebSGang He 200*a860f6ebSGang He spin_lock(&ocfs2_filecheck_sysfs_lock); 201*a860f6ebSGang He list_for_each_entry(p, &ocfs2_filecheck_sysfs_list, fs_list) { 202*a860f6ebSGang He if (!strcmp(p->fs_sb->s_id, devname)) { 203*a860f6ebSGang He atomic_inc(&p->fs_count); 204*a860f6ebSGang He spin_unlock(&ocfs2_filecheck_sysfs_lock); 205*a860f6ebSGang He return p; 206*a860f6ebSGang He } 207*a860f6ebSGang He } 208*a860f6ebSGang He spin_unlock(&ocfs2_filecheck_sysfs_lock); 209*a860f6ebSGang He return NULL; 210*a860f6ebSGang He } 211*a860f6ebSGang He 212*a860f6ebSGang He int ocfs2_filecheck_create_sysfs(struct super_block *sb) 213*a860f6ebSGang He { 214*a860f6ebSGang He int ret = 0; 215*a860f6ebSGang He struct kset *device_kset = NULL; 216*a860f6ebSGang He struct kset *fcheck_kset = NULL; 217*a860f6ebSGang He struct ocfs2_filecheck *fcheck = NULL; 218*a860f6ebSGang He struct ocfs2_filecheck_sysfs_entry *entry = NULL; 219*a860f6ebSGang He struct attribute **attrs = NULL; 220*a860f6ebSGang He struct attribute_group attrgp; 221*a860f6ebSGang He 222*a860f6ebSGang He if (!ocfs2_kset) 223*a860f6ebSGang He return -ENOMEM; 224*a860f6ebSGang He 225*a860f6ebSGang He attrs = kmalloc(sizeof(struct attribute *) * 4, GFP_NOFS); 226*a860f6ebSGang He if (!attrs) { 227*a860f6ebSGang He ret = -ENOMEM; 228*a860f6ebSGang He goto error; 229*a860f6ebSGang He } else { 230*a860f6ebSGang He attrs[0] = &ocfs2_attr_filecheck_chk.attr; 231*a860f6ebSGang He attrs[1] = &ocfs2_attr_filecheck_fix.attr; 232*a860f6ebSGang He attrs[2] = &ocfs2_attr_filecheck_set.attr; 233*a860f6ebSGang He attrs[3] = NULL; 234*a860f6ebSGang He memset(&attrgp, 0, sizeof(attrgp)); 235*a860f6ebSGang He attrgp.attrs = attrs; 236*a860f6ebSGang He } 237*a860f6ebSGang He 238*a860f6ebSGang He fcheck = kmalloc(sizeof(struct ocfs2_filecheck), GFP_NOFS); 239*a860f6ebSGang He if (!fcheck) { 240*a860f6ebSGang He ret = -ENOMEM; 241*a860f6ebSGang He goto error; 242*a860f6ebSGang He } else { 243*a860f6ebSGang He INIT_LIST_HEAD(&fcheck->fc_head); 244*a860f6ebSGang He spin_lock_init(&fcheck->fc_lock); 245*a860f6ebSGang He fcheck->fc_max = OCFS2_FILECHECK_MINSIZE; 246*a860f6ebSGang He fcheck->fc_size = 0; 247*a860f6ebSGang He fcheck->fc_done = 0; 248*a860f6ebSGang He } 249*a860f6ebSGang He 250*a860f6ebSGang He if (strlen(sb->s_id) <= 0) { 251*a860f6ebSGang He mlog(ML_ERROR, 252*a860f6ebSGang He "Cannot get device basename when create filecheck sysfs\n"); 253*a860f6ebSGang He ret = -ENODEV; 254*a860f6ebSGang He goto error; 255*a860f6ebSGang He } 256*a860f6ebSGang He 257*a860f6ebSGang He device_kset = kset_create_and_add(sb->s_id, NULL, &ocfs2_kset->kobj); 258*a860f6ebSGang He if (!device_kset) { 259*a860f6ebSGang He ret = -ENOMEM; 260*a860f6ebSGang He goto error; 261*a860f6ebSGang He } 262*a860f6ebSGang He 263*a860f6ebSGang He fcheck_kset = kset_create_and_add("filecheck", NULL, 264*a860f6ebSGang He &device_kset->kobj); 265*a860f6ebSGang He if (!fcheck_kset) { 266*a860f6ebSGang He ret = -ENOMEM; 267*a860f6ebSGang He goto error; 268*a860f6ebSGang He } 269*a860f6ebSGang He 270*a860f6ebSGang He ret = sysfs_create_group(&fcheck_kset->kobj, &attrgp); 271*a860f6ebSGang He if (ret) 272*a860f6ebSGang He goto error; 273*a860f6ebSGang He 274*a860f6ebSGang He entry = kmalloc(sizeof(struct ocfs2_filecheck_sysfs_entry), GFP_NOFS); 275*a860f6ebSGang He if (!entry) { 276*a860f6ebSGang He ret = -ENOMEM; 277*a860f6ebSGang He goto error; 278*a860f6ebSGang He } else { 279*a860f6ebSGang He atomic_set(&entry->fs_count, 1); 280*a860f6ebSGang He entry->fs_sb = sb; 281*a860f6ebSGang He entry->fs_devicekset = device_kset; 282*a860f6ebSGang He entry->fs_fcheckkset = fcheck_kset; 283*a860f6ebSGang He entry->fs_fcheck = fcheck; 284*a860f6ebSGang He ocfs2_filecheck_sysfs_add(entry); 285*a860f6ebSGang He } 286*a860f6ebSGang He 287*a860f6ebSGang He kfree(attrs); 288*a860f6ebSGang He return 0; 289*a860f6ebSGang He 290*a860f6ebSGang He error: 291*a860f6ebSGang He kfree(attrs); 292*a860f6ebSGang He kfree(entry); 293*a860f6ebSGang He kfree(fcheck); 294*a860f6ebSGang He kset_unregister(fcheck_kset); 295*a860f6ebSGang He kset_unregister(device_kset); 296*a860f6ebSGang He return ret; 297*a860f6ebSGang He } 298*a860f6ebSGang He 299*a860f6ebSGang He int ocfs2_filecheck_remove_sysfs(struct super_block *sb) 300*a860f6ebSGang He { 301*a860f6ebSGang He return ocfs2_filecheck_sysfs_del(sb->s_id); 302*a860f6ebSGang He } 303*a860f6ebSGang He 304*a860f6ebSGang He static int 305*a860f6ebSGang He ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent, 306*a860f6ebSGang He unsigned int count); 307*a860f6ebSGang He static int 308*a860f6ebSGang He ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent, 309*a860f6ebSGang He unsigned int len) 310*a860f6ebSGang He { 311*a860f6ebSGang He int ret; 312*a860f6ebSGang He 313*a860f6ebSGang He if ((len < OCFS2_FILECHECK_MINSIZE) || (len > OCFS2_FILECHECK_MAXSIZE)) 314*a860f6ebSGang He return -EINVAL; 315*a860f6ebSGang He 316*a860f6ebSGang He spin_lock(&ent->fs_fcheck->fc_lock); 317*a860f6ebSGang He if (len < (ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done)) { 318*a860f6ebSGang He mlog(ML_ERROR, 319*a860f6ebSGang He "Cannot set online file check maximum entry number " 320*a860f6ebSGang He "to %u due to too many pending entries(%u)\n", 321*a860f6ebSGang He len, ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done); 322*a860f6ebSGang He ret = -EBUSY; 323*a860f6ebSGang He } else { 324*a860f6ebSGang He if (len < ent->fs_fcheck->fc_size) 325*a860f6ebSGang He BUG_ON(!ocfs2_filecheck_erase_entries(ent, 326*a860f6ebSGang He ent->fs_fcheck->fc_size - len)); 327*a860f6ebSGang He 328*a860f6ebSGang He ent->fs_fcheck->fc_max = len; 329*a860f6ebSGang He ret = 0; 330*a860f6ebSGang He } 331*a860f6ebSGang He spin_unlock(&ent->fs_fcheck->fc_lock); 332*a860f6ebSGang He 333*a860f6ebSGang He return ret; 334*a860f6ebSGang He } 335*a860f6ebSGang He 336*a860f6ebSGang He #define OCFS2_FILECHECK_ARGS_LEN 24 337*a860f6ebSGang He static int 338*a860f6ebSGang He ocfs2_filecheck_args_get_long(const char *buf, size_t count, 339*a860f6ebSGang He unsigned long *val) 340*a860f6ebSGang He { 341*a860f6ebSGang He char buffer[OCFS2_FILECHECK_ARGS_LEN]; 342*a860f6ebSGang He 343*a860f6ebSGang He memcpy(buffer, buf, count); 344*a860f6ebSGang He buffer[count] = '\0'; 345*a860f6ebSGang He 346*a860f6ebSGang He if (kstrtoul(buffer, 0, val)) 347*a860f6ebSGang He return 1; 348*a860f6ebSGang He 349*a860f6ebSGang He return 0; 350*a860f6ebSGang He } 351*a860f6ebSGang He 352*a860f6ebSGang He static int 353*a860f6ebSGang He ocfs2_filecheck_type_parse(const char *name, unsigned int *type) 354*a860f6ebSGang He { 355*a860f6ebSGang He if (!strncmp(name, "fix", 4)) 356*a860f6ebSGang He *type = OCFS2_FILECHECK_TYPE_FIX; 357*a860f6ebSGang He else if (!strncmp(name, "check", 6)) 358*a860f6ebSGang He *type = OCFS2_FILECHECK_TYPE_CHK; 359*a860f6ebSGang He else if (!strncmp(name, "set", 4)) 360*a860f6ebSGang He *type = OCFS2_FILECHECK_TYPE_SET; 361*a860f6ebSGang He else 362*a860f6ebSGang He return 1; 363*a860f6ebSGang He 364*a860f6ebSGang He return 0; 365*a860f6ebSGang He } 366*a860f6ebSGang He 367*a860f6ebSGang He static int 368*a860f6ebSGang He ocfs2_filecheck_args_parse(const char *name, const char *buf, size_t count, 369*a860f6ebSGang He struct ocfs2_filecheck_args *args) 370*a860f6ebSGang He { 371*a860f6ebSGang He unsigned long val = 0; 372*a860f6ebSGang He unsigned int type; 373*a860f6ebSGang He 374*a860f6ebSGang He /* too short/long args length */ 375*a860f6ebSGang He if ((count < 1) || (count >= OCFS2_FILECHECK_ARGS_LEN)) 376*a860f6ebSGang He return 1; 377*a860f6ebSGang He 378*a860f6ebSGang He if (ocfs2_filecheck_type_parse(name, &type)) 379*a860f6ebSGang He return 1; 380*a860f6ebSGang He if (ocfs2_filecheck_args_get_long(buf, count, &val)) 381*a860f6ebSGang He return 1; 382*a860f6ebSGang He 383*a860f6ebSGang He if (val <= 0) 384*a860f6ebSGang He return 1; 385*a860f6ebSGang He 386*a860f6ebSGang He args->fa_type = type; 387*a860f6ebSGang He if (type == OCFS2_FILECHECK_TYPE_SET) 388*a860f6ebSGang He args->fa_len = (unsigned int)val; 389*a860f6ebSGang He else 390*a860f6ebSGang He args->fa_ino = val; 391*a860f6ebSGang He 392*a860f6ebSGang He return 0; 393*a860f6ebSGang He } 394*a860f6ebSGang He 395*a860f6ebSGang He static ssize_t ocfs2_filecheck_show(struct kobject *kobj, 396*a860f6ebSGang He struct kobj_attribute *attr, 397*a860f6ebSGang He char *buf) 398*a860f6ebSGang He { 399*a860f6ebSGang He 400*a860f6ebSGang He ssize_t ret = 0, total = 0, remain = PAGE_SIZE; 401*a860f6ebSGang He unsigned int type; 402*a860f6ebSGang He struct ocfs2_filecheck_entry *p; 403*a860f6ebSGang He struct ocfs2_filecheck_sysfs_entry *ent; 404*a860f6ebSGang He 405*a860f6ebSGang He if (ocfs2_filecheck_type_parse(attr->attr.name, &type)) 406*a860f6ebSGang He return -EINVAL; 407*a860f6ebSGang He 408*a860f6ebSGang He ent = ocfs2_filecheck_sysfs_get(kobj->parent->name); 409*a860f6ebSGang He if (!ent) { 410*a860f6ebSGang He mlog(ML_ERROR, 411*a860f6ebSGang He "Cannot get the corresponding entry via device basename %s\n", 412*a860f6ebSGang He kobj->name); 413*a860f6ebSGang He return -ENODEV; 414*a860f6ebSGang He } 415*a860f6ebSGang He 416*a860f6ebSGang He if (type == OCFS2_FILECHECK_TYPE_SET) { 417*a860f6ebSGang He spin_lock(&ent->fs_fcheck->fc_lock); 418*a860f6ebSGang He total = snprintf(buf, remain, "%u\n", ent->fs_fcheck->fc_max); 419*a860f6ebSGang He spin_unlock(&ent->fs_fcheck->fc_lock); 420*a860f6ebSGang He goto exit; 421*a860f6ebSGang He } 422*a860f6ebSGang He 423*a860f6ebSGang He ret = snprintf(buf, remain, "INO\t\tDONE\tERROR\n"); 424*a860f6ebSGang He total += ret; 425*a860f6ebSGang He remain -= ret; 426*a860f6ebSGang He spin_lock(&ent->fs_fcheck->fc_lock); 427*a860f6ebSGang He list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) { 428*a860f6ebSGang He if (p->fe_type != type) 429*a860f6ebSGang He continue; 430*a860f6ebSGang He 431*a860f6ebSGang He ret = snprintf(buf + total, remain, "%lu\t\t%u\t%s\n", 432*a860f6ebSGang He p->fe_ino, p->fe_done, 433*a860f6ebSGang He ocfs2_filecheck_error(p->fe_status)); 434*a860f6ebSGang He if (ret < 0) { 435*a860f6ebSGang He total = ret; 436*a860f6ebSGang He break; 437*a860f6ebSGang He } 438*a860f6ebSGang He if (ret == remain) { 439*a860f6ebSGang He /* snprintf() didn't fit */ 440*a860f6ebSGang He total = -E2BIG; 441*a860f6ebSGang He break; 442*a860f6ebSGang He } 443*a860f6ebSGang He total += ret; 444*a860f6ebSGang He remain -= ret; 445*a860f6ebSGang He } 446*a860f6ebSGang He spin_unlock(&ent->fs_fcheck->fc_lock); 447*a860f6ebSGang He 448*a860f6ebSGang He exit: 449*a860f6ebSGang He ocfs2_filecheck_sysfs_put(ent); 450*a860f6ebSGang He return total; 451*a860f6ebSGang He } 452*a860f6ebSGang He 453*a860f6ebSGang He static int 454*a860f6ebSGang He ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent) 455*a860f6ebSGang He { 456*a860f6ebSGang He struct ocfs2_filecheck_entry *p; 457*a860f6ebSGang He 458*a860f6ebSGang He list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) { 459*a860f6ebSGang He if (p->fe_done) { 460*a860f6ebSGang He list_del(&p->fe_list); 461*a860f6ebSGang He kfree(p); 462*a860f6ebSGang He ent->fs_fcheck->fc_size--; 463*a860f6ebSGang He ent->fs_fcheck->fc_done--; 464*a860f6ebSGang He return 1; 465*a860f6ebSGang He } 466*a860f6ebSGang He } 467*a860f6ebSGang He 468*a860f6ebSGang He return 0; 469*a860f6ebSGang He } 470*a860f6ebSGang He 471*a860f6ebSGang He static int 472*a860f6ebSGang He ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent, 473*a860f6ebSGang He unsigned int count) 474*a860f6ebSGang He { 475*a860f6ebSGang He unsigned int i = 0; 476*a860f6ebSGang He unsigned int ret = 0; 477*a860f6ebSGang He 478*a860f6ebSGang He while (i++ < count) { 479*a860f6ebSGang He if (ocfs2_filecheck_erase_entry(ent)) 480*a860f6ebSGang He ret++; 481*a860f6ebSGang He else 482*a860f6ebSGang He break; 483*a860f6ebSGang He } 484*a860f6ebSGang He 485*a860f6ebSGang He return (ret == count ? 1 : 0); 486*a860f6ebSGang He } 487*a860f6ebSGang He 488*a860f6ebSGang He static void 489*a860f6ebSGang He ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent, 490*a860f6ebSGang He struct ocfs2_filecheck_entry *entry) 491*a860f6ebSGang He { 492*a860f6ebSGang He entry->fe_done = 1; 493*a860f6ebSGang He spin_lock(&ent->fs_fcheck->fc_lock); 494*a860f6ebSGang He ent->fs_fcheck->fc_done++; 495*a860f6ebSGang He spin_unlock(&ent->fs_fcheck->fc_lock); 496*a860f6ebSGang He } 497*a860f6ebSGang He 498*a860f6ebSGang He static unsigned int 499*a860f6ebSGang He ocfs2_filecheck_handle(struct super_block *sb, 500*a860f6ebSGang He unsigned long ino, unsigned int flags) 501*a860f6ebSGang He { 502*a860f6ebSGang He unsigned int ret = OCFS2_FILECHECK_ERR_SUCCESS; 503*a860f6ebSGang He struct inode *inode = NULL; 504*a860f6ebSGang He int rc; 505*a860f6ebSGang He 506*a860f6ebSGang He inode = ocfs2_iget(OCFS2_SB(sb), ino, flags, 0); 507*a860f6ebSGang He if (IS_ERR(inode)) { 508*a860f6ebSGang He rc = (int)(-(long)inode); 509*a860f6ebSGang He if (rc >= OCFS2_FILECHECK_ERR_START && 510*a860f6ebSGang He rc < OCFS2_FILECHECK_ERR_END) 511*a860f6ebSGang He ret = rc; 512*a860f6ebSGang He else 513*a860f6ebSGang He ret = OCFS2_FILECHECK_ERR_FAILED; 514*a860f6ebSGang He } else 515*a860f6ebSGang He iput(inode); 516*a860f6ebSGang He 517*a860f6ebSGang He return ret; 518*a860f6ebSGang He } 519*a860f6ebSGang He 520*a860f6ebSGang He static void 521*a860f6ebSGang He ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent, 522*a860f6ebSGang He struct ocfs2_filecheck_entry *entry) 523*a860f6ebSGang He { 524*a860f6ebSGang He if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK) 525*a860f6ebSGang He entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb, 526*a860f6ebSGang He entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK); 527*a860f6ebSGang He else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX) 528*a860f6ebSGang He entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb, 529*a860f6ebSGang He entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX); 530*a860f6ebSGang He else 531*a860f6ebSGang He entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED; 532*a860f6ebSGang He 533*a860f6ebSGang He ocfs2_filecheck_done_entry(ent, entry); 534*a860f6ebSGang He } 535*a860f6ebSGang He 536*a860f6ebSGang He static ssize_t ocfs2_filecheck_store(struct kobject *kobj, 537*a860f6ebSGang He struct kobj_attribute *attr, 538*a860f6ebSGang He const char *buf, size_t count) 539*a860f6ebSGang He { 540*a860f6ebSGang He struct ocfs2_filecheck_args args; 541*a860f6ebSGang He struct ocfs2_filecheck_entry *entry; 542*a860f6ebSGang He struct ocfs2_filecheck_sysfs_entry *ent; 543*a860f6ebSGang He ssize_t ret = 0; 544*a860f6ebSGang He 545*a860f6ebSGang He if (count == 0) 546*a860f6ebSGang He return count; 547*a860f6ebSGang He 548*a860f6ebSGang He if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args)) { 549*a860f6ebSGang He mlog(ML_ERROR, "Invalid arguments for online file check\n"); 550*a860f6ebSGang He return -EINVAL; 551*a860f6ebSGang He } 552*a860f6ebSGang He 553*a860f6ebSGang He ent = ocfs2_filecheck_sysfs_get(kobj->parent->name); 554*a860f6ebSGang He if (!ent) { 555*a860f6ebSGang He mlog(ML_ERROR, 556*a860f6ebSGang He "Cannot get the corresponding entry via device basename %s\n", 557*a860f6ebSGang He kobj->parent->name); 558*a860f6ebSGang He return -ENODEV; 559*a860f6ebSGang He } 560*a860f6ebSGang He 561*a860f6ebSGang He if (args.fa_type == OCFS2_FILECHECK_TYPE_SET) { 562*a860f6ebSGang He ret = ocfs2_filecheck_adjust_max(ent, args.fa_len); 563*a860f6ebSGang He goto exit; 564*a860f6ebSGang He } 565*a860f6ebSGang He 566*a860f6ebSGang He entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS); 567*a860f6ebSGang He if (!entry) { 568*a860f6ebSGang He ret = -ENOMEM; 569*a860f6ebSGang He goto exit; 570*a860f6ebSGang He } 571*a860f6ebSGang He 572*a860f6ebSGang He spin_lock(&ent->fs_fcheck->fc_lock); 573*a860f6ebSGang He if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) && 574*a860f6ebSGang He (ent->fs_fcheck->fc_done == 0)) { 575*a860f6ebSGang He mlog(ML_ERROR, 576*a860f6ebSGang He "Cannot do more file check " 577*a860f6ebSGang He "since file check queue(%u) is full now\n", 578*a860f6ebSGang He ent->fs_fcheck->fc_max); 579*a860f6ebSGang He ret = -EBUSY; 580*a860f6ebSGang He kfree(entry); 581*a860f6ebSGang He } else { 582*a860f6ebSGang He if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) && 583*a860f6ebSGang He (ent->fs_fcheck->fc_done > 0)) { 584*a860f6ebSGang He /* Delete the oldest entry which was done, 585*a860f6ebSGang He * make sure the entry size in list does 586*a860f6ebSGang He * not exceed maximum value 587*a860f6ebSGang He */ 588*a860f6ebSGang He BUG_ON(!ocfs2_filecheck_erase_entry(ent)); 589*a860f6ebSGang He } 590*a860f6ebSGang He 591*a860f6ebSGang He entry->fe_ino = args.fa_ino; 592*a860f6ebSGang He entry->fe_type = args.fa_type; 593*a860f6ebSGang He entry->fe_done = 0; 594*a860f6ebSGang He entry->fe_status = OCFS2_FILECHECK_ERR_INPROGRESS; 595*a860f6ebSGang He list_add_tail(&entry->fe_list, &ent->fs_fcheck->fc_head); 596*a860f6ebSGang He ent->fs_fcheck->fc_size++; 597*a860f6ebSGang He } 598*a860f6ebSGang He spin_unlock(&ent->fs_fcheck->fc_lock); 599*a860f6ebSGang He 600*a860f6ebSGang He if (!ret) 601*a860f6ebSGang He ocfs2_filecheck_handle_entry(ent, entry); 602*a860f6ebSGang He 603*a860f6ebSGang He exit: 604*a860f6ebSGang He ocfs2_filecheck_sysfs_put(ent); 605*a860f6ebSGang He return (!ret ? count : ret); 606*a860f6ebSGang He } 607