// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/sched.h>#include <linux/cred.h>#include <linux/spinlock.h>#include <linux/completion.h>#include <linux/buffer_head.h>#include <linux/module.h>#include <linux/kobject.h>#include <linux/uaccess.h>#include <linux/gfs2_ondisk.h>#include <linux/blkdev.h> #include "gfs2.h"#include "incore.h"#include "sys.h"#include "super.h"#include "glock.h"#include "quota.h"#include "util.h"#include "glops.h"#include "recovery.h" struct gfs2_attr { struct attribute attr; ssize_t (*show)(struct gfs2_sbd *, char *); ssize_t (*store)(struct gfs2_sbd *, const char *, size_t);}; static ssize_t gfs2_attr_show(struct kobject *kobj, struct attribute *attr, char *buf){ struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj); struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr); return a->show ? a->show(sdp, buf) : 0;} static ssize_t gfs2_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t len){ struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj); struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr); return a->store ? a->store(sdp, buf, len) : len;} static const struct sysfs_ops gfs2_attr_ops = { .show = gfs2_attr_show, .store = gfs2_attr_store,}; static struct kset *gfs2_kset; static ssize_t id_show(struct gfs2_sbd *sdp, char *buf){ return sysfs_emit(buf, "%u:%u\n", MAJOR(sdp->sd_vfs->s_dev), MINOR(sdp->sd_vfs->s_dev));} static ssize_t status_show(struct gfs2_sbd *sdp, char *buf){ unsigned long f = sdp->sd_flags; ssize_t s; s = sysfs_emit(buf, "Journal Checked: %d\n" "Journal Live: %d\n" "Journal ID: %d\n" "Spectator: %d\n" "Withdrawn: %d\n" "No barriers: %d\n" "No recovery: %d\n" "Demote: %d\n" "No Journal ID: %d\n" "Mounted RO: %d\n" "RO Recovery: %d\n" "Force AIL Flush: %d\n" "FS Freeze Initiator: %d\n" "FS Frozen: %d\n" "Killing: %d\n" "sd_log_error: %d\n" "sd_log_flush_lock: %d\n" "sd_log_num_revoke: %u\n" "sd_log_in_flight: %d\n" "sd_log_blks_needed: %d\n" "sd_log_blks_free: %d\n" "sd_log_flush_head: %d\n" "sd_log_flush_tail: %d\n" "sd_log_blks_reserved: %d\n" "sd_log_revokes_available: %d\n" "sd_log_pinned: %d\n" "sd_log_thresh1: %d\n" "sd_log_thresh2: %d\n", test_bit(SDF_JOURNAL_CHECKED, &f), test_bit(SDF_JOURNAL_LIVE, &f), (sdp->sd_jdesc ? sdp->sd_jdesc->jd_jid : 0), (sdp->sd_args.ar_spectator ? 1 : 0), test_bit(SDF_WITHDRAWN, &f), test_bit(SDF_NOBARRIERS, &f), test_bit(SDF_NORECOVERY, &f), test_bit(SDF_DEMOTE, &f), test_bit(SDF_NOJOURNALID, &f), (sb_rdonly(sdp->sd_vfs) ? 1 : 0), test_bit(SDF_RORECOVERY, &f), test_bit(SDF_FORCE_AIL_FLUSH, &f), test_bit(SDF_FREEZE_INITIATOR, &f), test_bit(SDF_FROZEN, &f), test_bit(SDF_KILL, &f), sdp->sd_log_error, rwsem_is_locked(&sdp->sd_log_flush_lock), sdp->sd_log_num_revoke, atomic_read(&sdp->sd_log_in_flight), atomic_read(&sdp->sd_log_blks_needed), atomic_read(&sdp->sd_log_blks_free), sdp->sd_log_flush_head, sdp->sd_log_flush_tail, sdp->sd_log_blks_reserved, atomic_read(&sdp->sd_log_revokes_available), atomic_read(&sdp->sd_log_pinned), atomic_read(&sdp->sd_log_thresh1), atomic_read(&sdp->sd_log_thresh2)); return s;} static ssize_t fsname_show(struct gfs2_sbd *sdp, char *buf){ return sysfs_emit(buf, "%s\n", sdp->sd_fsname);} static ssize_t uuid_show(struct gfs2_sbd *sdp, char *buf){ struct super_block *s = sdp->sd_vfs; buf[0] = '\0'; if (uuid_is_null(&s->s_uuid)) return 0; return sysfs_emit(buf, "%pUB\n", &s->s_uuid);} static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf){ struct super_block *sb = sdp->sd_vfs; int frozen = (sb->s_writers.frozen == SB_UNFROZEN) ? 0 : 1; return sysfs_emit(buf, "%d\n", frozen);} static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len){ int error, n; error = kstrtoint(buf, 0, &n); if (error) return error; if (!capable(CAP_SYS_ADMIN)) return -EPERM; switch (n) { case 0: error = thaw_super(sdp->sd_vfs, FREEZE_HOLDER_USERSPACE, NULL); break; case 1: error = freeze_super(sdp->sd_vfs, FREEZE_HOLDER_USERSPACE, NULL); break; default: return -EINVAL; } if (error) { fs_warn(sdp, "freeze %d error %d\n", n, error); return error; } return len;} static ssize_t withdraw_show(struct gfs2_sbd *sdp, char *buf){ unsigned int b = gfs2_withdrawn(sdp); return sysfs_emit(buf, "%u\n", b);} static ssize_t withdraw_store(struct gfs2_sbd *sdp, const char *buf, size_t len){ int error, val; if (!capable(CAP_SYS_ADMIN)) return -EPERM; error = kstrtoint(buf, 0, &val); if (error) return error; if (val != 1) return -EINVAL; gfs2_lm(sdp, "withdrawing from cluster at user's request\n"); gfs2_withdraw(sdp); return len;} static ssize_t statfs_sync_store(struct gfs2_sbd *sdp, const char *buf, size_t len){ int error, val; if (!capable(CAP_SYS_ADMIN)) return -EPERM; error = kstrtoint(buf, 0, &val); if (error) return error; if (val != 1) return -EINVAL; gfs2_statfs_sync(sdp->sd_vfs, 0); return len;} static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf, size_t len){ int error, val; if (!capable(CAP_SYS_ADMIN)) return -EPERM; error = kstrtoint(buf, 0, &val); if (error) return error; if (val != 1) return -EINVAL; gfs2_quota_sync(sdp->sd_vfs, 0); return len;} static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf, size_t len){ struct kqid qid; int error; u32 id; if (!capable(CAP_SYS_ADMIN)) return -EPERM; error = kstrtou32(buf, 0, &id); if (error) return error; qid = make_kqid(current_user_ns(), USRQUOTA, id); if (!qid_valid(qid)) return -EINVAL; error = gfs2_quota_refresh(sdp, qid); return error ? error : len;} static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf, size_t len){ struct kqid qid; int error; u32 id; if (!capable(CAP_SYS_ADMIN)) return -EPERM; error = kstrtou32(buf, 0, &id); if (error) return error; qid = make_kqid(current_user_ns(), GRPQUOTA, id); if (!qid_valid(qid)) return -EINVAL; error = gfs2_quota_refresh(sdp, qid); return error ? error : len;} static ssize_t demote_rq_store(struct gfs2_sbd *sdp, const char *buf, size_t len){ struct gfs2_glock *gl; const struct gfs2_glock_operations *glops; unsigned int glmode; unsigned int gltype; unsigned long long glnum; char mode[16]; int rv; if (!capable(CAP_SYS_ADMIN)) return -EPERM; rv = sscanf(buf, "%u:%llu %15s", &gltype, &glnum, mode); if (rv != 3) return -EINVAL; if (strcmp(mode, "EX") == 0) glmode = LM_ST_UNLOCKED; else if ((strcmp(mode, "CW") == 0) || (strcmp(mode, "DF") == 0)) glmode = LM_ST_DEFERRED; else if ((strcmp(mode, "PR") == 0) || (strcmp(mode, "SH") == 0)) glmode = LM_ST_SHARED; else return -EINVAL; if (gltype > LM_TYPE_JOURNAL) return -EINVAL; if (gltype == LM_TYPE_NONDISK && glnum == GFS2_FREEZE_LOCK) glops = &gfs2_freeze_glops; else glops = gfs2_glops_list[gltype]; if (glops == NULL) return -EINVAL; if (!test_and_set_bit(SDF_DEMOTE, &sdp->sd_flags)) fs_info(sdp, "demote interface used\n"); rv = gfs2_glock_get(sdp, glnum, glops, NO_CREATE, &gl); if (rv) return rv; gfs2_glock_cb(gl, glmode); gfs2_glock_put(gl); return len;} #define GFS2_ATTR(name, mode, show, store) \static struct gfs2_attr gfs2_attr_##name = __ATTR(name, mode, show, store) GFS2_ATTR(id, 0444, id_show, NULL);GFS2_ATTR(fsname, 0444, fsname_show, NULL);GFS2_ATTR(uuid, 0444, uuid_show, NULL);GFS2_ATTR(freeze, 0644, freeze_show, freeze_store);GFS2_ATTR(withdraw, 0644, withdraw_show, withdraw_store);GFS2_ATTR(statfs_sync, 0200, NULL, statfs_sync_store);GFS2_ATTR(quota_sync, 0200, NULL, quota_sync_store);GFS2_ATTR(quota_refresh_user, 0200, NULL, quota_refresh_user_store);GFS2_ATTR(quota_refresh_group, 0200, NULL, quota_refresh_group_store);GFS2_ATTR(demote_rq, 0200, NULL, demote_rq_store);GFS2_ATTR(status, 0400, status_show, NULL); static struct attribute *gfs2_attrs[] = { &gfs2_attr_id.attr, &gfs2_attr_fsname.attr, &gfs2_attr_uuid.attr, &gfs2_attr_freeze.attr, &gfs2_attr_withdraw.attr, &gfs2_attr_statfs_sync.attr, &gfs2_attr_quota_sync.attr, &gfs2_attr_quota_refresh_user.attr, &gfs2_attr_quota_refresh_group.attr, &gfs2_attr_demote_rq.attr, &gfs2_attr_status.attr, NULL,};ATTRIBUTE_GROUPS(gfs2); static void gfs2_sbd_release(struct kobject *kobj){ struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj); complete(&sdp->sd_kobj_unregister);} static struct kobj_type gfs2_ktype = { .release = gfs2_sbd_release, .default_groups = gfs2_groups, .sysfs_ops = &gfs2_attr_ops,}; /* * lock_module. Originally from lock_dlm */ static ssize_t proto_name_show(struct gfs2_sbd *sdp, char *buf){ const struct lm_lockops *ops = sdp->sd_lockstruct.ls_ops; return sysfs_emit(buf, "%s\n", ops->lm_proto_name);} static ssize_t block_show(struct gfs2_sbd *sdp, char *buf){ struct lm_lockstruct *ls = &sdp->sd_lockstruct; ssize_t ret; int val = 0; if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags)) val = 1; ret = sysfs_emit(buf, "%d\n", val); return ret;} static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len){ struct lm_lockstruct *ls = &sdp->sd_lockstruct; int ret, val; ret = kstrtoint(buf, 0, &val); if (ret) return ret; if (val == 1) set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags); else if (val == 0) { clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags); smp_mb__after_atomic(); gfs2_glock_thaw(sdp); } else { return -EINVAL; } return len;} static ssize_t withdraw_helper_status_store(struct gfs2_sbd *sdp, const char *buf, size_t len){ int ret, val; ret = kstrtoint(buf, 0, &val); if (ret) return ret; if (val < 0 || val > 1) return -EINVAL; sdp->sd_withdraw_helper_status = val; complete(&sdp->sd_withdraw_helper); return len;} static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf){ struct lm_lockstruct *ls = &sdp->sd_lockstruct; return sysfs_emit(buf, "%d\n", ls->ls_first);} static ssize_t lkfirst_store(struct gfs2_sbd *sdp, const char *buf, size_t len){ unsigned first; int rv; rv = sscanf(buf, "%u", &first); if (rv != 1 || first > 1) return -EINVAL; rv = wait_for_completion_killable(&sdp->sd_locking_init); if (rv) return rv; spin_lock(&sdp->sd_jindex_spin); rv = -EBUSY; if (test_bit(SDF_NOJOURNALID, &sdp->sd_flags) == 0) goto out; rv = -EINVAL; if (sdp->sd_args.ar_spectator) goto out; if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL) goto out; sdp->sd_lockstruct.ls_first = first; rv = 0;out: spin_unlock(&sdp->sd_jindex_spin); return rv ? rv : len;} static ssize_t first_done_show(struct gfs2_sbd *sdp, char *buf){ struct lm_lockstruct *ls = &sdp->sd_lockstruct; return sysfs_emit(buf, "%d\n", !!test_bit(DFL_FIRST_MOUNT_DONE, &ls->ls_recover_flags));} int gfs2_recover_set(struct gfs2_sbd *sdp, unsigned jid){ struct gfs2_jdesc *jd; int rv; /* Wait for our primary journal to be initialized */ wait_for_completion(&sdp->sd_journal_ready); spin_lock(&sdp->sd_jindex_spin); rv = -EBUSY; /** * If we're a spectator, we use journal0, but it's not really ours. * So we need to wait for its recovery too. If we skip it we'd never * queue work to the recovery workqueue, and so its completion would * never clear the DFL_BLOCK_LOCKS flag, so all our locks would * permanently stop working. */ if (!sdp->sd_jdesc) goto out;Lines 1–500 of 795. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/sched.h> #include <linux/cred.h> #include <linux/spinlock.h> #include <linux/completion.h> #include <linux/buffer_head.h> #include <linux/module.h> #include <linux/kobject.h> #include <linux/uaccess.h> #include <linux/gfs2_ondisk.h> #include <linux/blkdev.h> #include "gfs2.h" #include "incore.h" #include "sys.h" #include "super.h" #include "glock.h" #include "quota.h" #include "util.h" #include "glops.h" #include "recovery.h" struct gfs2_attr { struct attribute attr; ssize_t (*show)(struct gfs2_sbd *, char *); ssize_t (*store)(struct gfs2_sbd *, const char *, size_t); }; static ssize_t gfs2_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj); struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr); return a->show ? a->show(sdp, buf) : 0; } static ssize_t gfs2_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t len) { struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj); struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr); return a->store ? a->store(sdp, buf, len) : len; } static const struct sysfs_ops gfs2_attr_ops = { .show = gfs2_attr_show, .store = gfs2_attr_store, }; static struct kset *gfs2_kset; static ssize_t id_show(struct gfs2_sbd *sdp, char *buf) { return sysfs_emit(buf, "%u:%u\n", MAJOR(sdp->sd_vfs->s_dev), MINOR(sdp->sd_vfs->s_dev)); } static ssize_t status_show(struct gfs2_sbd *sdp, char *buf) { unsigned long f = sdp->sd_flags; ssize_t s; s = sysfs_emit(buf, "Journal Checked: %d\n" "Journal Live: %d\n" "Journal ID: %d\n" "Spectator: %d\n" "Withdrawn: %d\n" "No barriers: %d\n" "No recovery: %d\n" "Demote: %d\n" "No Journal ID: %d\n" "Mounted RO: %d\n" "RO Recovery: %d\n" "Force AIL Flush: %d\n" "FS Freeze Initiator: %d\n" "FS Frozen: %d\n" "Killing: %d\n" "sd_log_error: %d\n" "sd_log_flush_lock: %d\n" "sd_log_num_revoke: %u\n" "sd_log_in_flight: %d\n" "sd_log_blks_needed: %d\n" "sd_log_blks_free: %d\n" "sd_log_flush_head: %d\n" "sd_log_flush_tail: %d\n" "sd_log_blks_reserved: %d\n" "sd_log_revokes_available: %d\n" "sd_log_pinned: %d\n" "sd_log_thresh1: %d\n" "sd_log_thresh2: %d\n", test_bit(SDF_JOURNAL_CHECKED, &f), test_bit(SDF_JOURNAL_LIVE, &f), (sdp->sd_jdesc ? sdp->sd_jdesc->jd_jid : 0), (sdp->sd_args.ar_spectator ? 1 : 0), test_bit(SDF_WITHDRAWN, &f), test_bit(SDF_NOBARRIERS, &f), test_bit(SDF_NORECOVERY, &f), test_bit(SDF_DEMOTE, &f), test_bit(SDF_NOJOURNALID, &f), (sb_rdonly(sdp->sd_vfs) ? 1 : 0), test_bit(SDF_RORECOVERY, &f), test_bit(SDF_FORCE_AIL_FLUSH, &f), test_bit(SDF_FREEZE_INITIATOR, &f), test_bit(SDF_FROZEN, &f), test_bit(SDF_KILL, &f), sdp->sd_log_error, rwsem_is_locked(&sdp->sd_log_flush_lock), sdp->sd_log_num_revoke, atomic_read(&sdp->sd_log_in_flight), atomic_read(&sdp->sd_log_blks_needed), atomic_read(&sdp->sd_log_blks_free), sdp->sd_log_flush_head, sdp->sd_log_flush_tail, sdp->sd_log_blks_reserved, atomic_read(&sdp->sd_log_revokes_available), atomic_read(&sdp->sd_log_pinned), atomic_read(&sdp->sd_log_thresh1), atomic_read(&sdp->sd_log_thresh2)); return s; } static ssize_t fsname_show(struct gfs2_sbd *sdp, char *buf) { return sysfs_emit(buf, "%s\n", sdp->sd_fsname); } static ssize_t uuid_show(struct gfs2_sbd *sdp, char *buf) { struct super_block *s = sdp->sd_vfs; buf[0] = '\0'; if (uuid_is_null(&s->s_uuid)) return 0; return sysfs_emit(buf, "%pUB\n", &s->s_uuid); } static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf) { struct super_block *sb = sdp->sd_vfs; int frozen = (sb->s_writers.frozen == SB_UNFROZEN) ? 0 : 1; return sysfs_emit(buf, "%d\n", frozen); } static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len) { int error, n; error = kstrtoint(buf, 0, &n); if (error) return error; if (!capable(CAP_SYS_ADMIN)) return -EPERM; switch (n) { case 0: error = thaw_super(sdp->sd_vfs, FREEZE_HOLDER_USERSPACE, NULL); break; case 1: error = freeze_super(sdp->sd_vfs, FREEZE_HOLDER_USERSPACE, NULL); break; default: return -EINVAL; } if (error) { fs_warn(sdp, "freeze %d error %d\n", n, error); return error; } return len; } static ssize_t withdraw_show(struct gfs2_sbd *sdp, char *buf) { unsigned int b = gfs2_withdrawn(sdp); return sysfs_emit(buf, "%u\n", b); } static ssize_t withdraw_store(struct gfs2_sbd *sdp, const char *buf, size_t len) { int error, val; if (!capable(CAP_SYS_ADMIN)) return -EPERM; error = kstrtoint(buf, 0, &val); if (error) return error; if (val != 1) return -EINVAL; gfs2_lm(sdp, "withdrawing from cluster at user's request\n"); gfs2_withdraw(sdp); return len; } static ssize_t statfs_sync_store(struct gfs2_sbd *sdp, const char *buf, size_t len) { int error, val; if (!capable(CAP_SYS_ADMIN)) return -EPERM; error = kstrtoint(buf, 0, &val); if (error) return error; if (val != 1) return -EINVAL; gfs2_statfs_sync(sdp->sd_vfs, 0); return len; } static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf, size_t len) { int error, val; if (!capable(CAP_SYS_ADMIN)) return -EPERM; error = kstrtoint(buf, 0, &val); if (error) return error; if (val != 1) return -EINVAL; gfs2_quota_sync(sdp->sd_vfs, 0); return len; } static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf, size_t len) { struct kqid qid; int error; u32 id; if (!capable(CAP_SYS_ADMIN)) return -EPERM; error = kstrtou32(buf, 0, &id); if (error) return error; qid = make_kqid(current_user_ns(), USRQUOTA, id); if (!qid_valid(qid)) return -EINVAL; error = gfs2_quota_refresh(sdp, qid); return error ? error : len; } static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf, size_t len) { struct kqid qid; int error; u32 id; if (!capable(CAP_SYS_ADMIN)) return -EPERM; error = kstrtou32(buf, 0, &id); if (error) return error; qid = make_kqid(current_user_ns(), GRPQUOTA, id); if (!qid_valid(qid)) return -EINVAL; error = gfs2_quota_refresh(sdp, qid); return error ? error : len; } static ssize_t demote_rq_store(struct gfs2_sbd *sdp, const char *buf, size_t len) { struct gfs2_glock *gl; const struct gfs2_glock_operations *glops; unsigned int glmode; unsigned int gltype; unsigned long long glnum; char mode[16]; int rv; if (!capable(CAP_SYS_ADMIN)) return -EPERM; rv = sscanf(buf, "%u:%llu %15s", &gltype, &glnum, mode); if (rv != 3) return -EINVAL; if (strcmp(mode, "EX") == 0) glmode = LM_ST_UNLOCKED; else if ((strcmp(mode, "CW") == 0) || (strcmp(mode, "DF") == 0)) glmode = LM_ST_DEFERRED; else if ((strcmp(mode, "PR") == 0) || (strcmp(mode, "SH") == 0)) glmode = LM_ST_SHARED; else return -EINVAL; if (gltype > LM_TYPE_JOURNAL) return -EINVAL; if (gltype == LM_TYPE_NONDISK && glnum == GFS2_FREEZE_LOCK) glops = &gfs2_freeze_glops; else glops = gfs2_glops_list[gltype]; if (glops == NULL) return -EINVAL; if (!test_and_set_bit(SDF_DEMOTE, &sdp->sd_flags)) fs_info(sdp, "demote interface used\n"); rv = gfs2_glock_get(sdp, glnum, glops, NO_CREATE, &gl); if (rv) return rv; gfs2_glock_cb(gl, glmode); gfs2_glock_put(gl); return len; } #define GFS2_ATTR(name, mode, show, store) \ static struct gfs2_attr gfs2_attr_##name = __ATTR(name, mode, show, store) GFS2_ATTR(id, 0444, id_show, NULL); GFS2_ATTR(fsname, 0444, fsname_show, NULL); GFS2_ATTR(uuid, 0444, uuid_show, NULL); GFS2_ATTR(freeze, 0644, freeze_show, freeze_store); GFS2_ATTR(withdraw, 0644, withdraw_show, withdraw_store); GFS2_ATTR(statfs_sync, 0200, NULL, statfs_sync_store); GFS2_ATTR(quota_sync, 0200, NULL, quota_sync_store); GFS2_ATTR(quota_refresh_user, 0200, NULL, quota_refresh_user_store); GFS2_ATTR(quota_refresh_group, 0200, NULL, quota_refresh_group_store); GFS2_ATTR(demote_rq, 0200, NULL, demote_rq_store); GFS2_ATTR(status, 0400, status_show, NULL); static struct attribute *gfs2_attrs[] = { &gfs2_attr_id.attr, &gfs2_attr_fsname.attr, &gfs2_attr_uuid.attr, &gfs2_attr_freeze.attr, &gfs2_attr_withdraw.attr, &gfs2_attr_statfs_sync.attr, &gfs2_attr_quota_sync.attr, &gfs2_attr_quota_refresh_user.attr, &gfs2_attr_quota_refresh_group.attr, &gfs2_attr_demote_rq.attr, &gfs2_attr_status.attr, NULL, }; ATTRIBUTE_GROUPS(gfs2); static void gfs2_sbd_release(struct kobject *kobj) { struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj); complete(&sdp->sd_kobj_unregister); } static struct kobj_type gfs2_ktype = { .release = gfs2_sbd_release, .default_groups = gfs2_groups, .sysfs_ops = &gfs2_attr_ops, }; /* * lock_module. Originally from lock_dlm */ static ssize_t proto_name_show(struct gfs2_sbd *sdp, char *buf) { const struct lm_lockops *ops = sdp->sd_lockstruct.ls_ops; return sysfs_emit(buf, "%s\n", ops->lm_proto_name); } static ssize_t block_show(struct gfs2_sbd *sdp, char *buf) { struct lm_lockstruct *ls = &sdp->sd_lockstruct; ssize_t ret; int val = 0; if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags)) val = 1; ret = sysfs_emit(buf, "%d\n", val); return ret; } static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len) { struct lm_lockstruct *ls = &sdp->sd_lockstruct; int ret, val; ret = kstrtoint(buf, 0, &val); if (ret) return ret; if (val == 1) set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags); else if (val == 0) { clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags); smp_mb__after_atomic(); gfs2_glock_thaw(sdp); } else { return -EINVAL; } return len; } static ssize_t withdraw_helper_status_store(struct gfs2_sbd *sdp, const char *buf, size_t len) { int ret, val; ret = kstrtoint(buf, 0, &val); if (ret) return ret; if (val < 0 || val > 1) return -EINVAL; sdp->sd_withdraw_helper_status = val; complete(&sdp->sd_withdraw_helper); return len; } static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf) { struct lm_lockstruct *ls = &sdp->sd_lockstruct; return sysfs_emit(buf, "%d\n", ls->ls_first); } static ssize_t lkfirst_store(struct gfs2_sbd *sdp, const char *buf, size_t len) { unsigned first; int rv; rv = sscanf(buf, "%u", &first); if (rv != 1 || first > 1) return -EINVAL; rv = wait_for_completion_killable(&sdp->sd_locking_init); if (rv) return rv; spin_lock(&sdp->sd_jindex_spin); rv = -EBUSY; if (test_bit(SDF_NOJOURNALID, &sdp->sd_flags) == 0) goto out; rv = -EINVAL; if (sdp->sd_args.ar_spectator) goto out; if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL) goto out; sdp->sd_lockstruct.ls_first = first; rv = 0; out: spin_unlock(&sdp->sd_jindex_spin); return rv ? rv : len; } static ssize_t first_done_show(struct gfs2_sbd *sdp, char *buf) { struct lm_lockstruct *ls = &sdp->sd_lockstruct; return sysfs_emit(buf, "%d\n", !!test_bit(DFL_FIRST_MOUNT_DONE, &ls->ls_recover_flags)); } int gfs2_recover_set(struct gfs2_sbd *sdp, unsigned jid) { struct gfs2_jdesc *jd; int rv; /* Wait for our primary journal to be initialized */ wait_for_completion(&sdp->sd_journal_ready); spin_lock(&sdp->sd_jindex_spin); rv = -EBUSY; /** * If we're a spectator, we use journal0, but it's not really ours. * So we need to wait for its recovery too. If we skip it we'd never * queue work to the recovery workqueue, and so its completion would * never clear the DFL_BLOCK_LOCKS flag, so all our locks would * permanently stop working. */ if (!sdp->sd_jdesc) goto out;