Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

SSL filecheck.c

  Sprache: C
 

// SPDX-License-Identifier: GPL-2.0-only
/*
 * filecheck.c
 *
 * Code which implements online file check.
 *
 * Copyright (C) 2016 SuSE.  All rights reserved.
 */


#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/kmod.h>
#include <linux/fs.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/sysctl.h>
#include <cluster/masklog.h>

#include "ocfs2.h"
#include "ocfs2_fs.h"
#include "stackglue.h"
#include "inode.h"

#include "filecheck.h"


/* File check error strings,
 * must correspond with error number in header file.
 */

static const char * const ocfs2_filecheck_errs[] = {
 "SUCCESS",
 "FAILED",
 "INPROGRESS",
 "READONLY",
 "INJBD",
 "INVALIDINO",
 "BLOCKECC",
 "BLOCKNO",
 "VALIDFLAG",
 "GENERATION",
 "UNSUPPORTED"
};

struct ocfs2_filecheck_entry {
 struct list_head fe_list;
 unsigned long fe_ino;
 unsigned int fe_type;
 unsigned int fe_done:1;
 unsigned int fe_status:31;
};

struct ocfs2_filecheck_args {
 unsigned int fa_type;
 union {
  unsigned long fa_ino;
  unsigned int fa_len;
 };
};

static const char *
ocfs2_filecheck_error(int errno)
{
 if (!errno)
  return ocfs2_filecheck_errs[errno];

 BUG_ON(errno < OCFS2_FILECHECK_ERR_START ||
        errno > OCFS2_FILECHECK_ERR_END);
 return ocfs2_filecheck_errs[errno - OCFS2_FILECHECK_ERR_START + 1];
}

static ssize_t ocfs2_filecheck_attr_show(struct kobject *kobj,
     struct kobj_attribute *attr,
     char *buf);
static ssize_t ocfs2_filecheck_attr_store(struct kobject *kobj,
     struct kobj_attribute *attr,
     const char *buf, size_t count);
static struct kobj_attribute ocfs2_filecheck_attr_chk =
     __ATTR(check, S_IRUSR | S_IWUSR,
     ocfs2_filecheck_attr_show,
     ocfs2_filecheck_attr_store);
static struct kobj_attribute ocfs2_filecheck_attr_fix =
     __ATTR(fix, S_IRUSR | S_IWUSR,
     ocfs2_filecheck_attr_show,
     ocfs2_filecheck_attr_store);
static struct kobj_attribute ocfs2_filecheck_attr_set =
     __ATTR(set, S_IRUSR | S_IWUSR,
     ocfs2_filecheck_attr_show,
     ocfs2_filecheck_attr_store);
static struct attribute *ocfs2_filecheck_attrs[] = {
 &ocfs2_filecheck_attr_chk.attr,
 &ocfs2_filecheck_attr_fix.attr,
 &ocfs2_filecheck_attr_set.attr,
 NULL
};
ATTRIBUTE_GROUPS(ocfs2_filecheck);

static void ocfs2_filecheck_release(struct kobject *kobj)
{
 struct ocfs2_filecheck_sysfs_entry *entry = container_of(kobj,
    struct ocfs2_filecheck_sysfs_entry, fs_kobj);

 complete(&entry->fs_kobj_unregister);
}

static ssize_t
ocfs2_filecheck_show(struct kobject *kobj, struct attribute *attr, char *buf)
{
 ssize_t ret = -EIO;
 struct kobj_attribute *kattr = container_of(attr,
     struct kobj_attribute, attr);

 kobject_get(kobj);
 if (kattr->show)
  ret = kattr->show(kobj, kattr, buf);
 kobject_put(kobj);
 return ret;
}

static ssize_t
ocfs2_filecheck_store(struct kobject *kobj, struct attribute *attr,
   const char *buf, size_t count)
{
 ssize_t ret = -EIO;
 struct kobj_attribute *kattr = container_of(attr,
     struct kobj_attribute, attr);

 kobject_get(kobj);
 if (kattr->store)
  ret = kattr->store(kobj, kattr, buf, count);
 kobject_put(kobj);
 return ret;
}

