Commit 1ebb275a authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw

* git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw: (31 commits)
  GFS2: Fix glock refcount issues
  writeback: remove unused nonblocking and congestion checks (gfs2)
  GFS2: drop rindex glock to refresh rindex list
  GFS2: Tag all metadata with jid
  GFS2: Locking order fix in gfs2_check_blk_state
  GFS2: Remove dirent_first() function
  GFS2: Display nobarrier option in /proc/mounts
  GFS2: add barrier/nobarrier mount options
  GFS2: remove division from new statfs code
  GFS2: Improve statfs and quota usability
  GFS2: Use dquot_send_warning()
  VFS: Export dquot_send_warning
  GFS2: Add set_xquota support
  GFS2: Add get_xquota support
  GFS2: Clean up gfs2_adjust_quota() and do_glock()
  GFS2: Remove constant argument from qd_get()
  GFS2: Remove constant argument from qdsb_get()
  GFS2: Add proper error reporting to quota sync via sysfs
  GFS2: Add get_xstate quota function
  GFS2: Remove obsolete code in quota.c
  ...
parents 83fdbfbf 26bb7505
......@@ -8,6 +8,8 @@ config GFS2_FS
select FS_POSIX_ACL
select CRC32
select SLOW_WORK
select QUOTA
select QUOTACTL
help
A cluster filesystem.
......
......@@ -12,6 +12,7 @@
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/xattr.h>
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
#include <linux/gfs2_ondisk.h>
......@@ -26,108 +27,44 @@
#include "trans.h"
#include "util.h"
#define ACL_ACCESS 1
#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)
static const char *gfs2_acl_name(int type)
{
struct posix_acl *acl;
int error;
error = gfs2_acl_validate_remove(ip, access);
if (error)
return error;
if (!er->er_data)
return -EINVAL;
acl = posix_acl_from_xattr(er->er_data, er->er_data_len);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (!acl) {
*remove = 1;
return 0;
}
error = posix_acl_valid(acl);
if (error)
goto out;
if (access) {
error = posix_acl_equiv_mode(acl, mode);
if (!error)
*remove = 1;
else if (error > 0)
error = 0;
switch (type) {
case ACL_TYPE_ACCESS:
return GFS2_POSIX_ACL_ACCESS;
case ACL_TYPE_DEFAULT:
return GFS2_POSIX_ACL_DEFAULT;
}
out:
posix_acl_release(acl);
return error;
}
int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access)
{
if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl)
return -EOPNOTSUPP;
if (!is_owner_or_cap(&ip->i_inode))
return -EPERM;
if (S_ISLNK(ip->i_inode.i_mode))
return -EOPNOTSUPP;
if (!access && !S_ISDIR(ip->i_inode.i_mode))
return -EACCES;
return 0;
return NULL;
}
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)
static struct posix_acl *gfs2_acl_get(struct gfs2_inode *ip, int type)
{
struct posix_acl *acl;
const char *name;
char *data;
unsigned int len;
int error;
el->el_bh = NULL;
int len;
if (!ip->i_eattr)
return 0;
error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, name, el);
if (error)
return error;
if (!el->el_ea)
return 0;
if (!GFS2_EA_DATA_LEN(el->el_ea))
goto out;
return NULL;
len = GFS2_EA_DATA_LEN(el->el_ea);
data = kmalloc(len, GFP_NOFS);
error = -ENOMEM;
if (!data)
goto out;
acl = get_cached_acl(&ip->i_inode, type);
if (acl != ACL_NOT_CACHED)
return acl;
error = gfs2_ea_get_copy(ip, el, data, len);
if (error < 0)
goto out_kfree;
error = 0;
name = gfs2_acl_name(type);
if (name == NULL)
return ERR_PTR(-EINVAL);
if (acl) {
*acl = posix_acl_from_xattr(data, len);
if (IS_ERR(*acl))
error = PTR_ERR(*acl);
}
len = gfs2_xattr_acl_get(ip, name, &data);
if (len < 0)
return ERR_PTR(len);
if (len == 0)
return NULL;
out_kfree:
if (error || !datap) {
kfree(data);
} else {
*datap = data;
*lenp = len;
}
out:
return error;
acl = posix_acl_from_xattr(data, len);
kfree(data);
return acl;
}
/**
......@@ -140,14 +77,12 @@ out:
int gfs2_check_acl(struct inode *inode, int mask)
{
struct gfs2_ea_location el;
struct posix_acl *acl = NULL;
struct posix_acl *acl;
int error;
error = acl_get(GFS2_I(inode), GFS2_POSIX_ACL_ACCESS, &acl, &el, NULL, NULL);
brelse(el.el_bh);
if (error)
return error;
acl = gfs2_acl_get(GFS2_I(inode), ACL_TYPE_ACCESS);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl) {
error = posix_acl_permission(inode, acl, mask);
......@@ -158,57 +93,75 @@ int gfs2_check_acl(struct inode *inode, int mask)
return -EAGAIN;
}
static int munge_mode(struct gfs2_inode *ip, mode_t mode)
static int gfs2_set_mode(struct inode *inode, mode_t mode)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct buffer_head *dibh;
int error;
int error = 0;
error = gfs2_trans_begin(sdp, RES_DINODE, 0);
if (error)
return error;
if (mode != inode->i_mode) {
struct iattr iattr;
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
gfs2_assert_withdraw(sdp,
(ip->i_inode.i_mode & S_IFMT) == (mode & S_IFMT));
ip->i_inode.i_mode = mode;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
iattr.ia_valid = ATTR_MODE;
iattr.ia_mode = mode;
error = gfs2_setattr_simple(GFS2_I(inode), &iattr);
}
gfs2_trans_end(sdp);
return error;
}
static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl)
{
int error;
int len;
char *data;
const char *name = gfs2_acl_name(type);
return 0;
BUG_ON(name == NULL);
len = posix_acl_to_xattr(acl, NULL, 0);
if (len == 0)
return 0;
data = kmalloc(len, GFP_NOFS);
if (data == NULL)
return -ENOMEM;
error = posix_acl_to_xattr(acl, data, len);
if (error < 0)
goto out;
error = gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, data, len, 0);
if (!error)
set_cached_acl(inode, type, acl);
out:
kfree(data);
return error;
}
int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode)
{
struct gfs2_ea_location el;
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct posix_acl *acl = NULL, *clone;
mode_t mode = ip->i_inode.i_mode;
char *data = NULL;
unsigned int len;
int error;
struct posix_acl *acl, *clone;
mode_t mode = inode->i_mode;
int error = 0;
if (!sdp->sd_args.ar_posix_acl)
return 0;
if (S_ISLNK(ip->i_inode.i_mode))
if (S_ISLNK(inode->i_mode))
return 0;
error = acl_get(dip, GFS2_POSIX_ACL_DEFAULT, &acl, &el, &data, &len);
brelse(el.el_bh);
if (error)
return error;
acl = gfs2_acl_get(dip, ACL_TYPE_DEFAULT);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (!acl) {
mode &= ~current_umask();
if (mode != ip->i_inode.i_mode)
error = munge_mode(ip, mode);
if (mode != inode->i_mode)
error = gfs2_set_mode(inode, mode);
return error;
}
if (S_ISDIR(inode->i_mode)) {
error = gfs2_acl_set(inode, ACL_TYPE_DEFAULT, acl);
if (error)
goto out;
}
clone = posix_acl_clone(acl, GFP_NOFS);
error = -ENOMEM;
if (!clone)
......@@ -216,43 +169,32 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
posix_acl_release(acl);
acl = clone;
if (S_ISDIR(ip->i_inode.i_mode)) {
error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS,
GFS2_POSIX_ACL_DEFAULT, data, len, 0);
if (error)
goto out;
}
error = posix_acl_create_masq(acl, &mode);
if (error < 0)
goto out;
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);
error = gfs2_acl_set(inode, ACL_TYPE_ACCESS, acl);
if (error)
goto out;
munge:
error = munge_mode(ip, mode);
error = gfs2_set_mode(inode, mode);
out:
posix_acl_release(acl);
kfree(data);
return error;
}
int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
{
struct posix_acl *acl = NULL, *clone;
struct gfs2_ea_location el;
struct posix_acl *acl, *clone;
char *data;
unsigned int len;
int error;
error = acl_get(ip, GFS2_POSIX_ACL_ACCESS, &acl, &el, &data, &len);
if (error)
goto out_brelse;
acl = gfs2_acl_get(ip, ACL_TYPE_ACCESS);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (!acl)
return gfs2_setattr_simple(ip, attr);
......@@ -265,15 +207,134 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
error = posix_acl_chmod_masq(acl, attr->ia_mode);
if (!error) {
len = posix_acl_to_xattr(acl, NULL, 0);
data = kmalloc(len, GFP_NOFS);
error = -ENOMEM;
if (data == NULL)
goto out;
posix_acl_to_xattr(acl, data, len);
error = gfs2_ea_acl_chmod(ip, &el, attr, data);
error = gfs2_xattr_acl_chmod(ip, attr, data);
kfree(data);
set_cached_acl(&ip->i_inode, ACL_TYPE_ACCESS, acl);
}
out:
posix_acl_release(acl);
kfree(data);
out_brelse:
brelse(el.el_bh);
return error;
}
static int gfs2_acl_type(const char *name)
{
if (strcmp(name, GFS2_POSIX_ACL_ACCESS) == 0)
return ACL_TYPE_ACCESS;
if (strcmp(name, GFS2_POSIX_ACL_DEFAULT) == 0)
return ACL_TYPE_DEFAULT;
return -EINVAL;
}
static int gfs2_xattr_system_get(struct inode *inode, const char *name,
void *buffer, size_t size)
{
struct posix_acl *acl;
int type;
int error;
type = gfs2_acl_type(name);
if (type < 0)
return type;
acl = gfs2_acl_get(GFS2_I(inode), type);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl == NULL)
return -ENODATA;
error = posix_acl_to_xattr(acl, buffer, size);
posix_acl_release(acl);
return error;
}
static int gfs2_xattr_system_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct posix_acl *acl = NULL;
int error = 0, type;
if (!sdp->sd_args.ar_posix_acl)
return -EOPNOTSUPP;
type = gfs2_acl_type(name);
if (type < 0)
return type;
if (flags & XATTR_CREATE)
return -EINVAL;
if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
return value ? -EACCES : 0;
if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER))
return -EPERM;
if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
if (!value)
goto set_acl;
acl = posix_acl_from_xattr(value, size);
if (!acl) {
/*
* acl_set_file(3) may request that we set default ACLs with
* zero length -- defend (gracefully) against that here.
*/
goto out;
}
if (IS_ERR(acl)) {
error = PTR_ERR(acl);
goto out;
}
error = posix_acl_valid(acl);
if (error)
goto out_release;
error = -EINVAL;
if (acl->a_count > GFS2_ACL_MAX_ENTRIES)
goto out_release;
if (type == ACL_TYPE_ACCESS) {
mode_t mode = inode->i_mode;
error = posix_acl_equiv_mode(acl, &mode);
if (error <= 0) {
posix_acl_release(acl);
acl = NULL;
if (error < 0)
return error;
}
error = gfs2_set_mode(inode, mode);
if (error)
goto out_release;
}
set_acl:
error = gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, 0);
if (!error) {
if (acl)
set_cached_acl(inode, type, acl);
else
forget_cached_acl(inode, type);
}
out_release:
posix_acl_release(acl);
out:
return error;
}
struct xattr_handler gfs2_xattr_system_handler = {
.prefix = XATTR_SYSTEM_PREFIX,
.get = gfs2_xattr_system_get,
.set = gfs2_xattr_system_set,
};
......@@ -13,26 +13,12 @@
#include "incore.h"
#define GFS2_POSIX_ACL_ACCESS "posix_acl_access"
#define GFS2_POSIX_ACL_ACCESS_LEN 16
#define GFS2_POSIX_ACL_DEFAULT "posix_acl_default"
#define GFS2_POSIX_ACL_DEFAULT_LEN 17
#define GFS2_ACL_MAX_ENTRIES 25
#define GFS2_ACL_IS_ACCESS(name, len) \
((len) == GFS2_POSIX_ACL_ACCESS_LEN && \
!memcmp(GFS2_POSIX_ACL_ACCESS, (name), (len)))
#define GFS2_ACL_IS_DEFAULT(name, len) \
((len) == GFS2_POSIX_ACL_DEFAULT_LEN && \
!memcmp(GFS2_POSIX_ACL_DEFAULT, (name), (len)))
struct gfs2_ea_request;
int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
struct gfs2_ea_request *er,
int *remove, mode_t *mode);
int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access);
int gfs2_check_acl(struct inode *inode, int mask);
int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip);
int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr);
extern int gfs2_check_acl(struct inode *inode, int mask);
extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode);
extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr);
extern struct xattr_handler gfs2_xattr_system_handler;
#endif /* __ACL_DOT_H__ */
......@@ -269,7 +269,6 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping,
pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
unsigned offset = i_size & (PAGE_CACHE_SIZE-1);
unsigned nrblocks = nr_pages * (PAGE_CACHE_SIZE/inode->i_sb->s_blocksize);
struct backing_dev_info *bdi = mapping->backing_dev_info;
int i;
int ret;
......@@ -313,11 +312,6 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping,
if (ret || (--(wbc->nr_to_write) <= 0))
ret = 1;
if (wbc->nonblocking && bdi_write_congested(bdi)) {
wbc->encountered_congestion = 1;
ret = 1;
}
}
gfs2_trans_end(sdp);
return ret;
......@@ -338,7 +332,6 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping,
static int gfs2_write_cache_jdata(struct address_space *mapping,
struct writeback_control *wbc)
{
struct backing_dev_info *bdi = mapping->backing_dev_info;
int ret = 0;
int done = 0;
struct pagevec pvec;
......@@ -348,11 +341,6 @@ static int gfs2_write_cache_jdata(struct address_space *mapping,
int scanned = 0;
int range_whole = 0;
if (wbc->nonblocking && bdi_write_congested(bdi)) {
wbc->encountered_congestion = 1;
return 0;
}
pagevec_init(&pvec, 0);
if (wbc->range_cyclic) {
index = mapping->writeback_index; /* Start from prev offset */
......@@ -819,8 +807,10 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
mark_inode_dirty(inode);
}
if (inode == sdp->sd_rindex)
if (inode == sdp->sd_rindex) {
adjust_fs_space(inode);
ip->i_gh.gh_flags |= GL_NOCACHE;
}
brelse(dibh);
gfs2_trans_end(sdp);
......@@ -889,8 +879,10 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
mark_inode_dirty(inode);
}
if (inode == sdp->sd_rindex)
if (inode == sdp->sd_rindex) {
adjust_fs_space(inode);
ip->i_gh.gh_flags |= GL_NOCACHE;
}
brelse(dibh);
gfs2_trans_end(sdp);
......
......@@ -525,38 +525,6 @@ consist_inode:
return ERR_PTR(-EIO);
}
/**
* dirent_first - Return the first dirent
* @dip: the directory
* @bh: The buffer
* @dent: Pointer to list of dirents
*
* return first dirent whether bh points to leaf or stuffed dinode
*
* Returns: IS_LEAF, IS_DINODE, or -errno
*/
static int dirent_first(struct gfs2_inode *dip, struct buffer_head *bh,
struct gfs2_dirent **dent)
{
struct gfs2_meta_header *h = (struct gfs2_meta_header *)bh->b_data;
if (be32_to_cpu(h->mh_type) == GFS2_METATYPE_LF) {
if (gfs2_meta_check(GFS2_SB(&dip->i_inode), bh))
return -EIO;
*dent = (struct gfs2_dirent *)(bh->b_data +
sizeof(struct gfs2_leaf));
return IS_LEAF;
} else {
if (gfs2_metatype_check(GFS2_SB(&dip->i_inode), bh, GFS2_METATYPE_DI))
return -EIO;
*dent = (struct gfs2_dirent *)(bh->b_data +
sizeof(struct gfs2_dinode));
return IS_DINODE;
}
}
static int dirent_check_reclen(struct gfs2_inode *dip,
const struct gfs2_dirent *d, const void *end_p)
{
......@@ -1006,7 +974,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
divider = (start + half_len) << (32 - dip->i_depth);
/* Copy the entries */
dirent_first(dip, obh, &dent);
dent = (struct gfs2_dirent *)(obh->b_data + sizeof(struct gfs2_leaf));
do {
next = dent;
......
......@@ -241,15 +241,14 @@ int gfs2_glock_put(struct gfs2_glock *gl)
int rv = 0;
write_lock(gl_lock_addr(gl->gl_hash));
if (atomic_dec_and_test(&gl->gl_ref)) {
if (atomic_dec_and_lock(&gl->gl_ref, &lru_lock)) {
hlist_del(&gl->gl_list);
write_unlock(gl_lock_addr(gl->gl_hash));
spin_lock(&lru_lock);
if (!list_empty(&gl->gl_lru)) {
list_del_init(&gl->gl_lru);
atomic_dec(&lru_count);
}
spin_unlock(&lru_lock);
write_unlock(gl_lock_addr(gl->gl_hash));
GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders));