0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/list.h>
0011 #include <linux/spinlock.h>
0012 #include <linux/module.h>
0013 #include <linux/slab.h>
0014 #include <linux/kmod.h>
0015 #include <linux/fs.h>
0016 #include <linux/kobject.h>
0017 #include <linux/sysfs.h>
0018 #include <linux/sysctl.h>
0019 #include <cluster/masklog.h>
0020
0021 #include "ocfs2.h"
0022 #include "ocfs2_fs.h"
0023 #include "stackglue.h"
0024 #include "inode.h"
0025
0026 #include "filecheck.h"
0027
0028
0029
0030
0031
0032 static const char * const ocfs2_filecheck_errs[] = {
0033 "SUCCESS",
0034 "FAILED",
0035 "INPROGRESS",
0036 "READONLY",
0037 "INJBD",
0038 "INVALIDINO",
0039 "BLOCKECC",
0040 "BLOCKNO",
0041 "VALIDFLAG",
0042 "GENERATION",
0043 "UNSUPPORTED"
0044 };
0045
0046 struct ocfs2_filecheck_entry {
0047 struct list_head fe_list;
0048 unsigned long fe_ino;
0049 unsigned int fe_type;
0050 unsigned int fe_done:1;
0051 unsigned int fe_status:31;
0052 };
0053
0054 struct ocfs2_filecheck_args {
0055 unsigned int fa_type;
0056 union {
0057 unsigned long fa_ino;
0058 unsigned int fa_len;
0059 };
0060 };
0061
0062 static const char *
0063 ocfs2_filecheck_error(int errno)
0064 {
0065 if (!errno)
0066 return ocfs2_filecheck_errs[errno];
0067
0068 BUG_ON(errno < OCFS2_FILECHECK_ERR_START ||
0069 errno > OCFS2_FILECHECK_ERR_END);
0070 return ocfs2_filecheck_errs[errno - OCFS2_FILECHECK_ERR_START + 1];
0071 }
0072
0073 static ssize_t ocfs2_filecheck_attr_show(struct kobject *kobj,
0074 struct kobj_attribute *attr,
0075 char *buf);
0076 static ssize_t ocfs2_filecheck_attr_store(struct kobject *kobj,
0077 struct kobj_attribute *attr,
0078 const char *buf, size_t count);
0079 static struct kobj_attribute ocfs2_filecheck_attr_chk =
0080 __ATTR(check, S_IRUSR | S_IWUSR,
0081 ocfs2_filecheck_attr_show,
0082 ocfs2_filecheck_attr_store);
0083 static struct kobj_attribute ocfs2_filecheck_attr_fix =
0084 __ATTR(fix, S_IRUSR | S_IWUSR,
0085 ocfs2_filecheck_attr_show,
0086 ocfs2_filecheck_attr_store);
0087 static struct kobj_attribute ocfs2_filecheck_attr_set =
0088 __ATTR(set, S_IRUSR | S_IWUSR,
0089 ocfs2_filecheck_attr_show,
0090 ocfs2_filecheck_attr_store);
0091 static struct attribute *ocfs2_filecheck_attrs[] = {
0092 &ocfs2_filecheck_attr_chk.attr,
0093 &ocfs2_filecheck_attr_fix.attr,
0094 &ocfs2_filecheck_attr_set.attr,
0095 NULL
0096 };
0097 ATTRIBUTE_GROUPS(ocfs2_filecheck);
0098
0099 static void ocfs2_filecheck_release(struct kobject *kobj)
0100 {
0101 struct ocfs2_filecheck_sysfs_entry *entry = container_of(kobj,
0102 struct ocfs2_filecheck_sysfs_entry, fs_kobj);
0103
0104 complete(&entry->fs_kobj_unregister);
0105 }
0106
0107 static ssize_t
0108 ocfs2_filecheck_show(struct kobject *kobj, struct attribute *attr, char *buf)
0109 {
0110 ssize_t ret = -EIO;
0111 struct kobj_attribute *kattr = container_of(attr,
0112 struct kobj_attribute, attr);
0113
0114 kobject_get(kobj);
0115 if (kattr->show)
0116 ret = kattr->show(kobj, kattr, buf);
0117 kobject_put(kobj);
0118 return ret;
0119 }
0120
0121 static ssize_t
0122 ocfs2_filecheck_store(struct kobject *kobj, struct attribute *attr,
0123 const char *buf, size_t count)
0124 {
0125 ssize_t ret = -EIO;
0126 struct kobj_attribute *kattr = container_of(attr,
0127 struct kobj_attribute, attr);
0128
0129 kobject_get(kobj);
0130 if (kattr->store)
0131 ret = kattr->store(kobj, kattr, buf, count);
0132 kobject_put(kobj);
0133 return ret;
0134 }
0135
0136 static const struct sysfs_ops ocfs2_filecheck_ops = {
0137 .show = ocfs2_filecheck_show,
0138 .store = ocfs2_filecheck_store,
0139 };
0140
0141 static struct kobj_type ocfs2_ktype_filecheck = {
0142 .default_groups = ocfs2_filecheck_groups,
0143 .sysfs_ops = &ocfs2_filecheck_ops,
0144 .release = ocfs2_filecheck_release,
0145 };
0146
0147 static void
0148 ocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry *entry)
0149 {
0150 struct ocfs2_filecheck_entry *p;
0151
0152 spin_lock(&entry->fs_fcheck->fc_lock);
0153 while (!list_empty(&entry->fs_fcheck->fc_head)) {
0154 p = list_first_entry(&entry->fs_fcheck->fc_head,
0155 struct ocfs2_filecheck_entry, fe_list);
0156 list_del(&p->fe_list);
0157 BUG_ON(!p->fe_done);
0158 kfree(p);
0159 }
0160 spin_unlock(&entry->fs_fcheck->fc_lock);
0161
0162 kfree(entry->fs_fcheck);
0163 entry->fs_fcheck = NULL;
0164 }
0165
0166 int ocfs2_filecheck_create_sysfs(struct ocfs2_super *osb)
0167 {
0168 int ret;
0169 struct ocfs2_filecheck *fcheck;
0170 struct ocfs2_filecheck_sysfs_entry *entry = &osb->osb_fc_ent;
0171
0172 fcheck = kmalloc(sizeof(struct ocfs2_filecheck), GFP_NOFS);
0173 if (!fcheck)
0174 return -ENOMEM;
0175
0176 INIT_LIST_HEAD(&fcheck->fc_head);
0177 spin_lock_init(&fcheck->fc_lock);
0178 fcheck->fc_max = OCFS2_FILECHECK_MINSIZE;
0179 fcheck->fc_size = 0;
0180 fcheck->fc_done = 0;
0181
0182 entry->fs_kobj.kset = osb->osb_dev_kset;
0183 init_completion(&entry->fs_kobj_unregister);
0184 ret = kobject_init_and_add(&entry->fs_kobj, &ocfs2_ktype_filecheck,
0185 NULL, "filecheck");
0186 if (ret) {
0187 kobject_put(&entry->fs_kobj);
0188 kfree(fcheck);
0189 return ret;
0190 }
0191
0192 entry->fs_fcheck = fcheck;
0193 return 0;
0194 }
0195
0196 void ocfs2_filecheck_remove_sysfs(struct ocfs2_super *osb)
0197 {
0198 if (!osb->osb_fc_ent.fs_fcheck)
0199 return;
0200
0201 kobject_del(&osb->osb_fc_ent.fs_kobj);
0202 kobject_put(&osb->osb_fc_ent.fs_kobj);
0203 wait_for_completion(&osb->osb_fc_ent.fs_kobj_unregister);
0204 ocfs2_filecheck_sysfs_free(&osb->osb_fc_ent);
0205 }
0206
0207 static int
0208 ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
0209 unsigned int count);
0210 static int
0211 ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent,
0212 unsigned int len)
0213 {
0214 int ret;
0215
0216 if ((len < OCFS2_FILECHECK_MINSIZE) || (len > OCFS2_FILECHECK_MAXSIZE))
0217 return -EINVAL;
0218
0219 spin_lock(&ent->fs_fcheck->fc_lock);
0220 if (len < (ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done)) {
0221 mlog(ML_NOTICE,
0222 "Cannot set online file check maximum entry number "
0223 "to %u due to too many pending entries(%u)\n",
0224 len, ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done);
0225 ret = -EBUSY;
0226 } else {
0227 if (len < ent->fs_fcheck->fc_size)
0228 BUG_ON(!ocfs2_filecheck_erase_entries(ent,
0229 ent->fs_fcheck->fc_size - len));
0230
0231 ent->fs_fcheck->fc_max = len;
0232 ret = 0;
0233 }
0234 spin_unlock(&ent->fs_fcheck->fc_lock);
0235
0236 return ret;
0237 }
0238
0239 #define OCFS2_FILECHECK_ARGS_LEN 24
0240 static int
0241 ocfs2_filecheck_args_get_long(const char *buf, size_t count,
0242 unsigned long *val)
0243 {
0244 char buffer[OCFS2_FILECHECK_ARGS_LEN];
0245
0246 memcpy(buffer, buf, count);
0247 buffer[count] = '\0';
0248
0249 if (kstrtoul(buffer, 0, val))
0250 return 1;
0251
0252 return 0;
0253 }
0254
0255 static int
0256 ocfs2_filecheck_type_parse(const char *name, unsigned int *type)
0257 {
0258 if (!strncmp(name, "fix", 4))
0259 *type = OCFS2_FILECHECK_TYPE_FIX;
0260 else if (!strncmp(name, "check", 6))
0261 *type = OCFS2_FILECHECK_TYPE_CHK;
0262 else if (!strncmp(name, "set", 4))
0263 *type = OCFS2_FILECHECK_TYPE_SET;
0264 else
0265 return 1;
0266
0267 return 0;
0268 }
0269
0270 static int
0271 ocfs2_filecheck_args_parse(const char *name, const char *buf, size_t count,
0272 struct ocfs2_filecheck_args *args)
0273 {
0274 unsigned long val = 0;
0275 unsigned int type;
0276
0277
0278 if ((count < 1) || (count >= OCFS2_FILECHECK_ARGS_LEN))
0279 return 1;
0280
0281 if (ocfs2_filecheck_type_parse(name, &type))
0282 return 1;
0283 if (ocfs2_filecheck_args_get_long(buf, count, &val))
0284 return 1;
0285
0286 if (val <= 0)
0287 return 1;
0288
0289 args->fa_type = type;
0290 if (type == OCFS2_FILECHECK_TYPE_SET)
0291 args->fa_len = (unsigned int)val;
0292 else
0293 args->fa_ino = val;
0294
0295 return 0;
0296 }
0297
0298 static ssize_t ocfs2_filecheck_attr_show(struct kobject *kobj,
0299 struct kobj_attribute *attr,
0300 char *buf)
0301 {
0302
0303 ssize_t ret = 0, total = 0, remain = PAGE_SIZE;
0304 unsigned int type;
0305 struct ocfs2_filecheck_entry *p;
0306 struct ocfs2_filecheck_sysfs_entry *ent = container_of(kobj,
0307 struct ocfs2_filecheck_sysfs_entry, fs_kobj);
0308
0309 if (ocfs2_filecheck_type_parse(attr->attr.name, &type))
0310 return -EINVAL;
0311
0312 if (type == OCFS2_FILECHECK_TYPE_SET) {
0313 spin_lock(&ent->fs_fcheck->fc_lock);
0314 total = snprintf(buf, remain, "%u\n", ent->fs_fcheck->fc_max);
0315 spin_unlock(&ent->fs_fcheck->fc_lock);
0316 goto exit;
0317 }
0318
0319 ret = snprintf(buf, remain, "INO\t\tDONE\tERROR\n");
0320 total += ret;
0321 remain -= ret;
0322 spin_lock(&ent->fs_fcheck->fc_lock);
0323 list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
0324 if (p->fe_type != type)
0325 continue;
0326
0327 ret = snprintf(buf + total, remain, "%lu\t\t%u\t%s\n",
0328 p->fe_ino, p->fe_done,
0329 ocfs2_filecheck_error(p->fe_status));
0330 if (ret >= remain) {
0331
0332 total = -E2BIG;
0333 break;
0334 }
0335 total += ret;
0336 remain -= ret;
0337 }
0338 spin_unlock(&ent->fs_fcheck->fc_lock);
0339
0340 exit:
0341 return total;
0342 }
0343
0344 static inline int
0345 ocfs2_filecheck_is_dup_entry(struct ocfs2_filecheck_sysfs_entry *ent,
0346 unsigned long ino)
0347 {
0348 struct ocfs2_filecheck_entry *p;
0349
0350 list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
0351 if (!p->fe_done) {
0352 if (p->fe_ino == ino)
0353 return 1;
0354 }
0355 }
0356
0357 return 0;
0358 }
0359
0360 static inline int
0361 ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
0362 {
0363 struct ocfs2_filecheck_entry *p;
0364
0365 list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
0366 if (p->fe_done) {
0367 list_del(&p->fe_list);
0368 kfree(p);
0369 ent->fs_fcheck->fc_size--;
0370 ent->fs_fcheck->fc_done--;
0371 return 1;
0372 }
0373 }
0374
0375 return 0;
0376 }
0377
0378 static int
0379 ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
0380 unsigned int count)
0381 {
0382 unsigned int i = 0;
0383 unsigned int ret = 0;
0384
0385 while (i++ < count) {
0386 if (ocfs2_filecheck_erase_entry(ent))
0387 ret++;
0388 else
0389 break;
0390 }
0391
0392 return (ret == count ? 1 : 0);
0393 }
0394
0395 static void
0396 ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent,
0397 struct ocfs2_filecheck_entry *entry)
0398 {
0399 spin_lock(&ent->fs_fcheck->fc_lock);
0400 entry->fe_done = 1;
0401 ent->fs_fcheck->fc_done++;
0402 spin_unlock(&ent->fs_fcheck->fc_lock);
0403 }
0404
0405 static unsigned int
0406 ocfs2_filecheck_handle(struct ocfs2_super *osb,
0407 unsigned long ino, unsigned int flags)
0408 {
0409 unsigned int ret = OCFS2_FILECHECK_ERR_SUCCESS;
0410 struct inode *inode = NULL;
0411 int rc;
0412
0413 inode = ocfs2_iget(osb, ino, flags, 0);
0414 if (IS_ERR(inode)) {
0415 rc = (int)(-(long)inode);
0416 if (rc >= OCFS2_FILECHECK_ERR_START &&
0417 rc < OCFS2_FILECHECK_ERR_END)
0418 ret = rc;
0419 else
0420 ret = OCFS2_FILECHECK_ERR_FAILED;
0421 } else
0422 iput(inode);
0423
0424 return ret;
0425 }
0426
0427 static void
0428 ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
0429 struct ocfs2_filecheck_entry *entry)
0430 {
0431 struct ocfs2_super *osb = container_of(ent, struct ocfs2_super,
0432 osb_fc_ent);
0433
0434 if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
0435 entry->fe_status = ocfs2_filecheck_handle(osb,
0436 entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
0437 else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
0438 entry->fe_status = ocfs2_filecheck_handle(osb,
0439 entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
0440 else
0441 entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
0442
0443 ocfs2_filecheck_done_entry(ent, entry);
0444 }
0445
0446 static ssize_t ocfs2_filecheck_attr_store(struct kobject *kobj,
0447 struct kobj_attribute *attr,
0448 const char *buf, size_t count)
0449 {
0450 ssize_t ret = 0;
0451 struct ocfs2_filecheck_args args;
0452 struct ocfs2_filecheck_entry *entry;
0453 struct ocfs2_filecheck_sysfs_entry *ent = container_of(kobj,
0454 struct ocfs2_filecheck_sysfs_entry, fs_kobj);
0455
0456 if (count == 0)
0457 return count;
0458
0459 if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args))
0460 return -EINVAL;
0461
0462 if (args.fa_type == OCFS2_FILECHECK_TYPE_SET) {
0463 ret = ocfs2_filecheck_adjust_max(ent, args.fa_len);
0464 goto exit;
0465 }
0466
0467 entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS);
0468 if (!entry) {
0469 ret = -ENOMEM;
0470 goto exit;
0471 }
0472
0473 spin_lock(&ent->fs_fcheck->fc_lock);
0474 if (ocfs2_filecheck_is_dup_entry(ent, args.fa_ino)) {
0475 ret = -EEXIST;
0476 kfree(entry);
0477 } else if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
0478 (ent->fs_fcheck->fc_done == 0)) {
0479 mlog(ML_NOTICE,
0480 "Cannot do more file check "
0481 "since file check queue(%u) is full now\n",
0482 ent->fs_fcheck->fc_max);
0483 ret = -EAGAIN;
0484 kfree(entry);
0485 } else {
0486 if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
0487 (ent->fs_fcheck->fc_done > 0)) {
0488
0489
0490
0491
0492 BUG_ON(!ocfs2_filecheck_erase_entry(ent));
0493 }
0494
0495 entry->fe_ino = args.fa_ino;
0496 entry->fe_type = args.fa_type;
0497 entry->fe_done = 0;
0498 entry->fe_status = OCFS2_FILECHECK_ERR_INPROGRESS;
0499 list_add_tail(&entry->fe_list, &ent->fs_fcheck->fc_head);
0500 ent->fs_fcheck->fc_size++;
0501 }
0502 spin_unlock(&ent->fs_fcheck->fc_lock);
0503
0504 if (!ret)
0505 ocfs2_filecheck_handle_entry(ent, entry);
0506
0507 exit:
0508 return (!ret ? count : ret);
0509 }