static const struct sysfs_ops ocfs2_filecheck_ops = {
 .show = ocfs2_filecheck_show,
 .store = ocfs2_filecheck_store,
};

static struct kobj_type ocfs2_ktype_filecheck = {
 .default_groups = ocfs2_filecheck_groups,
 .sysfs_ops = &ocfs2_filecheck_ops,
 .release = ocfs2_filecheck_release,
};

static void
ocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry *entry)
{
 struct ocfs2_filecheck_entry *p;

 spin_lock(&entry->fs_fcheck->fc_lock);
 while (!list_empty(&entry->fs_fcheck->fc_head)) {
  p = list_first_entry(&entry->fs_fcheck->fc_head,
         struct ocfs2_filecheck_entry, fe_list);
  list_del(&p->fe_list);
  BUG_ON(!p->fe_done); /* To free a undone file check entry */
  kfree(p);
 }
 spin_unlock(&entry->fs_fcheck->fc_lock);

 kfree(entry->fs_fcheck);
 entry->fs_fcheck = NULL;
}

int ocfs2_filecheck_create_sysfs(struct ocfs2_super *osb)
{
 int ret;
 struct ocfs2_filecheck *fcheck;
 struct ocfs2_filecheck_sysfs_entry *entry = &osb->osb_fc_ent;

 fcheck = kmalloc(sizeof(struct ocfs2_filecheck), GFP_NOFS);
 if (!fcheck)
  return -ENOMEM;

 INIT_LIST_HEAD(&fcheck->fc_head);
 spin_lock_init(&fcheck->fc_lock);
 fcheck->fc_max = OCFS2_FILECHECK_MINSIZE;
 fcheck->fc_size = 0;
 fcheck->fc_done = 0;

 entry->fs_kobj.kset = osb->osb_dev_kset;
 init_completion(&entry->fs_kobj_unregister);
 ret = kobject_init_and_add(&entry->fs_kobj, &ocfs2_ktype_filecheck,
     NULL, "filecheck");
 if (ret) {
  kobject_put(&entry->fs_kobj);
  kfree(fcheck);
  return ret;
 }

 entry->fs_fcheck = fcheck;
 return 0;
}

void ocfs2_filecheck_remove_sysfs(struct ocfs2_super *osb)
{
 if (!osb->osb_fc_ent.fs_fcheck)
  return;

 kobject_del(&osb->osb_fc_ent.fs_kobj);
 kobject_put(&osb->osb_fc_ent.fs_kobj);
 wait_for_completion(&osb->osb_fc_ent.fs_kobj_unregister);
 ocfs2_filecheck_sysfs_free(&osb->osb_fc_ent);
}

static int
ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
         unsigned int count);
static int
ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent,
      unsigned int len)
{
 int ret;

 if ((len < OCFS2_FILECHECK_MINSIZE) || (len > OCFS2_FILECHECK_MAXSIZE))
  return -EINVAL;

 spin_lock(&ent->fs_fcheck->fc_lock);
 if (len < (ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done)) {
  mlog(ML_NOTICE,
  "Cannot set online file check maximum entry number "
  "to %u due to too many pending entries(%u)\n",
  len, ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done);
  ret = -EBUSY;
 } else {
  if (len < ent->fs_fcheck->fc_size)
   BUG_ON(!ocfs2_filecheck_erase_entries(ent,
    ent->fs_fcheck->fc_size - len));

  ent->fs_fcheck->fc_max = len;
  ret = 0;
 }
 spin_unlock(&ent->fs_fcheck->fc_lock);

 return ret;
}

