Commit 33f1de69 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw

* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw:
  GFS2: Whitespace fixes
  GFS2: Remove unused sysfs file
  GFS2: Be extra careful about deallocating inodes
  GFS2: Remove no_formal_ino generating code
  GFS2: Rename eattr.[ch] as xattr.[ch]
  GFS2: Clean up of extended attribute support
  GFS2: Add explanation of extended attr on-disk format
  GFS2: Add "-o errors=panic|withdraw" mount options
  GFS2: jumping to wrong label?
  GFS2: free disk inode which is deleted by remote node -V2
  GFS2: Add a document explaining GFS2's uevents
  GFS2: Add sysfs link to device
  GFS2: Replace assertion with proper error handling
  GFS2: Improve error handling in inode allocation
  GFS2: Add some more info to uevents
  GFS2: Add online uevent to GFS2
parents 041d6d0b 86d00636
uevents and GFS2
==================
During the lifetime of a GFS2 mount, a number of uevents are generated.
This document explains what the events are and what they are used
for (by gfs_controld in gfs2-utils).
A list of GFS2 uevents
-----------------------
1. ADD
The ADD event occurs at mount time. It will always be the first
uevent generated by the newly created filesystem. If the mount
is successful, an ONLINE uevent will follow. If it is not successful
then a REMOVE uevent will follow.
The ADD uevent has two environment variables: SPECTATOR=[0|1]
and RDONLY=[0|1] that specify the spectator status (a read-only mount
with no journal assigned), and read-only (with journal assigned) status
of the filesystem respectively.
2. ONLINE
The ONLINE uevent is generated after a successful mount or remount. It
has the same environment variables as the ADD uevent. The ONLINE
uevent, along with the two environment variables for spectator and
RDONLY are a relatively recent addition (2.6.32-rc+) and will not
be generated by older kernels.
3. CHANGE
The CHANGE uevent is used in two places. One is when reporting the
successful mount of the filesystem by the first node (FIRSTMOUNT=Done).
This is used as a signal by gfs_controld that it is then ok for other
nodes in the cluster to mount the filesystem.
The other CHANGE uevent is used to inform of the completion
of journal recovery for one of the filesystems journals. It has
two environment variables, JID= which specifies the journal id which
has just been recovered, and RECOVERY=[Done|Failed] to indicate the
success (or otherwise) of the operation. These uevents are generated
for every journal recovered, whether it is during the initial mount
process or as the result of gfs_controld requesting a specific journal
recovery via the /sys/fs/gfs2/<fsname>/lock_module/recovery file.
Because the CHANGE uevent was used (in early versions of gfs_controld)
without checking the environment variables to discover the state, we
cannot add any more functions to it without running the risk of
someone using an older version of the user tools and breaking their
cluster. For this reason the ONLINE uevent was used when adding a new
uevent for a successful mount or remount.
4. OFFLINE
The OFFLINE uevent is only generated due to filesystem errors and is used
as part of the "withdraw" mechanism. Currently this doesn't give any
information about what the error is, which is something that needs to
be fixed.
5. REMOVE
The REMOVE uevent is generated at the end of an unsuccessful mount
or at the end of a umount of the filesystem. All REMOVE uevents will
have been preceeded by at least an ADD uevent for the same fileystem,
and unlike the other uevents is generated automatically by the kernel's
kobject subsystem.
Information common to all GFS2 uevents (uevent environment variables)
----------------------------------------------------------------------
1. LOCKTABLE=
The LOCKTABLE is a string, as supplied on the mount command
line (locktable=) or via fstab. It is used as a filesystem label
as well as providing the information for a lock_dlm mount to be
able to join the cluster.
2. LOCKPROTO=
The LOCKPROTO is a string, and its value depends on what is set
on the mount command line, or via fstab. It will be either
lock_nolock or lock_dlm. In the future other lock managers
may be supported.
3. JOURNALID=
If a journal is in use by the filesystem (journals are not
assigned for spectator mounts) then this will give the
numeric journal id in all GFS2 uevents.
4. UUID=
With recent versions of gfs2-utils, mkfs.gfs2 writes a UUID
into the filesystem superblock. If it exists, this will
be included in every uevent relating to the filesystem.
EXTRA_CFLAGS := -I$(src)
obj-$(CONFIG_GFS2_FS) += gfs2.o
gfs2-y := acl.o bmap.o dir.o eaops.o eattr.o glock.o \
gfs2-y := acl.o bmap.o dir.o xattr.o glock.o \
glops.o inode.o log.o lops.o main.o meta_io.o \
aops.o dentry.o export.o file.o \
ops_fstype.o ops_inode.o quota.o \
......
......@@ -19,8 +19,7 @@
#include "gfs2.h"
#include "incore.h"
#include "acl.h"
#include "eaops.h"
#include "eattr.h"
#include "xattr.h"
#include "glock.h"
#include "inode.h"
#include "meta_io.h"
......@@ -31,8 +30,7 @@
#define ACL_DEFAULT 0
int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
struct gfs2_ea_request *er,
int *remove, mode_t *mode)
struct gfs2_ea_request *er, int *remove, mode_t *mode)
{
struct posix_acl *acl;
int error;
......@@ -83,30 +81,20 @@ int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access)
return 0;
}
static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl,
struct gfs2_ea_location *el, char **data, unsigned int *len)
static int acl_get(struct gfs2_inode *ip, const char *name,
struct posix_acl **acl, struct gfs2_ea_location *el,
char **datap, unsigned int *lenp)
{
struct gfs2_ea_request er;
struct gfs2_ea_location el_this;
char *data;
unsigned int len;
int error;
el->el_bh = NULL;
if (!ip->i_eattr)
return 0;
memset(&er, 0, sizeof(struct gfs2_ea_request));
if (access) {
er.er_name = GFS2_POSIX_ACL_ACCESS;
er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN;
} else {
er.er_name = GFS2_POSIX_ACL_DEFAULT;
er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN;
}
er.er_type = GFS2_EATYPE_SYS;
if (!el)
el = &el_this;
error = gfs2_ea_find(ip, &er, el);
error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, name, el);
if (error)
return error;
if (!el->el_ea)
......@@ -114,32 +102,31 @@ static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl,
if (!GFS2_EA_DATA_LEN(el->el_ea))
goto out;
er.er_data_len = GFS2_EA_DATA_LEN(el->el_ea);
er.er_data = kmalloc(er.er_data_len, GFP_NOFS);
len = GFS2_EA_DATA_LEN(el->el_ea);
data = kmalloc(len, GFP_NOFS);
error = -ENOMEM;
if (!er.er_data)
if (!data)
goto out;
error = gfs2_ea_get_copy(ip, el, er.er_data);
if (error)
error = gfs2_ea_get_copy(ip, el, data, len);
if (error < 0)
goto out_kfree;
error = 0;
if (acl) {
*acl = posix_acl_from_xattr(er.er_data, er.er_data_len);
*acl = posix_acl_from_xattr(data, len);
if (IS_ERR(*acl))
error = PTR_ERR(*acl);
}
out_kfree:
if (error || !data)
kfree(er.er_data);
else {
*data = er.er_data;
*len = er.er_data_len;
if (error || !datap) {
kfree(data);
} else {
*datap = data;
*lenp = len;
}
out:
if (error || el == &el_this)
brelse(el->el_bh);
return error;
}
......@@ -153,10 +140,12 @@ static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl,
int gfs2_check_acl(struct inode *inode, int mask)
{
struct gfs2_ea_location el;
struct posix_acl *acl = NULL;
int error;
error = acl_get(GFS2_I(inode), ACL_ACCESS, &acl, NULL, NULL, NULL);
error = acl_get(GFS2_I(inode), GFS2_POSIX_ACL_ACCESS, &acl, &el, NULL, NULL);
brelse(el.el_bh);
if (error)
return error;
......@@ -196,10 +185,12 @@ static int munge_mode(struct gfs2_inode *ip, mode_t mode)
int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
{
struct gfs2_ea_location el;
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct posix_acl *acl = NULL, *clone;
struct gfs2_ea_request er;
mode_t mode = ip->i_inode.i_mode;
char *data = NULL;
unsigned int len;
int error;
if (!sdp->sd_args.ar_posix_acl)
......@@ -207,11 +198,8 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
if (S_ISLNK(ip->i_inode.i_mode))
return 0;
memset(&er, 0, sizeof(struct gfs2_ea_request));
er.er_type = GFS2_EATYPE_SYS;
error = acl_get(dip, ACL_DEFAULT, &acl, NULL,
&er.er_data, &er.er_data_len);
error = acl_get(dip, GFS2_POSIX_ACL_DEFAULT, &acl, &el, &data, &len);
brelse(el.el_bh);
if (error)
return error;
if (!acl) {
......@@ -229,9 +217,8 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
acl = clone;
if (S_ISDIR(ip->i_inode.i_mode)) {
er.er_name = GFS2_POSIX_ACL_DEFAULT;
er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN;
error = gfs2_system_eaops.eo_set(ip, &er);
error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS,
GFS2_POSIX_ACL_DEFAULT, data, len, 0);
if (error)
goto out;
}
......@@ -239,21 +226,19 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
error = posix_acl_create_masq(acl, &mode);
if (error < 0)
goto out;
if (error > 0) {
er.er_name = GFS2_POSIX_ACL_ACCESS;
er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN;
posix_acl_to_xattr(acl, er.er_data, er.er_data_len);
er.er_mode = mode;
er.er_flags = GFS2_ERF_MODE;
error = gfs2_system_eaops.eo_set(ip, &er);
if (error == 0)
goto munge;
posix_acl_to_xattr(acl, data, len);
error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS,
GFS2_POSIX_ACL_ACCESS, data, len, 0);
if (error)
goto out;
} else
munge_mode(ip, mode);
munge:
error = munge_mode(ip, mode);
out:
posix_acl_release(acl);
kfree(er.er_data);
kfree(data);
return error;
}
......@@ -265,9 +250,9 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
unsigned int len;
int error;
error = acl_get(ip, ACL_ACCESS, &acl, &el, &data, &len);
error = acl_get(ip, GFS2_POSIX_ACL_ACCESS, &acl, &el, &data, &len);
if (error)
return error;
goto out_brelse;
if (!acl)
return gfs2_setattr_simple(ip, attr);
......@@ -286,8 +271,9 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
out:
posix_acl_release(acl);
brelse(el.el_bh);
kfree(data);
out_brelse:
brelse(el.el_bh);
return error;
}
......@@ -107,8 +107,26 @@ static int gfs2_dhash(struct dentry *dentry, struct qstr *str)
return 0;
}
static int gfs2_dentry_delete(struct dentry *dentry)
{
struct gfs2_inode *ginode;
if (!dentry->d_inode)
return 0;
ginode = GFS2_I(dentry->d_inode);
if (!ginode->i_iopen_gh.gh_gl)
return 0;
if (test_bit(GLF_DEMOTE, &ginode->i_iopen_gh.gh_gl->gl_flags))
return 1;
return 0;
}
const struct dentry_operations gfs2_dops = {
.d_revalidate = gfs2_drevalidate,
.d_hash = gfs2_dhash,
.d_delete = gfs2_dentry_delete,
};
/*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License version 2.
*/
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/capability.h>
#include <linux/xattr.h>
#include <linux/gfs2_ondisk.h>
#include <asm/uaccess.h>
#include "gfs2.h"
#include "incore.h"
#include "acl.h"
#include "eaops.h"
#include "eattr.h"
#include "util.h"
/**
* gfs2_ea_name2type - get the type of the ea, and truncate type from the name
* @namep: ea name, possibly with type appended
*
* Returns: GFS2_EATYPE_XXX
*/
unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name)
{
unsigned int type;
if (strncmp(name, "system.", 7) == 0) {
type = GFS2_EATYPE_SYS;
if (truncated_name)
*truncated_name = name + sizeof("system.") - 1;
} else if (strncmp(name, "user.", 5) == 0) {
type = GFS2_EATYPE_USR;
if (truncated_name)
*truncated_name = name + sizeof("user.") - 1;
} else if (strncmp(name, "security.", 9) == 0) {
type = GFS2_EATYPE_SECURITY;
if (truncated_name)
*truncated_name = name + sizeof("security.") - 1;
} else {
type = GFS2_EATYPE_UNUSED;
if (truncated_name)
*truncated_name = NULL;
}
return type;
}
static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) &&
!GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len) &&
!capable(CAP_SYS_ADMIN))
return -EPERM;
if (GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl == 0 &&
(GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) ||
GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)))
return -EOPNOTSUPP;
return gfs2_ea_get_i(ip, er);
}
static int system_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
int remove = 0;
int error;
if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
if (!(er->er_flags & GFS2_ERF_MODE)) {
er->er_mode = ip->i_inode.i_mode;
er->er_flags |= GFS2_ERF_MODE;
}
error = gfs2_acl_validate_set(ip, 1, er,
&remove, &er->er_mode);
if (error)
return error;
error = gfs2_ea_set_i(ip, er);
if (error)
return error;
if (remove)
gfs2_ea_remove_i(ip, er);
return 0;
} else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
error = gfs2_acl_validate_set(ip, 0, er,
&remove, NULL);
if (error)
return error;
if (!remove)
error = gfs2_ea_set_i(ip, er);
else {
error = gfs2_ea_remove_i(ip, er);
if (error == -ENODATA)
error = 0;
}
return error;
}
return -EPERM;
}
static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
int error = gfs2_acl_validate_remove(ip, 1);
if (error)
return error;
} else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
int error = gfs2_acl_validate_remove(ip, 0);
if (error)
return error;
} else
return -EPERM;
return gfs2_ea_remove_i(ip, er);
}
static const struct gfs2_eattr_operations gfs2_user_eaops = {
.eo_get = gfs2_ea_get_i,
.eo_set = gfs2_ea_set_i,
.eo_remove = gfs2_ea_remove_i,
.eo_name = "user",
};
const struct gfs2_eattr_operations gfs2_system_eaops = {
.eo_get = system_eo_get,
.eo_set = system_eo_set,
.eo_remove = system_eo_remove,
.eo_name = "system",
};
static const struct gfs2_eattr_operations gfs2_security_eaops = {
.eo_get = gfs2_ea_get_i,
.eo_set = gfs2_ea_set_i,
.eo_remove = gfs2_ea_remove_i,
.eo_name = "security",
};
const struct gfs2_eattr_operations *gfs2_ea_ops[] = {
NULL,
&gfs2_user_eaops,
&gfs2_system_eaops,
&gfs2_security_eaops,
};
/*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License version 2.
*/
#ifndef __EAOPS_DOT_H__
#define __EAOPS_DOT_H__
struct gfs2_ea_request;
struct gfs2_inode;
struct gfs2_eattr_operations {
int (*eo_get) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
int (*eo_set) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
int (*eo_remove) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
char *eo_name;
};
unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name);
extern const struct gfs2_eattr_operations gfs2_system_eaops;
extern const struct gfs2_eattr_operations *gfs2_ea_ops[];
#endif /* __EAOPS_DOT_H__ */
......@@ -146,14 +146,11 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb,
struct gfs2_inum_host *inum)
{
struct gfs2_sbd *sdp = sb->s_fs_info;
struct gfs2_holder i_gh, ri_gh, rgd_gh;
struct gfs2_rgrpd *rgd;
struct gfs2_holder i_gh;
struct inode *inode;
struct dentry *dentry;
int error;
/* System files? */
inode = gfs2_ilookup(sb, inum->no_addr);
if (inode) {
if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) {
......@@ -168,29 +165,11 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb,
if (error)
return ERR_PTR(error);
error = gfs2_rindex_hold(sdp, &ri_gh);
error = gfs2_check_blk_type(sdp, inum->no_addr, GFS2_BLKST_DINODE);
if (error)
goto fail;
error = -EINVAL;
rgd = gfs2_blk2rgrpd(sdp, inum->no_addr);
if (!rgd)
goto fail_rindex;
error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh);
if (error)
goto fail_rindex;
error = -ESTALE;
if (gfs2_get_block_type(rgd, inum->no_addr) != GFS2_BLKST_DINODE)
goto fail_rgd;
gfs2_glock_dq_uninit(&rgd_gh);
gfs2_glock_dq_uninit(&ri_gh);
inode = gfs2_inode_lookup(sb, DT_UNKNOWN,
inum->no_addr,
0, 0);
inode = gfs2_inode_lookup(sb, DT_UNKNOWN, inum->no_addr, 0, 0);
if (IS_ERR(inode)) {
error = PTR_ERR(inode);
goto fail;
......@@ -224,13 +203,6 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb,
if (!IS_ERR(dentry))
dentry->d_op = &gfs2_dops;
return dentry;
fail_rgd:
gfs2_glock_dq_uninit(&rgd_gh);
fail_rindex:
gfs2_glock_dq_uninit(&ri_gh);
fail:
gfs2_glock_dq_uninit(&i_gh);
return ERR_PTR(error);
......
......@@ -38,7 +38,6 @@
#include "rgrp.h"
#include "trans.h"
#include "util.h"
#include "eaops.h"
/**
* gfs2_llseek - seek to a location in a file
......
......@@ -406,6 +406,12 @@ struct gfs2_statfs_change_host {
#define GFS2_DATA_WRITEBACK 1
#define GFS2_DATA_ORDERED 2
#define GFS2_ERRORS_DEFAULT GFS2_ERRORS_WITHDRAW
#define GFS2_ERRORS_WITHDRAW 0
#define GFS2_ERRORS_CONTINUE 1 /* place holder for future feature */
#define GFS2_ERRORS_RO 2 /* place holder for future feature */
#define GFS2_ERRORS_PANIC 3
struct gfs2_args {
char ar_lockproto[GFS2_LOCKNAME_LEN]; /* Name of the Lock Protocol */
char ar_locktable[GFS2_LOCKNAME_LEN]; /* Name of the Lock Table */
......@@ -422,6 +428,7 @@ struct gfs2_args {
unsigned int ar_data:2; /* ordered/writeback */
unsigned int ar_meta:1; /* mount metafs */
unsigned int ar_discard:1; /* discard requests */
unsigned int ar_errors:2; /* errors=withdraw | panic */
int ar_commit; /* Commit interval */
};
......@@ -489,7 +496,6 @@ struct gfs2_sb_host {
*/
struct lm_lockstruct {
u32 ls_id;
unsigned int ls_jid;
unsigned int ls_first;
unsigned int ls_first_done;
......@@ -541,18 +547,12 @@ struct gfs2_sbd {
struct dentry *sd_root_dir;
struct inode *sd_jindex;
struct inode *sd_inum_inode;
struct inode *sd_statfs_inode;
struct inode *sd_ir_inode;
struct inode *sd_sc_inode;
struct inode *sd_qc_inode;
struct inode *sd_rindex;
struct inode *sd_quota_inode;
/* Inum stuff */
struct mutex sd_inum_mutex;
/* StatFS stuff */
spinlock_t sd_statfs_spin;
......@@ -580,7 +580,6 @@ struct gfs2_sbd {
struct gfs2_holder sd_journal_gh;
struct gfs2_holder sd_jinode_gh;
struct gfs2_holder sd_ir_gh;
struct gfs2_holder sd_sc_gh;
struct gfs2_holder sd_qc_gh;
......
......@@ -24,7 +24,7 @@
#include "acl.h"
#include "bmap.h"
#include "dir.h"
#include "eattr.h"
#include "xattr.h"
#include "glock.h"
#include "glops.h"
#include "inode.h"
......@@ -519,139 +519,6 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
return inode ? inode : ERR_PTR(error);
}
static void gfs2_inum_range_in(struct gfs2_inum_range_host *ir, const void *buf)
{
const struct gfs2_inum_range *str = buf;
ir->ir_start = be64_to_cpu(str->ir_start);
ir->ir_length = be64_to_cpu(str->ir_length);
}
static void gfs2_inum_range_out(const struct gfs2_inum_range_host *ir, void *buf)
{
struct gfs2_inum_range *str = buf;
str->ir_start = cpu_to_be64(ir->ir_start);
str->ir_length = cpu_to_be64(ir->ir_length);
}
static int pick_formal_ino_1(struct gfs2_sbd *sdp, u64 *formal_ino)
{
struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode);
struct buffer_head *bh;
struct gfs2_inum_range_host ir;
int error;
error = gfs2_trans_begin(sdp, RES_DINODE, 0);
if (error)
return error;
mutex_lock(&sdp->sd_inum_mutex);
error = gfs2_meta_inode_buffer(ip, &bh);
if (error) {
mutex_unlock(&sdp->sd_inum_mutex);
gfs2_trans_end(sdp);
return error;
}
gfs2_inum_range_in(&ir, bh->b_data + sizeof(struct gfs2_dinode));
if (ir.ir_length) {
*formal_ino = ir.ir_start++;
ir.ir_length--;
gfs2_trans_add_bh(ip->i_gl, bh, 1);
gfs2_inum_range_out(&ir,
bh->b_data + sizeof(struct gfs2_dinode));
brelse(bh);
mutex_unlock(&sdp->sd_inum_mutex);
gfs2_trans_end(sdp);
return 0;
}
brelse(bh);
mutex_unlock(&sdp->sd_inum_mutex);
gfs2_trans_end(sdp);
return 1;
}
static int pick_formal_ino_2(struct gfs2_sbd *sdp, u64 *formal_ino)
{
struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode);
struct gfs2_inode *m_ip = GFS2_I(sdp->sd_inum_inode);
struct gfs2_holder gh;
struct buffer_head *bh;
struct gfs2_inum_range_host ir;
int error;
error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
if (error)
return error;
error = gfs2_trans_begin(sdp, 2 * RES_DINODE, 0);
if (error)
goto out;
mutex_lock(&sdp->sd_inum_mutex);
error = gfs2_meta_inode_buffer(ip, &bh);
if (error)
goto out_end_trans;
gfs2_inum_range_in(&ir, bh->b_data + sizeof(struct gfs2_dinode));
if (!ir.ir_length) {
struct buffer_head *m_bh;
u64 x, y;
__be64 z;
error = gfs2_meta_inode_buffer(m_ip, &m_bh);
if (error)
goto out_brelse;
z = *(__be64 *)(m_bh->b_data + sizeof(struct gfs2_dinode));
x = y = be64_to_cpu(z);
ir.ir_start = x;
ir.ir_length = GFS2_INUM_QUANTUM;
x += GFS2_INUM_QUANTUM;
if (x < y)
gfs2_consist_inode(m_ip);
z = cpu_to_be64(x);
gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1);
*(__be64 *)(m_bh->b_data + sizeof(struct gfs2_dinode)) = z;
brelse(m_bh);
}
*formal_ino = ir.ir_start++;
ir.ir_length--;
gfs2_trans_add_bh(ip->i_gl, bh, 1);
gfs2_inum_range_out(&ir, bh->b_data + sizeof(struct gfs2_dinode));
out_brelse:
brelse(bh);
out_end_trans:
mutex_unlock(&sdp->sd_inum_mutex);
gfs2_trans_end(sdp);
out:
gfs2_glock_dq_uninit(&gh);
return error;
}
static int pick_formal_ino(struct gfs2_sbd *sdp, u64 *inum)
{
int error;
error = pick_formal_ino_1(sdp, inum);
if (error <= 0)
return error;
error = pick_formal_ino_2(sdp, inum);
return error;
}
/**
* create_ok - OK to create a new on-disk inode here?
* @dip: Directory in which dinode is to be created
......@@ -731,7 +598,7 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation)
if (error)
goto out_ipreserv;
*no_addr = gfs2_alloc_di(dip, generation);
error = gfs2_alloc_di(dip, no_addr, generation);
gfs2_trans_end(sdp);
......@@ -924,7 +791,6 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip)
size_t len;
void *value;
char *name;
struct gfs2_ea_request er;
err = security_inode_init_security(&ip->i_inode, &dip->i_inode,
&name, &value, &len);
......@@ -935,16 +801,7 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip)
return err;
}
memset(&er, 0, sizeof(struct gfs2_ea_request));
er.er_type = GFS2_EATYPE_SECURITY;
er.er_name = name;
er.er_data = value;
er.er_name_len = strlen(name);
er.er_data_len = len;
err = gfs2_ea_set_i(ip, &er);
err = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SECURITY, name, value, len, 0);
kfree(value);
kfree(name);
......@@ -991,13 +848,10 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
if (error)
goto fail_gunlock;
error = pick_formal_ino(sdp, &inum.no_formal_ino);
if (error)
goto fail_gunlock;
error = alloc_dinode(dip, &inum.no_addr, &generation);
if (error)
goto fail_gunlock;
inum.no_formal_ino = generation;
error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops,
LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
......@@ -1008,8 +862,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
if (error)
goto fail_gunlock2;
inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode),
inum.no_addr,
inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr,
inum.no_formal_ino, 0);
if (IS_ERR(inode))
goto fail_gunlock2;
......
......@@ -84,7 +84,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
gfs2_tune_init(&sdp->sd_tune);
mutex_init(&sdp->sd_inum_mutex);
spin_lock_init(&sdp->sd_statfs_spin);
spin_lock_init(&sdp->sd_rindex_spin);
......@@ -833,21 +832,12 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo)
if (error)
goto fail;
/* Read in the master inode number inode */
sdp->sd_inum_inode = gfs2_lookup_simple(master, "inum");
if (IS_ERR(sdp->sd_inum_inode)) {
error = PTR_ERR(sdp->sd_inum_inode);
fs_err(sdp, "can't read in inum inode: %d\n", error);
goto fail_journal;
}
/* Read in the master statfs inode */
sdp->sd_statfs_inode = gfs2_lookup_simple(master, "statfs");
if (IS_ERR(sdp->sd_statfs_inode)) {
error = PTR_ERR(sdp->sd_statfs_inode);
fs_err(sdp, "can't read in statfs inode: %d\n", error);
goto fail_inum;
goto fail_journal;
}
/* Read in the resource index inode */
......@@ -876,8 +866,6 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo)
iput(sdp->sd_rindex);
fail_statfs:
iput(sdp->sd_statfs_inode);
fail_inum:
iput(sdp->sd_inum_inode);
fail_journal:
init_journal(sdp, UNDO);
fail:
......@@ -905,20 +893,12 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo)
return error;
}
sprintf(buf, "inum_range%u", sdp->sd_jdesc->jd_jid);
sdp->sd_ir_inode = gfs2_lookup_simple(pn, buf);
if (IS_ERR(sdp->sd_ir_inode)) {
error = PTR_ERR(sdp->sd_ir_inode);
fs_err(sdp, "can't find local \"ir\" file: %d\n", error);
goto fail;
}
sprintf(buf, "statfs_change%u", sdp->sd_jdesc->jd_jid);
sdp->sd_sc_inode = gfs2_lookup_simple(pn, buf);
if (IS_ERR(sdp->sd_sc_inode)) {
error = PTR_ERR(sdp->sd_sc_inode);
fs_err(sdp, "can't find local \"sc\" file: %d\n", error);
goto fail_ir_i;
goto fail;
}
sprintf(buf, "quota_change%u", sdp->sd_jdesc->jd_jid);
......@@ -932,27 +912,16 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo)
iput(pn);
pn = NULL;
ip = GFS2_I(sdp->sd_ir_inode);
error = gfs2_glock_nq_init(ip->i_gl,
LM_ST_EXCLUSIVE, 0,
&sdp->sd_ir_gh);
if (error) {
fs_err(sdp, "can't lock local \"ir\" file: %d\n", error);
goto fail_qc_i;
}
ip = GFS2_I(sdp->sd_sc_inode);
error = gfs2_glock_nq_init(ip->i_gl,
LM_ST_EXCLUSIVE, 0,
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0,
&sdp->sd_sc_gh);
if (error) {
fs_err(sdp, "can't lock local \"sc\" file: %d\n", error);
goto fail_ir_gh;
goto fail_qc_i;
}
ip = GFS2_I(sdp->sd_qc_inode);
error = gfs2_glock_nq_init(ip->i_gl,
LM_ST_EXCLUSIVE, 0,
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0,
&sdp->sd_qc_gh);
if (error) {
fs_err(sdp, "can't lock local \"qc\" file: %d\n", error);
......@@ -965,14 +934,10 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo)
gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
fail_ut_gh:
gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
fail_ir_gh:
gfs2_glock_dq_uninit(&sdp->sd_ir_gh);
fail_qc_i:
iput(sdp->sd_qc_inode);
fail_ut_i:
iput(sdp->sd_sc_inode);
fail_ir_i:
iput(sdp->sd_ir_inode);
fail:
if (pn)
iput(pn);
......@@ -1063,7 +1028,6 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
ls->ls_ops = lm;
ls->ls_first = 1;
ls->ls_id = 0;
for (options = args->ar_hostdata; (o = strsep(&options, ":")); ) {
substring_t tmp[MAX_OPT_ARGS];
......@@ -1081,10 +1045,7 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
ls->ls_jid = option;
break;
case Opt_id:
ret = match_int(&tmp[0], &option);
if (ret)
goto hostdata_error;
ls->ls_id = option;
/* Obsolete, but left for backward compat purposes */
break;
case Opt_first:
ret = match_int(&tmp[0], &option);
......@@ -1133,6 +1094,17 @@ void gfs2_lm_unmount(struct gfs2_sbd *sdp)
lm->lm_unmount(sdp);
}
void gfs2_online_uevent(struct gfs2_sbd *sdp)
{
struct super_block *sb = sdp->sd_vfs;
char ro[20];
char spectator[20];
char *envp[] = { ro, spectator, NULL };
sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0);
sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0);
kobject_uevent_env(&sdp->sd_kobj, KOBJ_ONLINE, envp);
}
/**
* fill_super - Read in superblock
* @sb: The VFS superblock
......@@ -1157,6 +1129,7 @@ static int fill_super(struct super_block *sb, void *data, int silent)
sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT;
sdp->sd_args.ar_data = GFS2_DATA_DEFAULT;
sdp->sd_args.ar_commit = 60;
sdp->sd_args.ar_errors = GFS2_ERRORS_DEFAULT;
error = gfs2_mount_args(sdp, &sdp->sd_args, data);
if (error) {
......@@ -1174,6 +1147,7 @@ static int fill_super(struct super_block *sb, void *data, int silent)
sb->s_magic = GFS2_MAGIC;
sb->s_op = &gfs2_super_ops;
sb->s_export_op = &gfs2_export_ops;
sb->s_xattr = gfs2_xattr_handlers;
sb->s_time_gran = 1;
sb->s_maxbytes = MAX_LFS_FILESIZE;
......@@ -1236,7 +1210,7 @@ static int fill_super(struct super_block *sb, void *data, int silent)
}
gfs2_glock_dq_uninit(&mount_gh);
gfs2_online_uevent(sdp);
return 0;
fail_threads:
......
......@@ -26,8 +26,7 @@
#include "acl.h"
#include "bmap.h"
#include "dir.h"
#include "eaops.h"
#include "eattr.h"
#include "xattr.h"
#include "glock.h"
#include "inode.h"
#include "meta_io.h"
......@@ -349,7 +348,7 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0);
if (error)
goto out_rgrp;
goto out_gunlock;
error = gfs2_dir_del(dip, &dentry->d_name);
if (error)
......@@ -1302,60 +1301,53 @@ static int gfs2_setxattr(struct dentry *dentry, const char *name,
const void *data, size_t size, int flags)
{
struct inode *inode = dentry->d_inode;
struct gfs2_ea_request er;
memset(&er, 0, sizeof(struct gfs2_ea_request));
er.er_type = gfs2_ea_name2type(name, &er.er_name);
if (er.er_type == GFS2_EATYPE_UNUSED)
return -EOPNOTSUPP;
er.er_data = (char *)data;
er.er_name_len = strlen(er.er_name);
er.er_data_len = size;
er.er_flags = flags;
gfs2_assert_warn(GFS2_SB(inode), !(er.er_flags & GFS2_ERF_MODE));
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh;
int ret;
return gfs2_ea_set(GFS2_I(inode), &er);
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
ret = gfs2_glock_nq(&gh);
if (ret == 0) {
ret = generic_setxattr(dentry, name, data, size, flags);
gfs2_glock_dq(&gh);
}
gfs2_holder_uninit(&gh);
return ret;
}
static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name,
void *data, size_t size)
{
struct gfs2_ea_request er;
memset(&er, 0, sizeof(struct gfs2_ea_request));
er.er_type = gfs2_ea_name2type(name, &er.er_name);
if (er.er_type == GFS2_EATYPE_UNUSED)
return -EOPNOTSUPP;
er.er_data = data;
er.er_name_len = strlen(er.er_name);
er.er_data_len = size;
return gfs2_ea_get(GFS2_I(dentry->d_inode), &er);
}
static ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
{
struct gfs2_ea_request er;
memset(&er, 0, sizeof(struct gfs2_ea_request));
er.er_data = (size) ? buffer : NULL;
er.er_data_len = size;
struct inode *inode = dentry->d_inode;
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh;
int ret;
return gfs2_ea_list(GFS2_I(dentry->d_inode), &er);
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
ret = gfs2_glock_nq(&gh);
if (ret == 0) {
ret = generic_getxattr(dentry, name, data, size);
gfs2_glock_dq(&gh);
}
gfs2_holder_uninit(&gh);
return ret;
}
static int gfs2_removexattr(struct dentry *dentry, const char *name)
{
struct gfs2_ea_request er;
memset(&er, 0, sizeof(struct gfs2_ea_request));
er.er_type = gfs2_ea_name2type(name, &er.er_name);
if (er.er_type == GFS2_EATYPE_UNUSED)
return -EOPNOTSUPP;
er.er_name_len = strlen(er.er_name);
struct inode *inode = dentry->d_inode;
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh;
int ret;
return gfs2_ea_remove(GFS2_I(dentry->d_inode), &er);
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
ret = gfs2_glock_nq(&gh);
if (ret == 0) {
ret = generic_removexattr(dentry, name);
gfs2_glock_dq(&gh);
}
gfs2_holder_uninit(&gh);
return ret;
}
static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
......
......@@ -1256,7 +1256,7 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
* Returns: The block type (GFS2_BLKST_*)
*/
unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block)
static unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block)
{
struct gfs2_bitmap *bi = NULL;
u32 length, rgrp_block, buf_block;
......@@ -1459,6 +1459,16 @@ int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl)
return 0;
}
static void gfs2_rgrp_error(struct gfs2_rgrpd *rgd)
{
struct gfs2_sbd *sdp = rgd->rd_sbd;
fs_warn(sdp, "rgrp %llu has an error, marking it readonly until umount\n",
(unsigned long long)rgd->rd_addr);
fs_warn(sdp, "umount on all nodes and run fsck.gfs2 to fix the error\n");
gfs2_rgrp_dump(NULL, rgd->rd_gl);
rgd->rd_flags |= GFS2_RDF_ERROR;
}
/**
* gfs2_alloc_block - Allocate one or more blocks
* @ip: the inode to allocate the block for
......@@ -1520,22 +1530,20 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n)
return 0;
rgrp_error:
fs_warn(sdp, "rgrp %llu has an error, marking it readonly until umount\n",
(unsigned long long)rgd->rd_addr);
fs_warn(sdp, "umount on all nodes and run fsck.gfs2 to fix the error\n");
gfs2_rgrp_dump(NULL, rgd->rd_gl);
rgd->rd_flags |= GFS2_RDF_ERROR;
gfs2_rgrp_error(rgd);
return -EIO;
}
/**
* gfs2_alloc_di - Allocate a dinode
* @dip: the directory that the inode is going in
* @bn: the block number which is allocated
* @generation: the generation number of the inode
*
* Returns: the block allocated
* Returns: 0 on success or error
*/
u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
int gfs2_alloc_di(struct gfs2_inode *dip, u64 *bn, u64 *generation)
{
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct gfs2_alloc *al = dip->i_alloc;
......@@ -1546,16 +1554,21 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
blk = rgblk_search(rgd, rgd->rd_last_alloc,
GFS2_BLKST_FREE, GFS2_BLKST_DINODE, &n);
BUG_ON(blk == BFITNOENT);
rgd->rd_last_alloc = blk;
/* Since all blocks are reserved in advance, this shouldn't happen */
if (blk == BFITNOENT)
goto rgrp_error;
rgd->rd_last_alloc = blk;
block = rgd->rd_data0 + blk;
if (rgd->rd_free == 0)
goto rgrp_error;
gfs2_assert_withdraw(sdp, rgd->rd_free);
rgd->rd_free--;
rgd->rd_dinodes++;
*generation = rgd->rd_igeneration++;
if (*generation == 0)
*generation = rgd->rd_igeneration++;
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
......@@ -1568,7 +1581,12 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
rgd->rd_free_clone--;
spin_unlock(&sdp->sd_rindex_spin);
trace_gfs2_block_alloc(dip, block, 1, GFS2_BLKST_DINODE);
return block;
*bn = block;
return 0;
rgrp_error:
gfs2_rgrp_error(rgd);
return -EIO;
}
/**
......@@ -1675,6 +1693,46 @@ void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
gfs2_meta_wipe(ip, ip->i_no_addr, 1);
}
/**
* gfs2_check_blk_type - Check the type of a block
* @sdp: The superblock
* @no_addr: The block number to check
* @type: The block type we are looking for
*
* Returns: 0 if the block type matches the expected type
* -ESTALE if it doesn't match
* or -ve errno if something went wrong while checking
*/
int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type)
{
struct gfs2_rgrpd *rgd;
struct gfs2_holder ri_gh, rgd_gh;
int error;
error = gfs2_rindex_hold(sdp, &ri_gh);
if (error)
goto fail;
error = -EINVAL;
rgd = gfs2_blk2rgrpd(sdp, no_addr);
if (!rgd)
goto fail_rindex;
error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh);
if (error)
goto fail_rindex;
if (gfs2_get_block_type(rgd, no_addr) != type)
error = -ESTALE;
gfs2_glock_dq_uninit(&rgd_gh);
fail_rindex:
gfs2_glock_dq_uninit(&ri_gh);
fail:
return error;
}
/**
* gfs2_rlist_add - add a RG to a list of RGs
* @sdp: the filesystem
......
......@@ -44,15 +44,15 @@ gfs2_inplace_reserve_i((ip), __FILE__, __LINE__)
extern void gfs2_inplace_release(struct gfs2_inode *ip);
extern unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block);
extern int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n);
extern u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation);
extern int gfs2_alloc_di(struct gfs2_inode *ip, u64 *bn, u64 *generation);
extern void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen);
extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen);
extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip);
extern void gfs2_unlink_di(struct inode *inode);
extern int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr,
unsigned int type);
struct gfs2_rgrp_list {
unsigned int rl_rgrps;
......
......@@ -38,7 +38,7 @@
#include "trans.h"
#include "util.h"
#include "sys.h"
#include "eattr.h"
#include "xattr.h"
#define args_neq(a1, a2, x) ((a1)->ar_##x != (a2)->ar_##x)
......@@ -68,6 +68,8 @@ enum {
Opt_discard,
Opt_nodiscard,
Opt_commit,
Opt_err_withdraw,
Opt_err_panic,
Opt_error,
};
......@@ -97,6 +99,8 @@ static const match_table_t tokens = {
{Opt_discard, "discard"},
{Opt_nodiscard, "nodiscard"},
{Opt_commit, "commit=%d"},
{Opt_err_withdraw, "errors=withdraw"},
{Opt_err_panic, "errors=panic"},
{Opt_error, NULL}
};
......@@ -152,6 +156,11 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
args->ar_localcaching = 1;
break;
case Opt_debug:
if (args->ar_errors == GFS2_ERRORS_PANIC) {
fs_info(sdp, "-o debug and -o errors=panic "
"are mutually exclusive.\n");
return -EINVAL;
}
args->ar_debug = 1;
break;
case Opt_nodebug:
......@@ -205,6 +214,17 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
return rv ? rv : -EINVAL;
}
break;
case Opt_err_withdraw:
args->ar_errors = GFS2_ERRORS_WITHDRAW;
break;
case Opt_err_panic:
if (args->ar_debug) {
fs_info(sdp, "-o debug and -o errors=panic "
"are mutually exclusive.\n");
return -EINVAL;
}
args->ar_errors = GFS2_ERRORS_PANIC;
break;
case Opt_error:
default:
fs_info(sdp, "invalid mount option: %s\n", o);
......@@ -768,7 +788,6 @@ static void gfs2_put_super(struct super_block *sb)
/* Release stuff */
iput(sdp->sd_jindex);
iput(sdp->sd_inum_inode);
iput(sdp->sd_statfs_inode);
iput(sdp->sd_rindex);
iput(sdp->sd_quota_inode);
......@@ -779,10 +798,8 @@ static void gfs2_put_super(struct super_block *sb)
if (!sdp->sd_args.ar_spectator) {
gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
gfs2_glock_dq_uninit(&sdp->sd_ir_gh);
gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
iput(sdp->sd_ir_inode);
iput(sdp->sd_sc_inode);
iput(sdp->sd_qc_inode);
}
......@@ -1084,6 +1101,7 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
gt->gt_log_flush_secs = args.ar_commit;
spin_unlock(&gt->gt_spin);
gfs2_online_uevent(sdp);
return 0;
}
......@@ -1225,6 +1243,22 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
lfsecs = sdp->sd_tune.gt_log_flush_secs;
if (lfsecs != 60)
seq_printf(s, ",commit=%d", lfsecs);
if (args->ar_errors != GFS2_ERRORS_DEFAULT) {
const char *state;
switch (args->ar_errors) {
case GFS2_ERRORS_WITHDRAW:
state = "withdraw";
break;
case GFS2_ERRORS_PANIC:
state = "panic";
break;
default:
state = "unknown";
break;
}
seq_printf(s, ",errors=%s", state);
}
return 0;
}
......@@ -1252,6 +1286,10 @@ static void gfs2_delete_inode(struct inode *inode)
goto out;
}
error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
if (error)
goto out_truncate;
gfs2_glock_dq_wait(&ip->i_iopen_gh);
gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh);
error = gfs2_glock_nq(&ip->i_iopen_gh);
......
......@@ -25,7 +25,7 @@ static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp)
return x;
}
void gfs2_jindex_free(struct gfs2_sbd *sdp);
extern void gfs2_jindex_free(struct gfs2_sbd *sdp);
extern int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *data);
......@@ -36,7 +36,7 @@ extern int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename,
struct gfs2_inode **ipp);
extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp);
extern void gfs2_online_uevent(struct gfs2_sbd *sdp);
extern int gfs2_statfs_init(struct gfs2_sbd *sdp);
extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
s64 dinodes);
......@@ -54,6 +54,7 @@ extern struct file_system_type gfs2meta_fs_type;
extern const struct export_operations gfs2_export_ops;
extern const struct super_operations gfs2_super_ops;
extern const struct dentry_operations gfs2_dops;
extern struct xattr_handler *gfs2_xattr_handlers[];
#endif /* __SUPER_DOT_H__ */
......@@ -16,6 +16,7 @@
#include <linux/kobject.h>
#include <asm/uaccess.h>
#include <linux/gfs2_ondisk.h>
#include <linux/genhd.h>
#include "gfs2.h"
#include "incore.h"
......@@ -319,12 +320,6 @@ static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
return ret;
}
static ssize_t lkid_show(struct gfs2_sbd *sdp, char *buf)
{
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
return sprintf(buf, "%u\n", ls->ls_id);
}
static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf)
{
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
......@@ -389,7 +384,6 @@ static struct gfs2_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store)
GDLM_ATTR(proto_name, 0444, proto_name_show, NULL);
GDLM_ATTR(block, 0644, block_show, block_store);
GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store);
GDLM_ATTR(id, 0444, lkid_show, NULL);
GDLM_ATTR(jid, 0444, jid_show, NULL);
GDLM_ATTR(first, 0444, lkfirst_show, NULL);
GDLM_ATTR(first_done, 0444, first_done_show, NULL);
......@@ -401,7 +395,6 @@ static struct attribute *lock_module_attrs[] = {
&gdlm_attr_proto_name.attr,
&gdlm_attr_block.attr,
&gdlm_attr_withdraw.attr,
&gdlm_attr_id.attr,
&gdlm_attr_jid.attr,
&gdlm_attr_first.attr,
&gdlm_attr_first_done.attr,
......@@ -519,7 +512,14 @@ static struct attribute_group lock_module_group = {
int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
{
struct super_block *sb = sdp->sd_vfs;
int error;
char ro[20];
char spectator[20];
char *envp[] = { ro, spectator, NULL };
sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0);
sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0);
sdp->sd_kobj.kset = gfs2_kset;
error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL,
......@@ -535,9 +535,17 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
if (error)
goto fail_tune;
kobject_uevent(&sdp->sd_kobj, KOBJ_ADD);
error = sysfs_create_link(&sdp->sd_kobj,
&disk_to_dev(sb->s_bdev->bd_disk)->kobj,
"device");
if (error)
goto fail_lock_module;
kobject_uevent_env(&sdp->sd_kobj, KOBJ_ADD, envp);
return 0;
fail_lock_module:
sysfs_remove_group(&sdp->sd_kobj, &lock_module_group);
fail_tune:
sysfs_remove_group(&sdp->sd_kobj, &tune_group);
fail_reg:
......@@ -549,12 +557,12 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
void gfs2_sys_fs_del(struct gfs2_sbd *sdp)
{
sysfs_remove_link(&sdp->sd_kobj, "device");
sysfs_remove_group(&sdp->sd_kobj, &tune_group);
sysfs_remove_group(&sdp->sd_kobj, &lock_module_group);
kobject_put(&sdp->sd_kobj);
}
static int gfs2_uevent(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env *env)
{
......@@ -563,6 +571,8 @@ static int gfs2_uevent(struct kset *kset, struct kobject *kobj,
add_uevent_var(env, "LOCKTABLE=%s", sdp->sd_table_name);
add_uevent_var(env, "LOCKPROTO=%s", sdp->sd_proto_name);
if (!sdp->sd_args.ar_spectator)
add_uevent_var(env, "JOURNALID=%u", sdp->sd_lockstruct.ls_jid);
if (gfs2_uuid_valid(uuid)) {
add_uevent_var(env, "UUID=%02X%02X%02X%02X-%02X%02X-%02X%02X-"
"%02X%02X-%02X%02X%02X%02X%02X%02X",
......@@ -578,7 +588,6 @@ static struct kset_uevent_ops gfs2_uevent_ops = {
.uevent = gfs2_uevent,
};
int gfs2_sys_init(void)
{
gfs2_kset = kset_create_and_add("gfs2", &gfs2_uevent_ops, fs_kobj);
......
......@@ -38,13 +38,15 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
const struct lm_lockops *lm = ls->ls_ops;
va_list args;
if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags))
if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW &&
test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags))
return 0;
va_start(args, fmt);
vprintk(fmt, args);
va_end(args);
if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) {
fs_err(sdp, "about to withdraw this file system\n");
BUG_ON(sdp->sd_args.ar_debug);
......@@ -56,6 +58,10 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
}
fs_err(sdp, "withdrawn\n");
dump_stack();
}
if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC)
panic("GFS2: fsid=%s: panic requested.\n", sdp->sd_fsname);
return -1;
}
......@@ -93,6 +99,7 @@ int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion,
gfs2_tune_get(sdp, gt_complain_secs) * HZ))
return -2;
if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW)
printk(KERN_WARNING
"GFS2: fsid=%s: warning: assertion \"%s\" failed\n"
"GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
......@@ -104,6 +111,12 @@ int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion,
else
dump_stack();
if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC)
panic("GFS2: fsid=%s: warning: assertion \"%s\" failed\n"
"GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
sdp->sd_fsname, assertion,
sdp->sd_fsname, function, file, line);
sdp->sd_last_warning = jiffies;
return -1;
......
......@@ -18,8 +18,7 @@
#include "gfs2.h"
#include "incore.h"
#include "acl.h"
#include "eaops.h"
#include "eattr.h"
#include "xattr.h"
#include "glock.h"
#include "inode.h"
#include "meta_io.h"
......@@ -38,26 +37,32 @@
* Returns: 1 if the EA should be stuffed
*/
static int ea_calc_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er,
static int ea_calc_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize,
unsigned int *size)
{
*size = GFS2_EAREQ_SIZE_STUFFED(er);
if (*size <= sdp->sd_jbsize)
unsigned int jbsize = sdp->sd_jbsize;
/* Stuffed */
*size = ALIGN(sizeof(struct gfs2_ea_header) + nsize + dsize, 8);
if (*size <= jbsize)
return 1;
*size = GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er);
/* Unstuffed */
*size = ALIGN(sizeof(struct gfs2_ea_header) + nsize +
(sizeof(__be64) * DIV_ROUND_UP(dsize, jbsize)), 8);
return 0;
}
static int ea_check_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er)
static int ea_check_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize)
{
unsigned int size;
if (er->er_data_len > GFS2_EA_MAX_DATA_LEN)
if (dsize > GFS2_EA_MAX_DATA_LEN)
return -ERANGE;
ea_calc_size(sdp, er, &size);
ea_calc_size(sdp, nsize, dsize, &size);
/* This can only happen with 512 byte blocks */
if (size > sdp->sd_jbsize)
......@@ -151,7 +156,9 @@ static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data)
}
struct ea_find {
struct gfs2_ea_request *ef_er;
int type;
const char *name;
size_t namel;
struct gfs2_ea_location *ef_el;
};
......@@ -160,14 +167,13 @@ static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh,
void *private)
{
struct ea_find *ef = private;
struct gfs2_ea_request *er = ef->ef_er;
if (ea->ea_type == GFS2_EATYPE_UNUSED)
return 0;
if (ea->ea_type == er->er_type) {
if (ea->ea_name_len == er->er_name_len &&
!memcmp(GFS2_EA2NAME(ea), er->er_name, ea->ea_name_len)) {
if (ea->ea_type == ef->type) {
if (ea->ea_name_len == ef->namel &&
!memcmp(GFS2_EA2NAME(ea), ef->name, ea->ea_name_len)) {
struct gfs2_ea_location *el = ef->ef_el;
get_bh(bh);
el->el_bh = bh;
......@@ -180,13 +186,15 @@ static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh,
return 0;
}
int gfs2_ea_find(struct gfs2_inode *ip, struct gfs2_ea_request *er,
int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name,
struct gfs2_ea_location *el)
{
struct ea_find ef;
int error;
ef.ef_er = er;
ef.type = type;
ef.name = name;
ef.namel = strlen(name);
ef.ef_el = el;
memset(el, 0, sizeof(struct gfs2_ea_location));
......@@ -344,6 +352,20 @@ struct ea_list {
unsigned int ei_size;
};
static inline unsigned int gfs2_ea_strlen(struct gfs2_ea_header *ea)
{
switch (ea->ea_type) {
case GFS2_EATYPE_USR:
return 5 + ea->ea_name_len + 1;
case GFS2_EATYPE_SYS:
return 7 + ea->ea_name_len + 1;
case GFS2_EATYPE_SECURITY:
return 9 + ea->ea_name_len + 1;
default:
return 0;
}
}
static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh,
struct gfs2_ea_header *ea, struct gfs2_ea_header *prev,
void *private)
......@@ -392,21 +414,25 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh,
}
/**
* gfs2_ea_list -
* @ip:
* @er:
* gfs2_listxattr - List gfs2 extended attributes
* @dentry: The dentry whose inode we are interested in
* @buffer: The buffer to write the results
* @size: The size of the buffer
*
* Returns: actual size of data on success, -errno on error
*/
int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er)
ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
{
struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
struct gfs2_ea_request er;
struct gfs2_holder i_gh;
int error;
if (!er->er_data || !er->er_data_len) {
er->er_data = NULL;
er->er_data_len = 0;
memset(&er, 0, sizeof(struct gfs2_ea_request));
if (size) {
er.er_data = buffer;
er.er_data_len = size;
}
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
......@@ -414,7 +440,7 @@ int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er)
return error;
if (ip->i_eattr) {
struct ea_list ei = { .ei_er = er, .ei_size = 0 };
struct ea_list ei = { .ei_er = &er, .ei_size = 0 };
error = ea_foreach(ip, ea_list_i, &ei);
if (!error)
......@@ -491,83 +517,60 @@ static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
}
int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el,
char *data)
char *data, size_t size)
{
int ret;
size_t len = GFS2_EA_DATA_LEN(el->el_ea);
if (len > size)
return -ERANGE;
if (GFS2_EA_IS_STUFFED(el->el_ea)) {
memcpy(data, GFS2_EA2DATA(el->el_ea), GFS2_EA_DATA_LEN(el->el_ea));
return 0;
} else
return ea_get_unstuffed(ip, el->el_ea, data);
memcpy(data, GFS2_EA2DATA(el->el_ea), len);
return len;
}
ret = ea_get_unstuffed(ip, el->el_ea, data);
if (ret < 0)
return ret;
return len;
}
/**
* gfs2_ea_get_i -
* @ip: The GFS2 inode
* @er: The request structure
* gfs2_xattr_get - Get a GFS2 extended attribute
* @inode: The inode
* @type: The type of extended attribute
* @name: The name of the extended attribute
* @buffer: The buffer to write the result into
* @size: The size of the buffer
*
* Returns: actual size of data on success, -errno on error
*/
int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er)
int gfs2_xattr_get(struct inode *inode, int type, const char *name,
void *buffer, size_t size)
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_ea_location el;
int error;
if (!ip->i_eattr)
return -ENODATA;
if (strlen(name) > GFS2_EA_MAX_NAME_LEN)
return -EINVAL;
error = gfs2_ea_find(ip, er, &el);
error = gfs2_ea_find(ip, type, name, &el);
if (error)
return error;
if (!el.el_ea)
return -ENODATA;
if (er->er_data_len) {
if (GFS2_EA_DATA_LEN(el.el_ea) > er->er_data_len)
error = -ERANGE;
if (size)
error = gfs2_ea_get_copy(ip, &el, buffer, size);
else
error = gfs2_ea_get_copy(ip, &el, er->er_data);
}
if (!error)
error = GFS2_EA_DATA_LEN(el.el_ea);
brelse(el.el_bh);
return error;
}
/**
* gfs2_ea_get -
* @ip: The GFS2 inode
* @er: The request structure
*
* Returns: actual size of data on success, -errno on error
*/
int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
struct gfs2_holder i_gh;
int error;
if (!er->er_name_len ||
er->er_name_len > GFS2_EA_MAX_NAME_LEN)
return -EINVAL;
if (!er->er_data || !er->er_data_len) {
er->er_data = NULL;
er->er_data_len = 0;
}
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
if (error)
return error;
error = gfs2_ea_ops[er->er_type]->eo_get(ip, er);
gfs2_glock_dq_uninit(&i_gh);
return error;
}
/**
* ea_alloc_blk - allocates a new block for extended attributes.
* @ip: A pointer to the inode that's getting extended attributes
......@@ -713,12 +716,6 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
if (er->er_flags & GFS2_ERF_MODE) {
gfs2_assert_withdraw(GFS2_SB(&ip->i_inode),
(ip->i_inode.i_mode & S_IFMT) ==
(er->er_mode & S_IFMT));
ip->i_inode.i_mode = er->er_mode;
}
ip->i_inode.i_ctime = CURRENT_TIME;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
......@@ -762,15 +759,23 @@ static int ea_init_i(struct gfs2_inode *ip, struct gfs2_ea_request *er,
* Returns: errno
*/
static int ea_init(struct gfs2_inode *ip, struct gfs2_ea_request *er)
static int ea_init(struct gfs2_inode *ip, int type, const char *name,
const void *data, size_t size)
{
struct gfs2_ea_request er;
unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize;
unsigned int blks = 1;
if (GFS2_EAREQ_SIZE_STUFFED(er) > jbsize)
blks += DIV_ROUND_UP(er->er_data_len, jbsize);
er.er_type = type;
er.er_name = name;
er.er_name_len = strlen(name);
er.er_data = (void *)data;
er.er_data_len = size;
if (GFS2_EAREQ_SIZE_STUFFED(&er) > jbsize)
blks += DIV_ROUND_UP(er.er_data_len, jbsize);
return ea_alloc_skeleton(ip, er, blks, ea_init_i, NULL);
return ea_alloc_skeleton(ip, &er, blks, ea_init_i, NULL);
}
static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea)
......@@ -848,12 +853,6 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh,
error = gfs2_meta_inode_buffer(ip, &dibh);
if (error)
goto out;
if (er->er_flags & GFS2_ERF_MODE) {
gfs2_assert_withdraw(GFS2_SB(&ip->i_inode),
(ip->i_inode.i_mode & S_IFMT) == (er->er_mode & S_IFMT));
ip->i_inode.i_mode = er->er_mode;
}
ip->i_inode.i_ctime = CURRENT_TIME;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
......@@ -894,7 +893,8 @@ static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh,
int stuffed;
int error;
stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er, &size);
stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er->er_name_len,
es->es_er->er_data_len, &size);
if (ea->ea_type == GFS2_EATYPE_UNUSED) {
if (GFS2_EA_REC_LEN(ea) < size)
......@@ -1005,15 +1005,22 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er,
return error;
}
static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er,
struct gfs2_ea_location *el)
static int ea_set_i(struct gfs2_inode *ip, int type, const char *name,
const void *value, size_t size, struct gfs2_ea_location *el)
{
struct gfs2_ea_request er;
struct ea_set es;
unsigned int blks = 2;
int error;
er.er_type = type;
er.er_name = name;
er.er_data = (void *)value;
er.er_name_len = strlen(name);
er.er_data_len = size;
memset(&es, 0, sizeof(struct ea_set));
es.es_er = er;
es.es_er = &er;
es.es_el = el;
error = ea_foreach(ip, ea_set_simple, &es);
......@@ -1024,10 +1031,10 @@ static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er,
if (!(ip->i_diskflags & GFS2_DIF_EA_INDIRECT))
blks++;
if (GFS2_EAREQ_SIZE_STUFFED(er) > GFS2_SB(&ip->i_inode)->sd_jbsize)
blks += DIV_ROUND_UP(er->er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize);
if (GFS2_EAREQ_SIZE_STUFFED(&er) > GFS2_SB(&ip->i_inode)->sd_jbsize)
blks += DIV_ROUND_UP(er.er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize);
return ea_alloc_skeleton(ip, er, blks, ea_set_block, el);
return ea_alloc_skeleton(ip, &er, blks, ea_set_block, el);
}
static int ea_set_remove_unstuffed(struct gfs2_inode *ip,
......@@ -1039,75 +1046,7 @@ static int ea_set_remove_unstuffed(struct gfs2_inode *ip,
GFS2_EA2NEXT(el->el_prev) == el->el_ea);
}
return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev,0);
}
int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
struct gfs2_ea_location el;
int error;
if (!ip->i_eattr) {
if (er->er_flags & XATTR_REPLACE)
return -ENODATA;
return ea_init(ip, er);
}
error = gfs2_ea_find(ip, er, &el);
if (error)
return error;
if (el.el_ea) {
if (ip->i_diskflags & GFS2_DIF_APPENDONLY) {
brelse(el.el_bh);
return -EPERM;
}
error = -EEXIST;
if (!(er->er_flags & XATTR_CREATE)) {
int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea);
error = ea_set_i(ip, er, &el);
if (!error && unstuffed)
ea_set_remove_unstuffed(ip, &el);
}
brelse(el.el_bh);
} else {
error = -ENODATA;
if (!(er->er_flags & XATTR_REPLACE))
error = ea_set_i(ip, er, NULL);
}
return error;
}
int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
struct gfs2_holder i_gh;
int error;
if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN)
return -EINVAL;
if (!er->er_data || !er->er_data_len) {
er->er_data = NULL;
er->er_data_len = 0;
}
error = ea_check_size(GFS2_SB(&ip->i_inode), er);
if (error)
return error;
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
if (error)
return error;
if (IS_IMMUTABLE(&ip->i_inode))
error = -EPERM;
else
error = gfs2_ea_ops[er->er_type]->eo_set(ip, er);
gfs2_glock_dq_uninit(&i_gh);
return error;
return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev, 0);
}
static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el)
......@@ -1131,8 +1070,9 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el)
if (GFS2_EA_IS_LAST(ea))
prev->ea_flags |= GFS2_EAFLAG_LAST;
} else
} else {
ea->ea_type = GFS2_EATYPE_UNUSED;
}
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
......@@ -1147,15 +1087,29 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el)
return error;
}
int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er)
/**
* gfs2_xattr_remove - Remove a GFS2 extended attribute
* @inode: The inode
* @type: The type of the extended attribute
* @name: The name of the extended attribute
*
* This is not called directly by the VFS since we use the (common)
* scheme of making a "set with NULL data" mean a remove request. Note
* that this is different from a set with zero length data.
*
* Returns: 0, or errno on failure
*/
static int gfs2_xattr_remove(struct inode *inode, int type, const char *name)
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_ea_location el;
int error;
if (!ip->i_eattr)
return -ENODATA;
error = gfs2_ea_find(ip, er, &el);
error = gfs2_ea_find(ip, type, name, &el);
if (error)
return error;
if (!el.el_ea)
......@@ -1164,8 +1118,7 @@ int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er)
if (GFS2_EA_IS_STUFFED(el.el_ea))
error = ea_remove_stuffed(ip, &el);
else
error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev,
0);
error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev, 0);
brelse(el.el_bh);
......@@ -1173,31 +1126,70 @@ int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er)
}
/**
* gfs2_ea_remove - sets (or creates or replaces) an extended attribute
* @ip: pointer to the inode of the target file
* @er: request information
* gfs2_xattr_set - Set (or remove) a GFS2 extended attribute
* @inode: The inode
* @type: The type of the extended attribute
* @name: The name of the extended attribute
* @value: The value of the extended attribute (NULL for remove)
* @size: The size of the @value argument
* @flags: Create or Replace
*
* Returns: errno
* See gfs2_xattr_remove() for details of the removal of xattrs.
*
* Returns: 0 or errno on failure
*/
int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
int gfs2_xattr_set(struct inode *inode, int type, const char *name,
const void *value, size_t size, int flags)
{
struct gfs2_holder i_gh;
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_ea_location el;
unsigned int namel = strlen(name);
int error;
if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN)
return -EINVAL;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
if (namel > GFS2_EA_MAX_NAME_LEN)
return -ERANGE;
if (value == NULL)
return gfs2_xattr_remove(inode, type, name);
if (ea_check_size(sdp, namel, size))
return -ERANGE;
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
if (!ip->i_eattr) {
if (flags & XATTR_REPLACE)
return -ENODATA;
return ea_init(ip, type, name, value, size);
}
error = gfs2_ea_find(ip, type, name, &el);
if (error)
return error;
if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode))
error = -EPERM;
else
error = gfs2_ea_ops[er->er_type]->eo_remove(ip, er);
if (el.el_ea) {
if (ip->i_diskflags & GFS2_DIF_APPENDONLY) {
brelse(el.el_bh);
return -EPERM;
}
gfs2_glock_dq_uninit(&i_gh);
error = -EEXIST;
if (!(flags & XATTR_CREATE)) {
int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea);
error = ea_set_i(ip, type, name, value, size, &el);
if (!error && unstuffed)
ea_set_remove_unstuffed(ip, &el);
}
brelse(el.el_bh);
return error;
}
error = -ENODATA;
if (!(flags & XATTR_REPLACE))
error = ea_set_i(ip, type, name, value, size, NULL);
return error;
}
......@@ -1503,3 +1495,64 @@ int gfs2_ea_dealloc(struct gfs2_inode *ip)
return error;
}
static int gfs2_xattr_user_get(struct inode *inode, const char *name,
void *buffer, size_t size)
{
return gfs2_xattr_get(inode, GFS2_EATYPE_USR, name, buffer, size);
}
static int gfs2_xattr_user_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
return gfs2_xattr_set(inode, GFS2_EATYPE_USR, name, value, size, flags);
}
static int gfs2_xattr_system_get(struct inode *inode, const char *name,
void *buffer, size_t size)
{
return gfs2_xattr_get(inode, GFS2_EATYPE_SYS, name, buffer, size);
}
static int gfs2_xattr_system_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
return gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, flags);
}
static int gfs2_xattr_security_get(struct inode *inode, const char *name,
void *buffer, size_t size)
{
return gfs2_xattr_get(inode, GFS2_EATYPE_SECURITY, name, buffer, size);
}
static int gfs2_xattr_security_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
return gfs2_xattr_set(inode, GFS2_EATYPE_SECURITY, name, value, size, flags);
}
static struct xattr_handler gfs2_xattr_user_handler = {
.prefix = XATTR_USER_PREFIX,
.get = gfs2_xattr_user_get,
.set = gfs2_xattr_user_set,
};
static struct xattr_handler gfs2_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.get = gfs2_xattr_security_get,
.set = gfs2_xattr_security_set,
};
static struct xattr_handler gfs2_xattr_system_handler = {
.prefix = XATTR_SYSTEM_PREFIX,
.get = gfs2_xattr_system_get,
.set = gfs2_xattr_system_set,
};
struct xattr_handler *gfs2_xattr_handlers[] = {
&gfs2_xattr_user_handler,
&gfs2_xattr_security_handler,
&gfs2_xattr_system_handler,
NULL,
};
......@@ -27,10 +27,6 @@ ALIGN(sizeof(struct gfs2_ea_header) + (ea)->ea_name_len + \
#define GFS2_EAREQ_SIZE_STUFFED(er) \
ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + (er)->er_data_len, 8)
#define GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er) \
ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + \
sizeof(__be64) * DIV_ROUND_UP((er)->er_data_len, (sdp)->sd_jbsize), 8)
#define GFS2_EA2NAME(ea) ((char *)((struct gfs2_ea_header *)(ea) + 1))
#define GFS2_EA2DATA(ea) (GFS2_EA2NAME(ea) + (ea)->ea_name_len)
......@@ -43,16 +39,12 @@ ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + \
#define GFS2_EA_BH2FIRST(bh) \
((struct gfs2_ea_header *)((bh)->b_data + sizeof(struct gfs2_meta_header)))
#define GFS2_ERF_MODE 0x80000000
struct gfs2_ea_request {
const char *er_name;
char *er_data;
unsigned int er_name_len;
unsigned int er_data_len;
unsigned int er_type; /* GFS2_EATYPE_... */
int er_flags;
mode_t er_mode;
};
struct gfs2_ea_location {
......@@ -61,40 +53,20 @@ struct gfs2_ea_location {
struct gfs2_ea_header *el_prev;
};
int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er);
int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er);
int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er);
int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er);
int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er);
int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er);
int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er);
int gfs2_ea_dealloc(struct gfs2_inode *ip);
extern int gfs2_xattr_get(struct inode *inode, int type, const char *name,
void *buffer, size_t size);
extern int gfs2_xattr_set(struct inode *inode, int type, const char *name,
const void *value, size_t size, int flags);
extern ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size);
extern int gfs2_ea_dealloc(struct gfs2_inode *ip);
/* Exported to acl.c */
int gfs2_ea_find(struct gfs2_inode *ip,
struct gfs2_ea_request *er,
extern int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name,
struct gfs2_ea_location *el);
int gfs2_ea_get_copy(struct gfs2_inode *ip,
struct gfs2_ea_location *el,
char *data);
int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el,
extern int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el,
char *data, size_t size);
extern int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el,
struct iattr *attr, char *data);
static inline unsigned int gfs2_ea_strlen(struct gfs2_ea_header *ea)
{
switch (ea->ea_type) {
case GFS2_EATYPE_USR:
return 5 + ea->ea_name_len + 1;
case GFS2_EATYPE_SYS:
return 7 + ea->ea_name_len + 1;
case GFS2_EATYPE_SECURITY:
return 9 + ea->ea_name_len + 1;
default:
return 0;
}
}
#endif /* __EATTR_DOT_H__ */
......@@ -333,6 +333,28 @@ struct gfs2_leaf {
/*
* Extended attribute header format
*
* This works in a similar way to dirents. There is a fixed size header
* followed by a variable length section made up of the name and the
* associated data. In the case of a "stuffed" entry, the value is
* inline directly after the name, the ea_num_ptrs entry will be
* zero in that case. For non-"stuffed" entries, there will be
* a set of pointers (aligned to 8 byte boundary) to the block(s)
* containing the value.
*
* The blocks containing the values and the blocks containing the
* extended attribute headers themselves all start with the common
* metadata header. Each inode, if it has extended attributes, will
* have either a single block containing the extended attribute headers
* or a single indirect block pointing to blocks containing the
* extended attribure headers.
*
* The maximim size of the data part of an extended attribute is 64k
* so the number of blocks required depends upon block size. Since the
* block size also determines the number of pointers in an indirect
* block, its a fairly complicated calculation to work out the maximum
* number of blocks that an inode may have relating to extended attributes.
*
*/
#define GFS2_EA_MAX_NAME_LEN 255
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment