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
This commit is contained in:
Коммит
33f1de6931
|
@ -0,0 +1,100 @@
|
|||
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.
|
||||
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
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 \
|
||||
|
|
106
fs/gfs2/acl.c
106
fs/gfs2/acl.c
|
@ -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 @@ out:
|
|||
|
||||
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)
|
||||
goto out;
|
||||
} else
|
||||
munge_mode(ip, mode);
|
||||
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;
|
||||
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,
|
||||
};
|
||||
|
||||
|
|
157
fs/gfs2/eaops.c
157
fs/gfs2/eaops.c
|
@ -1,157 +0,0 @@
|
|||
/*
|
||||
* 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,
|
||||
};
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* 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__ */
|
||||
|
|
@ -143,17 +143,14 @@ static struct dentry *gfs2_get_parent(struct dentry *child)
|
|||
}
|
||||
|
||||
static struct dentry *gfs2_get_dentry(struct super_block *sb,
|
||||
struct gfs2_inum_host *inum)
|
||||
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 @@ out_inode:
|
|||
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;
|
||||
|
||||
|
|
159
fs/gfs2/inode.c
159
fs/gfs2/inode.c
|
@ -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 @@ out:
|
|||
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,9 +862,8 @@ 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,
|
||||
inum.no_formal_ino, 0);
|
||||
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 @@ fail_rindex:
|
|||
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 @@ fail_qc_gh:
|
|||
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;
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_holder gh;
|
||||
int ret;
|
||||
|
||||
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));
|
||||
|
||||
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;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_holder gh;
|
||||
int ret;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_holder gh;
|
||||
int ret;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
/* 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 @@ restart:
|
|||
/* 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 @@ restart:
|
|||
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_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 @@ fail:
|
|||
|
||||
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,24 +38,30 @@ 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);
|
||||
|
||||
fs_err(sdp, "about to withdraw this file system\n");
|
||||
BUG_ON(sdp->sd_args.ar_debug);
|
||||
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);
|
||||
|
||||
kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE);
|
||||
kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE);
|
||||
|
||||
if (lm->lm_unmount) {
|
||||
fs_err(sdp, "telling LM to unmount\n");
|
||||
lm->lm_unmount(sdp);
|
||||
if (lm->lm_unmount) {
|
||||
fs_err(sdp, "telling LM to unmount\n");
|
||||
lm->lm_unmount(sdp);
|
||||
}
|
||||
fs_err(sdp, "withdrawn\n");
|
||||
dump_stack();
|
||||
}
|
||||
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,17 +99,24 @@ int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion,
|
|||
gfs2_tune_get(sdp, gt_complain_secs) * HZ))
|
||||
return -2;
|
||||
|
||||
printk(KERN_WARNING
|
||||
"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);
|
||||
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",
|
||||
sdp->sd_fsname, assertion,
|
||||
sdp->sd_fsname, function, file, line);
|
||||
|
||||
if (sdp->sd_args.ar_debug)
|
||||
BUG();
|
||||
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 @@ out:
|
|||
}
|
||||
|
||||
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 @@ out:
|
|||
}
|
||||
|
||||
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;
|
||||
else
|
||||
error = gfs2_ea_get_copy(ip, &el, er->er_data);
|
||||
}
|
||||
if (!error)
|
||||
if (size)
|
||||
error = gfs2_ea_get_copy(ip, &el, buffer, size);
|
||||
else
|
||||
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;
|
||||
|
||||
return ea_alloc_skeleton(ip, er, blks, ea_init_i, NULL);
|
||||
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);
|
||||
}
|
||||
|
||||
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 @@ out:
|
|||
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;
|
||||
|
||||
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
|
||||
if (value == NULL)
|
||||
return gfs2_xattr_remove(inode, type, name);
|
||||
|
||||
if (ea_check_size(sdp, namel, size))
|
||||
return -ERANGE;
|
||||
|
||||
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 @@ out_alloc:
|
|||
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,
|
||||
};
|
||||
|
|
@ -19,7 +19,7 @@ struct iattr;
|
|||
#define GFS2_EA_SIZE(ea) \
|
||||
ALIGN(sizeof(struct gfs2_ea_header) + (ea)->ea_name_len + \
|
||||
((GFS2_EA_IS_STUFFED(ea)) ? GFS2_EA_DATA_LEN(ea) : \
|
||||
(sizeof(__be64) * (ea)->ea_num_ptrs)), 8)
|
||||
(sizeof(__be64) * (ea)->ea_num_ptrs)), 8)
|
||||
|
||||
#define GFS2_EA_IS_STUFFED(ea) (!(ea)->ea_num_ptrs)
|
||||
#define GFS2_EA_IS_LAST(ea) ((ea)->ea_flags & GFS2_EAFLAG_LAST)
|
||||
|
@ -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,
|
||||
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,
|
||||
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;
|
||||
}
|
||||
}
|
||||
extern int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name,
|
||||
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);
|
||||
|
||||
#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
|
||||
|
|
Загрузка…
Ссылка в новой задаче