#define OCFS2_FILECHECK_ARGS_LEN 24
static int
ocfs2_filecheck_args_get_long(const char *buf, size_t count,
         unsigned long *val)
{
 char buffer[OCFS2_FILECHECK_ARGS_LEN];

 memcpy(buffer, buf, count);
 buffer[count] = '\0';

 if (kstrtoul(buffer, 0, val))
  return 1;

 return 0;
}

static int
ocfs2_filecheck_type_parse(const char *name, unsigned int *type)
{
 if (!strncmp(name, "fix"4))
  *type = OCFS2_FILECHECK_TYPE_FIX;
 else if (!strncmp(name, "check"6))
  *type = OCFS2_FILECHECK_TYPE_CHK;
 else if (!strncmp(name, "set"4))
  *type = OCFS2_FILECHECK_TYPE_SET;
 else
  return 1;

 return 0;
}

static int
ocfs2_filecheck_args_parse(const char *name, const char *buf, size_t count,
      struct ocfs2_filecheck_args *args)
{
 unsigned long val = 0;
 unsigned int type;

 /* too short/long args length */
 if ((count < 1) || (count >= OCFS2_FILECHECK_ARGS_LEN))
  return 1;

 if (ocfs2_filecheck_type_parse(name, &type))
  return 1;
 if (ocfs2_filecheck_args_get_long(buf, count, &val))
  return 1;

 if (val <= 0)
  return 1;

 args->fa_type = type;
 if (type == OCFS2_FILECHECK_TYPE_SET)
  args->fa_len = (unsigned int)val;
 else
  args->fa_ino = val;

 return 0;
}

static ssize_t ocfs2_filecheck_attr_show(struct kobject *kobj,
        struct kobj_attribute *attr,
        char *buf)
{

 ssize_t ret = 0, total = 0, remain = PAGE_SIZE;
 unsigned int type;
 struct ocfs2_filecheck_entry *p;
 struct ocfs2_filecheck_sysfs_entry *ent = container_of(kobj,
    struct ocfs2_filecheck_sysfs_entry, fs_kobj);

 if (ocfs2_filecheck_type_parse(attr->attr.name, &type))
  return -EINVAL;

 if (type == OCFS2_FILECHECK_TYPE_SET) {
  spin_lock(&ent->fs_fcheck->fc_lock);
  total = snprintf(buf, remain, "%u\n", ent->fs_fcheck->fc_max);
  spin_unlock(&ent->fs_fcheck->fc_lock);
  goto exit;
 }

 ret = snprintf(buf, remain, "INO\t\tDONE\tERROR\n");
 total += ret;
 remain -= ret;
 spin_lock(&ent->fs_fcheck->fc_lock);
 list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
  if (p->fe_type != type)
   continue;

  ret = snprintf(buf + total, remain, "%lu\t\t%u\t%s\n",
          p->fe_ino, p->fe_done,
          ocfs2_filecheck_error(p->fe_status));
  if (ret >= remain) {
   /* snprintf() didn't fit */
   total = -E2BIG;
   break;
  }
  total += ret;
  remain -= ret;
 }
 spin_unlock(&ent->fs_fcheck->fc_lock);

exit:
 return total;
}

static inline int
ocfs2_filecheck_is_dup_entry(struct ocfs2_filecheck_sysfs_entry *ent,
    unsigned long ino)
{
 struct ocfs2_filecheck_entry *p;

 list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
  if (!p->fe_done) {
   if (p->fe_ino == ino)
    return 1;
  }
 }

 return 0;
}

static inline int
ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
{
 struct ocfs2_filecheck_entry *p;

 list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
  if (p->fe_done) {
   list_del(&p->fe_list);
   kfree(p);
   ent->fs_fcheck->fc_size--;
   ent->fs_fcheck->fc_done--;
   return 1;
  }
 }

 return 0;
}

static int
ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
         unsigned int count)
{
 unsigned int i = 0;
 unsigned int ret = 0;

 while (i++ < count) {
  if (ocfs2_filecheck_erase_entry(ent))
   ret++;
  else
   break;
 }

 return (ret == count ? 1 : 0);
}

static void
ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent,
      struct ocfs2_filecheck_entry *entry)
{
 spin_lock(&ent->fs_fcheck->fc_lock);
 entry->fe_done = 1;
 ent->fs_fcheck->fc_done++;
 spin_unlock(&ent->fs_fcheck->fc_lock);
}

static unsigned int
ocfs2_filecheck_handle(struct ocfs2_super *osb,
         unsigned long ino, unsigned int flags)
{
 unsigned int ret = OCFS2_FILECHECK_ERR_SUCCESS;
 struct inode *inode = NULL;
 int rc;

 inode = ocfs2_iget(osb, ino, flags, 0);
 if (IS_ERR(inode)) {
  rc = (int)(-(long)inode);
  if (rc >= OCFS2_FILECHECK_ERR_START &&
      rc < OCFS2_FILECHECK_ERR_END)
   ret = rc;
  else
   ret = OCFS2_FILECHECK_ERR_FAILED;
 } else
  iput(inode);

 return ret;
}

static void
ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
        struct ocfs2_filecheck_entry *entry)
{
 struct ocfs2_super *osb = container_of(ent, struct ocfs2_super,
      osb_fc_ent);

 if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
  entry->fe_status = ocfs2_filecheck_handle(osb,
    entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
 else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
  entry->fe_status = ocfs2_filecheck_handle(osb,
    entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
 else
  entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;

 ocfs2_filecheck_done_entry(ent, entry);
}

static ssize_t ocfs2_filecheck_attr_store(struct kobject *kobj,
         struct kobj_attribute *attr,
         const char *buf, size_t count)
{
 ssize_t ret = 0;
 struct ocfs2_filecheck_args args;
 struct ocfs2_filecheck_entry *entry;
 struct ocfs2_filecheck_sysfs_entry *ent = container_of(kobj,
    struct ocfs2_filecheck_sysfs_entry, fs_kobj);

 if (count == 0)
  return count;

 if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args))
  return -EINVAL;

 if (args.fa_type == OCFS2_FILECHECK_TYPE_SET) {
  ret = ocfs2_filecheck_adjust_max(ent, args.fa_len);
  goto exit;
 }

 entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS);
 if (!entry) {
  ret = -ENOMEM;
  goto exit;
 }

 spin_lock(&ent->fs_fcheck->fc_lock);
 if (ocfs2_filecheck_is_dup_entry(ent, args.fa_ino)) {
  ret = -EEXIST;
  kfree(entry);
 } else if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
  (ent->fs_fcheck->fc_done == 0)) {
  mlog(ML_NOTICE,
  "Cannot do more file check "
  "since file check queue(%u) is full now\n",
  ent->fs_fcheck->fc_max);
  ret = -EAGAIN;
  kfree(entry);
 } else {
  if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
      (ent->fs_fcheck->fc_done > 0)) {
   /* Delete the oldest entry which was done,
 * make sure the entry size in list does
 * not exceed maximum value
 */

   BUG_ON(!ocfs2_filecheck_erase_entry(ent));
  }

  entry->fe_ino = args.fa_ino;
  entry->fe_type = args.fa_type;
  entry->fe_done = 0;
  entry->fe_status = OCFS2_FILECHECK_ERR_INPROGRESS;
  list_add_tail(&entry->fe_list, &ent->fs_fcheck->fc_head);
  ent->fs_fcheck->fc_size++;
 }
 spin_unlock(&ent->fs_fcheck->fc_lock);

 if (!ret)
  ocfs2_filecheck_handle_entry(ent, entry);

exit:
 return ret ?: count;
}

Messung V0.5 in Prozent
C=99 H=93 G=95

¤ Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.0.1Bemerkung:  (vorverarbeitet am  2026-06-08) ¤

*Bot Zugriff






Versionsinformation zu Columbo

Bemerkung:

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Anfrage:

Dauer der Verarbeitung:

Sekunden

sprechenden Kalenders






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002