Commit 2182c815 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gfs2-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw

Pull GFS2 updates from Steven Whitehouse:
 "The main topics this time are allocation, in the form of Bob's
  improvements when searching resource groups and several updates to
  quotas which should increase scalability.  The quota changes follow on
  from those in the last merge window, and there will likely be further
  work to come in this area in due course.

  There are also a few patches which help to improve efficiency of
  adding entries into directories, and clean up some of that code.

  One on-disk change is included this time, which is to write some
  additional information which should be useful to fsck and also
  potentially for debugging.

  Other than that, its just a few small random bug fixes and clean ups"

* tag 'gfs2-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw: (24 commits)
  GFS2: revert "GFS2: d_splice_alias() can't return error"
  GFS2: Small cleanup
  GFS2: Don't use ENOBUFS when ENOMEM is the correct error code
  GFS2: Fix kbuild test robot reported warning
  GFS2: Move quota bitmap operations under their own lock
  GFS2: Clean up quota slot allocation
  GFS2: Only run logd and quota when mounted read/write
  GFS2: Use RCU/hlist_bl based hash for quotas
  GFS2: No need to invalidate pages for a dio read
  GFS2: Add initialization for address space in super block
  GFS2: Add hints to directory leaf blocks
  GFS2: For exhash conversion, only one block is needed
  GFS2: Increase i_writecount during gfs2_setattr_chown
  GFS2: Remember directory insert point
  GFS2: Consolidate transaction blocks calculation for dir add
  GFS2: Add directory addition info structure
  GFS2: Use only a single address space for rgrps
  GFS2: Use range based functions for rgrp sync/invalidation
  GFS2: Remove test which is always true
  GFS2: Remove gfs2_quota_change_host structure
  ...
parents 03d11a0e d57b9c9a
...@@ -1032,8 +1032,9 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, ...@@ -1032,8 +1032,9 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
unmap_shared_mapping_range(ip->i_inode.i_mapping, offset, len); unmap_shared_mapping_range(ip->i_inode.i_mapping, offset, len);
rv = filemap_write_and_wait_range(mapping, lstart, end); rv = filemap_write_and_wait_range(mapping, lstart, end);
if (rv) if (rv)
return rv; goto out;
truncate_inode_pages_range(mapping, lstart, end); if (rw == WRITE)
truncate_inode_pages_range(mapping, lstart, end);
} }
rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
...@@ -1080,30 +1081,22 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) ...@@ -1080,30 +1081,22 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
bh = bh->b_this_page; bh = bh->b_this_page;
} while(bh != head); } while(bh != head);
spin_unlock(&sdp->sd_ail_lock); spin_unlock(&sdp->sd_ail_lock);
gfs2_log_unlock(sdp);
head = bh = page_buffers(page); head = bh = page_buffers(page);
do { do {
gfs2_log_lock(sdp);
bd = bh->b_private; bd = bh->b_private;
if (bd) { if (bd) {
gfs2_assert_warn(sdp, bd->bd_bh == bh); gfs2_assert_warn(sdp, bd->bd_bh == bh);
if (!list_empty(&bd->bd_list)) { if (!list_empty(&bd->bd_list))
if (!buffer_pinned(bh)) list_del_init(&bd->bd_list);
list_del_init(&bd->bd_list); bd->bd_bh = NULL;
else
bd = NULL;
}
if (bd)
bd->bd_bh = NULL;
bh->b_private = NULL; bh->b_private = NULL;
}
gfs2_log_unlock(sdp);
if (bd)
kmem_cache_free(gfs2_bufdata_cachep, bd); kmem_cache_free(gfs2_bufdata_cachep, bd);
}
bh = bh->b_this_page; bh = bh->b_this_page;
} while (bh != head); } while (bh != head);
gfs2_log_unlock(sdp);
return try_to_free_buffers(page); return try_to_free_buffers(page);
......
...@@ -834,6 +834,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, ...@@ -834,6 +834,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh,
struct gfs2_leaf *leaf; struct gfs2_leaf *leaf;
struct gfs2_dirent *dent; struct gfs2_dirent *dent;
struct qstr name = { .name = "" }; struct qstr name = { .name = "" };
struct timespec tv = CURRENT_TIME;
error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL); error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL);
if (error) if (error)
...@@ -850,7 +851,11 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, ...@@ -850,7 +851,11 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh,
leaf->lf_entries = 0; leaf->lf_entries = 0;
leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE); leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE);
leaf->lf_next = 0; leaf->lf_next = 0;
memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved)); leaf->lf_inode = cpu_to_be64(ip->i_no_addr);
leaf->lf_dist = cpu_to_be32(1);
leaf->lf_nsec = cpu_to_be32(tv.tv_nsec);
leaf->lf_sec = cpu_to_be64(tv.tv_sec);
memset(leaf->lf_reserved2, 0, sizeof(leaf->lf_reserved2));
dent = (struct gfs2_dirent *)(leaf+1); dent = (struct gfs2_dirent *)(leaf+1);
gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent); gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent);
*pbh = bh; *pbh = bh;
...@@ -1612,11 +1617,31 @@ int gfs2_dir_check(struct inode *dir, const struct qstr *name, ...@@ -1612,11 +1617,31 @@ int gfs2_dir_check(struct inode *dir, const struct qstr *name,
return ret; return ret;
} }
/**
* dir_new_leaf - Add a new leaf onto hash chain
* @inode: The directory
* @name: The name we are adding
*
* This adds a new dir leaf onto an existing leaf when there is not
* enough space to add a new dir entry. This is a last resort after
* we've expanded the hash table to max size and also split existing
* leaf blocks, so it will only occur for very large directories.
*
* The dist parameter is set to 1 for leaf blocks directly attached
* to the hash table, 2 for one layer of indirection, 3 for two layers
* etc. We are thus able to tell the difference between an old leaf
* with dist set to zero (i.e. "don't know") and a new one where we
* set this information for debug/fsck purposes.
*
* Returns: 0 on success, or -ve on error
*/
static int dir_new_leaf(struct inode *inode, const struct qstr *name) static int dir_new_leaf(struct inode *inode, const struct qstr *name)
{ {
struct buffer_head *bh, *obh; struct buffer_head *bh, *obh;
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_leaf *leaf, *oleaf; struct gfs2_leaf *leaf, *oleaf;
u32 dist = 1;
int error; int error;
u32 index; u32 index;
u64 bn; u64 bn;
...@@ -1626,6 +1651,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) ...@@ -1626,6 +1651,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name)
if (error) if (error)
return error; return error;
do { do {
dist++;
oleaf = (struct gfs2_leaf *)obh->b_data; oleaf = (struct gfs2_leaf *)obh->b_data;
bn = be64_to_cpu(oleaf->lf_next); bn = be64_to_cpu(oleaf->lf_next);
if (!bn) if (!bn)
...@@ -1643,6 +1669,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) ...@@ -1643,6 +1669,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name)
brelse(obh); brelse(obh);
return -ENOSPC; return -ENOSPC;
} }
leaf->lf_dist = cpu_to_be32(dist);
oleaf->lf_next = cpu_to_be64(bh->b_blocknr); oleaf->lf_next = cpu_to_be64(bh->b_blocknr);
brelse(bh); brelse(bh);
brelse(obh); brelse(obh);
...@@ -1659,39 +1686,53 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) ...@@ -1659,39 +1686,53 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name)
/** /**
* gfs2_dir_add - Add new filename into directory * gfs2_dir_add - Add new filename into directory
* @dip: The GFS2 inode * @inode: The directory inode
* @filename: The new name * @name: The new name
* @inode: The inode number of the entry * @nip: The GFS2 inode to be linked in to the directory
* @type: The type of the entry * @da: The directory addition info
*
* If the call to gfs2_diradd_alloc_required resulted in there being
* no need to allocate any new directory blocks, then it will contain
* a pointer to the directory entry and the bh in which it resides. We
* can use that without having to repeat the search. If there was no
* free space, then we must now create more space.
* *
* Returns: 0 on success, error code on failure * Returns: 0 on success, error code on failure
*/ */
int gfs2_dir_add(struct inode *inode, const struct qstr *name, int gfs2_dir_add(struct inode *inode, const struct qstr *name,
const struct gfs2_inode *nip) const struct gfs2_inode *nip, struct gfs2_diradd *da)
{ {
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct buffer_head *bh; struct buffer_head *bh = da->bh;
struct gfs2_dirent *dent; struct gfs2_dirent *dent = da->dent;
struct timespec tv;
struct gfs2_leaf *leaf; struct gfs2_leaf *leaf;
int error; int error;
while(1) { while(1) {
dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space, if (da->bh == NULL) {
&bh); dent = gfs2_dirent_search(inode, name,
gfs2_dirent_find_space, &bh);
}
if (dent) { if (dent) {
if (IS_ERR(dent)) if (IS_ERR(dent))
return PTR_ERR(dent); return PTR_ERR(dent);
dent = gfs2_init_dirent(inode, dent, name, bh); dent = gfs2_init_dirent(inode, dent, name, bh);
gfs2_inum_out(nip, dent); gfs2_inum_out(nip, dent);
dent->de_type = cpu_to_be16(IF2DT(nip->i_inode.i_mode)); dent->de_type = cpu_to_be16(IF2DT(nip->i_inode.i_mode));
tv = CURRENT_TIME;
if (ip->i_diskflags & GFS2_DIF_EXHASH) { if (ip->i_diskflags & GFS2_DIF_EXHASH) {
leaf = (struct gfs2_leaf *)bh->b_data; leaf = (struct gfs2_leaf *)bh->b_data;
be16_add_cpu(&leaf->lf_entries, 1); be16_add_cpu(&leaf->lf_entries, 1);
leaf->lf_nsec = cpu_to_be32(tv.tv_nsec);
leaf->lf_sec = cpu_to_be64(tv.tv_sec);
} }
da->dent = NULL;
da->bh = NULL;
brelse(bh); brelse(bh);
ip->i_entries++; ip->i_entries++;
ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; ip->i_inode.i_mtime = ip->i_inode.i_ctime = tv;
if (S_ISDIR(nip->i_inode.i_mode)) if (S_ISDIR(nip->i_inode.i_mode))
inc_nlink(&ip->i_inode); inc_nlink(&ip->i_inode);
mark_inode_dirty(inode); mark_inode_dirty(inode);
...@@ -1742,6 +1783,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry) ...@@ -1742,6 +1783,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry)
const struct qstr *name = &dentry->d_name; const struct qstr *name = &dentry->d_name;
struct gfs2_dirent *dent, *prev = NULL; struct gfs2_dirent *dent, *prev = NULL;
struct buffer_head *bh; struct buffer_head *bh;
struct timespec tv = CURRENT_TIME;
/* Returns _either_ the entry (if its first in block) or the /* Returns _either_ the entry (if its first in block) or the
previous entry otherwise */ previous entry otherwise */
...@@ -1767,13 +1809,15 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry) ...@@ -1767,13 +1809,15 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry)
if (!entries) if (!entries)
gfs2_consist_inode(dip); gfs2_consist_inode(dip);
leaf->lf_entries = cpu_to_be16(--entries); leaf->lf_entries = cpu_to_be16(--entries);
leaf->lf_nsec = cpu_to_be32(tv.tv_nsec);
leaf->lf_sec = cpu_to_be64(tv.tv_sec);
} }
brelse(bh); brelse(bh);
if (!dip->i_entries) if (!dip->i_entries)
gfs2_consist_inode(dip); gfs2_consist_inode(dip);
dip->i_entries--; dip->i_entries--;
dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME; dip->i_inode.i_mtime = dip->i_inode.i_ctime = tv;
if (S_ISDIR(dentry->d_inode->i_mode)) if (S_ISDIR(dentry->d_inode->i_mode))
drop_nlink(&dip->i_inode); drop_nlink(&dip->i_inode);
mark_inode_dirty(&dip->i_inode); mark_inode_dirty(&dip->i_inode);
...@@ -2017,22 +2061,36 @@ int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip) ...@@ -2017,22 +2061,36 @@ int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip)
* gfs2_diradd_alloc_required - find if adding entry will require an allocation * gfs2_diradd_alloc_required - find if adding entry will require an allocation
* @ip: the file being written to * @ip: the file being written to
* @filname: the filename that's going to be added * @filname: the filename that's going to be added
* @da: The structure to return dir alloc info
* *
* Returns: 1 if alloc required, 0 if not, -ve on error * Returns: 0 if ok, -ve on error
*/ */
int gfs2_diradd_alloc_required(struct inode *inode, const struct qstr *name) int gfs2_diradd_alloc_required(struct inode *inode, const struct qstr *name,
struct gfs2_diradd *da)
{ {
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
const unsigned int extra = sizeof(struct gfs2_dinode) - sizeof(struct gfs2_leaf);
struct gfs2_dirent *dent; struct gfs2_dirent *dent;
struct buffer_head *bh; struct buffer_head *bh;
da->nr_blocks = 0;
da->bh = NULL;
da->dent = NULL;
dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space, &bh); dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space, &bh);
if (!dent) { if (!dent) {
return 1; da->nr_blocks = sdp->sd_max_dirres;
if (!(ip->i_diskflags & GFS2_DIF_EXHASH) &&
(GFS2_DIRENT_SIZE(name->len) < extra))
da->nr_blocks = 1;
return 0;
} }
if (IS_ERR(dent)) if (IS_ERR(dent))
return PTR_ERR(dent); return PTR_ERR(dent);
brelse(bh); da->bh = bh;
da->dent = dent;
return 0; return 0;
} }
...@@ -16,6 +16,14 @@ ...@@ -16,6 +16,14 @@
struct inode; struct inode;
struct gfs2_inode; struct gfs2_inode;
struct gfs2_inum; struct gfs2_inum;
struct buffer_head;
struct gfs2_dirent;
struct gfs2_diradd {
unsigned nr_blocks;
struct gfs2_dirent *dent;
struct buffer_head *bh;
};
extern struct inode *gfs2_dir_search(struct inode *dir, extern struct inode *gfs2_dir_search(struct inode *dir,
const struct qstr *filename, const struct qstr *filename,
...@@ -23,7 +31,13 @@ extern struct inode *gfs2_dir_search(struct inode *dir, ...@@ -23,7 +31,13 @@ extern struct inode *gfs2_dir_search(struct inode *dir,
extern int gfs2_dir_check(struct inode *dir, const struct qstr *filename, extern int gfs2_dir_check(struct inode *dir, const struct qstr *filename,
const struct gfs2_inode *ip); const struct gfs2_inode *ip);
extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename, extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
const struct gfs2_inode *ip); const struct gfs2_inode *ip, struct gfs2_diradd *da);
static inline void gfs2_dir_no_add(struct gfs2_diradd *da)
{
if (da->bh)
brelse(da->bh);
da->bh = NULL;
}
extern int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry); extern int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry);
extern int gfs2_dir_read(struct inode *inode, struct dir_context *ctx, extern int gfs2_dir_read(struct inode *inode, struct dir_context *ctx,
struct file_ra_state *f_ra); struct file_ra_state *f_ra);
...@@ -33,7 +47,8 @@ extern int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, ...@@ -33,7 +47,8 @@ extern int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
extern int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip); extern int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip);
extern int gfs2_diradd_alloc_required(struct inode *dir, extern int gfs2_diradd_alloc_required(struct inode *dir,
const struct qstr *filename); const struct qstr *filename,
struct gfs2_diradd *da);
extern int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block, extern int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block,
struct buffer_head **bhp); struct buffer_head **bhp);
extern void gfs2_dir_hash_inval(struct gfs2_inode *ip); extern void gfs2_dir_hash_inval(struct gfs2_inode *ip);
......
...@@ -1552,13 +1552,11 @@ void gfs2_glock_thaw(struct gfs2_sbd *sdp) ...@@ -1552,13 +1552,11 @@ void gfs2_glock_thaw(struct gfs2_sbd *sdp)
glock_hash_walk(thaw_glock, sdp); glock_hash_walk(thaw_glock, sdp);
} }
static int dump_glock(struct seq_file *seq, struct gfs2_glock *gl) static void dump_glock(struct seq_file *seq, struct gfs2_glock *gl)
{ {
int ret;
spin_lock(&gl->gl_spin); spin_lock(&gl->gl_spin);
ret = gfs2_dump_glock(seq, gl); gfs2_dump_glock(seq, gl);
spin_unlock(&gl->gl_spin); spin_unlock(&gl->gl_spin);
return ret;
} }
static void dump_glock_func(struct gfs2_glock *gl) static void dump_glock_func(struct gfs2_glock *gl)
...@@ -1647,10 +1645,9 @@ static const char *hflags2str(char *buf, unsigned flags, unsigned long iflags) ...@@ -1647,10 +1645,9 @@ static const char *hflags2str(char *buf, unsigned flags, unsigned long iflags)
* @seq: the seq_file struct * @seq: the seq_file struct
* @gh: the glock holder * @gh: the glock holder
* *
* Returns: 0 on success, -ENOBUFS when we run out of space
*/ */
static int dump_holder(struct seq_file *seq, const struct gfs2_holder *gh) static void dump_holder(struct seq_file *seq, const struct gfs2_holder *gh)
{ {
struct task_struct *gh_owner = NULL; struct task_struct *gh_owner = NULL;
char flags_buf[32]; char flags_buf[32];
...@@ -1666,7 +1663,6 @@ static int dump_holder(struct seq_file *seq, const struct gfs2_holder *gh) ...@@ -1666,7 +1663,6 @@ static int dump_holder(struct seq_file *seq, const struct gfs2_holder *gh)
gh_owner ? gh_owner->comm : "(ended)", gh_owner ? gh_owner->comm : "(ended)",
(void *)gh->gh_ip); (void *)gh->gh_ip);
rcu_read_unlock(); rcu_read_unlock();
return 0;
} }
static const char *gflags2str(char *buf, const struct gfs2_glock *gl) static const char *gflags2str(char *buf, const struct gfs2_glock *gl)
...@@ -1721,16 +1717,14 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl) ...@@ -1721,16 +1717,14 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl)
* example. The field's are n = number (id of the object), f = flags, * example. The field's are n = number (id of the object), f = flags,
* t = type, s = state, r = refcount, e = error, p = pid. * t = type, s = state, r = refcount, e = error, p = pid.
* *
* Returns: 0 on success, -ENOBUFS when we run out of space
*/ */
int gfs2_dump_glock(struct seq_file *seq, const struct gfs2_glock *gl) void gfs2_dump_glock(struct seq_file *seq, const struct gfs2_glock *gl)
{ {
const struct gfs2_glock_operations *glops = gl->gl_ops; const struct gfs2_glock_operations *glops = gl->gl_ops;
unsigned long long dtime; unsigned long long dtime;
const struct gfs2_holder *gh; const struct gfs2_holder *gh;
char gflags_buf[32]; char gflags_buf[32];
int error = 0;
dtime = jiffies - gl->gl_demote_time; dtime = jiffies - gl->gl_demote_time;
dtime *= 1000000/HZ; /* demote time in uSec */ dtime *= 1000000/HZ; /* demote time in uSec */
...@@ -1747,15 +1741,11 @@ int gfs2_dump_glock(struct seq_file *seq, const struct gfs2_glock *gl) ...@@ -1747,15 +1741,11 @@ int gfs2_dump_glock(struct seq_file *seq, const struct gfs2_glock *gl)
atomic_read(&gl->gl_revokes), atomic_read(&gl->gl_revokes),
(int)gl->gl_lockref.count, gl->gl_hold_time); (int)gl->gl_lockref.count, gl->gl_hold_time);
list_for_each_entry(gh, &gl->gl_holders, gh_list) { list_for_each_entry(gh, &gl->gl_holders, gh_list)
error = dump_holder(seq, gh); dump_holder(seq, gh);
if (error)
goto out;
}
if (gl->gl_state != LM_ST_UNLOCKED && glops->go_dump) if (gl->gl_state != LM_ST_UNLOCKED && glops->go_dump)
error = glops->go_dump(seq, gl); glops->go_dump(seq, gl);
out:
return error;
} }
static int gfs2_glstats_seq_show(struct seq_file *seq, void *iter_ptr) static int gfs2_glstats_seq_show(struct seq_file *seq, void *iter_ptr)
...@@ -1953,7 +1943,8 @@ static void gfs2_glock_seq_stop(struct seq_file *seq, void *iter_ptr) ...@@ -1953,7 +1943,8 @@ static void gfs2_glock_seq_stop(struct seq_file *seq, void *iter_ptr)
static int gfs2_glock_seq_show(struct seq_file *seq, void *iter_ptr) static int gfs2_glock_seq_show(struct seq_file *seq, void *iter_ptr)
{ {
return dump_glock(seq, iter_ptr); dump_glock(seq, iter_ptr);
return 0;
} }
static void *gfs2_sbstats_seq_start(struct seq_file *seq, loff_t *pos) static void *gfs2_sbstats_seq_start(struct seq_file *seq, loff_t *pos)
......
...@@ -199,7 +199,7 @@ extern int gfs2_glock_nq_num(struct gfs2_sbd *sdp, u64 number, ...@@ -199,7 +199,7 @@ extern int gfs2_glock_nq_num(struct gfs2_sbd *sdp, u64 number,
struct gfs2_holder *gh); struct gfs2_holder *gh);
extern int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs); extern int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs);
extern void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs); extern void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs);
extern int gfs2_dump_glock(struct seq_file *seq, const struct gfs2_glock *gl); extern void gfs2_dump_glock(struct seq_file *seq, const struct gfs2_glock *gl);
#define GLOCK_BUG_ON(gl,x) do { if (unlikely(x)) { gfs2_dump_glock(NULL, gl); BUG(); } } while(0) #define GLOCK_BUG_ON(gl,x) do { if (unlikely(x)) { gfs2_dump_glock(NULL, gl); BUG(); } } while(0)
extern __printf(2, 3) extern __printf(2, 3)
void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...); void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...);
......
...@@ -133,7 +133,8 @@ void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync) ...@@ -133,7 +133,8 @@ void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
static void rgrp_go_sync(struct gfs2_glock *gl) static void rgrp_go_sync(struct gfs2_glock *gl)
{ {
struct address_space *metamapping = gfs2_glock2aspace(gl); struct gfs2_sbd *sdp = gl->gl_sbd;
struct address_space *mapping = &sdp->sd_aspace;
struct gfs2_rgrpd *rgd; struct gfs2_rgrpd *rgd;
int error; int error;
...@@ -141,10 +142,10 @@ static void rgrp_go_sync(struct gfs2_glock *gl) ...@@ -141,10 +142,10 @@ static void rgrp_go_sync(struct gfs2_glock *gl)
return; return;
GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE); GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE);
gfs2_log_flush(gl->gl_sbd, gl); gfs2_log_flush(sdp, gl);
filemap_fdatawrite(metamapping); filemap_fdatawrite_range(mapping, gl->gl_vm.start, gl->gl_vm.end);
error = filemap_fdatawait(metamapping); error = filemap_fdatawait_range(mapping, gl->gl_vm.start, gl->gl_vm.end);
mapping_set_error(metamapping, error); mapping_set_error(mapping, error);
gfs2_ail_empty_gl(gl); gfs2_ail_empty_gl(gl);
spin_lock(&gl->gl_spin); spin_lock(&gl->gl_spin);
...@@ -166,11 +167,12 @@ static void rgrp_go_sync(struct gfs2_glock *gl) ...@@ -166,11 +167,12 @@ static void rgrp_go_sync(struct gfs2_glock *gl)
static void rgrp_go_inval(struct gfs2_glock *gl, int flags) static void rgrp_go_inval(struct gfs2_glock *gl, int flags)
{ {
struct address_space *mapping = gfs2_glock2aspace(gl); struct gfs2_sbd *sdp = gl->gl_sbd;
struct address_space *mapping = &sdp->sd_aspace;
WARN_ON_ONCE(!(flags & DIO_METADATA)); WARN_ON_ONCE(!(flags & DIO_METADATA));
gfs2_assert_withdraw(gl->gl_sbd, !atomic_read(&gl->gl_ail_count)); gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
truncate_inode_pages(mapping, 0); truncate_inode_pages_range(mapping, gl->gl_vm.start, gl->gl_vm.end);
if (gl->gl_object) { if (gl->gl_object) {
struct gfs2_rgrpd *rgd = (struct gfs2_rgrpd *)gl->gl_object; struct gfs2_rgrpd *rgd = (struct gfs2_rgrpd *)gl->gl_object;
...@@ -435,21 +437,19 @@ static int inode_go_lock(struct gfs2_holder *gh) ...@@ -435,21 +437,19 @@ static int inode_go_lock(struct gfs2_holder *gh)
* @seq: The iterator * @seq: The iterator
* @ip: the inode * @ip: the inode
* *
* Returns: 0 on success, -ENOBUFS when we run out of space
*/ */
static int inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl) static void inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl)
{ {
const struct gfs2_inode *ip = gl->gl_object; const struct gfs2_inode *ip = gl->gl_object;
if (ip == NULL) if (ip == NULL)
return 0; return;
gfs2_print_dbg(seq, " I: n:%llu/%llu t:%u f:0x%02lx d:0x%08x s:%llu\n", gfs2_print_dbg(seq, " I: n:%llu/%llu t:%u f:0x%02lx d:0x%08x s:%llu\n",
(unsigned long long)ip->i_no_formal_ino, (unsigned long long)ip->i_no_formal_ino,
(unsigned long long)ip->i_no_addr, (unsigned long long)ip->i_no_addr,
IF2DT(ip->i_inode.i_mode), ip->i_flags, IF2DT(ip->i_inode.i_mode), ip->i_flags,
(unsigned int)ip->i_diskflags, (unsigned int)ip->i_diskflags,
(unsigned long long)i_size_read(&ip->i_inode)); (unsigned long long)i_size_read(&ip->i_inode));
return 0;
} }
/** /**
...@@ -558,7 +558,7 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = { ...@@ -558,7 +558,7 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = {
.go_unlock = gfs2_rgrp_go_unlock, .go_unlock = gfs2_rgrp_go_unlock,
.go_dump = gfs2_rgrp_dump, .go_dump = gfs2_rgrp_dump,
.go_type = LM_TYPE_RGRP, .go_type = LM_TYPE_RGRP,
.go_flags = GLOF_ASPACE | GLOF_LVB, .go_flags = GLOF_LVB,
}; };
const struct gfs2_glock_operations gfs2_trans_glops = { const struct gfs2_glock_operations gfs2_trans_glops = {
......
...@@ -93,6 +93,7 @@ struct gfs2_rgrpd { ...@@ -93,6 +93,7 @@ struct gfs2_rgrpd {
struct gfs2_rgrp_lvb *rd_rgl; struct gfs2_rgrp_lvb *rd_rgl;
u32 rd_last_alloc; u32 rd_last_alloc;
u32 rd_flags; u32 rd_flags;
u32 rd_extfail_pt; /* extent failure point */
#define GFS2_RDF_CHECK 0x10000000 /* check for unlinked inodes */ #define GFS2_RDF_CHECK 0x10000000 /* check for unlinked inodes */
#define GFS2_RDF_UPTODATE 0x20000000 /* rg is up to date */ #define GFS2_RDF_UPTODATE 0x20000000 /* rg is up to date */
#define GFS2_RDF_ERROR 0x40000000 /* error in rg */ #define GFS2_RDF_ERROR 0x40000000 /* error in rg */
...@@ -217,7 +218,7 @@ struct gfs2_glock_operations { ...@@ -217,7 +218,7 @@ struct gfs2_glock_operations {
int (*go_demote_ok) (const struct gfs2_glock *gl); int (*go_demote_ok) (const struct gfs2_glock *gl);
int (*go_lock) (struct gfs2_holder *gh); int (*go_lock) (struct gfs2_holder *gh);
void (*go_unlock) (struct gfs2_holder *gh); void (*go_unlock) (struct gfs2_holder *gh);
int (*go_dump)(struct seq_file *seq, const struct gfs2_glock *gl); void (*go_dump)(struct seq_file *seq, const struct gfs2_glock *gl);
void (*go_callback)(struct gfs2_glock *gl, bool remote); void (*go_callback)(struct gfs2_glock *gl, bool remote);
const int go_type; const int go_type;
const unsigned long go_flags; const unsigned long go_flags;
...@@ -350,7 +351,15 @@ struct gfs2_glock { ...@@ -350,7 +351,15 @@ struct gfs2_glock {
atomic_t gl_ail_count; atomic_t gl_ail_count;
atomic_t gl_revokes; atomic_t gl_revokes;
struct delayed_work gl_work; struct delayed_work gl_work;
struct work_struct gl_delete; union {
/* For inode and iopen glocks only */
struct work_struct gl_delete;
/* For rgrp glocks only */
struct {
loff_t start;
loff_t end;
} gl_vm;
};
struct rcu_head gl_rcu; struct rcu_head gl_rcu;
}; };
...@@ -419,10 +428,13 @@ enum { ...@@ -419,10 +428,13 @@ enum {
}; };
struct gfs2_quota_data { struct gfs2_quota_data {
struct hlist_bl_node qd_hlist;
struct list_head qd_list; struct list_head qd_list;
struct kqid qd_id; struct kqid qd_id;
struct gfs2_sbd *qd_sbd;
struct lockref qd_lockref; struct lockref qd_lockref;
struct list_head qd_lru; struct list_head qd_lru;
unsigned qd_hash;
unsigned long qd_flags; /* QDF_... */ unsigned long qd_flags; /* QDF_... */
...@@ -441,6 +453,7 @@ struct gfs2_quota_data { ...@@ -441,6 +453,7 @@ struct gfs2_quota_data {
u64 qd_sync_gen; u64 qd_sync_gen;
unsigned long qd_last_warn; unsigned long qd_last_warn;
struct rcu_head qd_rcu;
}; };
struct gfs2_trans { struct gfs2_trans {
...@@ -720,13 +733,15 @@ struct gfs2_sbd { ...@@ -720,13 +733,15 @@ struct gfs2_sbd {
spinlock_t sd_trunc_lock; spinlock_t sd_trunc_lock;
unsigned int sd_quota_slots; unsigned int sd_quota_slots;
unsigned int sd_quota_chunks; unsigned long *sd_quota_bitmap;
unsigned char **sd_quota_bitmap; spinlock_t sd_bitmap_lock;
u64 sd_quota_sync_gen; u64 sd_quota_sync_gen;
/* Log stuff */ /* Log stuff */
struct address_space sd_aspace;
spinlock_t sd_log_lock; spinlock_t sd_log_lock;
struct gfs2_trans *sd_log_tr; struct gfs2_trans *sd_log_tr;
......
...@@ -149,7 +149,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, ...@@ -149,7 +149,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
ip = GFS2_I(inode); ip = GFS2_I(inode);
if (!inode) if (!inode)
return ERR_PTR(-ENOBUFS); return ERR_PTR(-ENOMEM);
if (inode->i_state & I_NEW) { if (inode->i_state & I_NEW) {
struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_sbd *sdp = GFS2_SB(inode);
...@@ -469,14 +469,36 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_inode *ip, ...@@ -469,14 +469,36 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_inode *ip,
brelse(dibh); brelse(dibh);
} }
/**
* gfs2_trans_da_blocks - Calculate number of blocks to link inode
* @dip: The directory we are linking into
* @da: The dir add information
* @nr_inodes: The number of inodes involved
*
* This calculate the number of blocks we need to reserve in a
* transaction to link @nr_inodes into a directory. In most cases
* @nr_inodes will be 2 (the directory plus the inode being linked in)
* but in case of rename, 4 may be required.
*
* Returns: Number of blocks
*/
static unsigned gfs2_trans_da_blks(const struct gfs2_inode *dip,
const struct gfs2_diradd *da,
unsigned nr_inodes)
{
return da->nr_blocks + gfs2_rg_blocks(dip, da->nr_blocks) +
(nr_inodes * RES_DINODE) + RES_QUOTA + RES_STATFS;
}
static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
struct gfs2_inode *ip, int arq) struct gfs2_inode *ip, struct gfs2_diradd *da)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct gfs2_alloc_parms ap = { .target = sdp->sd_max_dirres, }; struct gfs2_alloc_parms ap = { .target = da->nr_blocks, };
int error; int error;
if (arq) { if (da->nr_blocks) {
error = gfs2_quota_lock_check(dip); error = gfs2_quota_lock_check(dip);
if (error) if (error)
goto fail_quota_locks; goto fail_quota_locks;
...@@ -485,10 +507,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, ...@@ -485,10 +507,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
if (error) if (error)
goto fail_quota_locks; goto fail_quota_locks;
error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + error = gfs2_trans_begin(sdp, gfs2_trans_da_blks(dip, da, 2), 0);
dip->i_rgd->rd_length +
2 * RES_DINODE +
RES_STATFS + RES_QUOTA, 0);
if (error) if (error)
goto fail_ipreserv; goto fail_ipreserv;
} else { } else {
...@@ -497,7 +516,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, ...@@ -497,7 +516,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
goto fail_quota_locks; goto fail_quota_locks;
} }
error = gfs2_dir_add(&dip->i_inode, name, ip); error = gfs2_dir_add(&dip->i_inode, name, ip, da);
if (error) if (error)
goto fail_end_trans; goto fail_end_trans;
...@@ -560,7 +579,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -560,7 +579,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
struct dentry *d; struct dentry *d;
int error; int error;
u32 aflags = 0; u32 aflags = 0;
int arq; struct gfs2_diradd da = { .bh = NULL, };
if (!name->len || name->len > GFS2_FNAMESIZE) if (!name->len || name->len > GFS2_FNAMESIZE)
return -ENAMETOOLONG; return -ENAMETOOLONG;
...@@ -585,6 +604,9 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -585,6 +604,9 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
error = PTR_ERR(inode); error = PTR_ERR(inode);
if (!IS_ERR(inode)) { if (!IS_ERR(inode)) {
d = d_splice_alias(inode, dentry); d = d_splice_alias(inode, dentry);
error = PTR_ERR(d);
if (IS_ERR(d))
goto fail_gunlock;
error = 0; error = 0;
if (file) { if (file) {
if (S_ISREG(inode->i_mode)) { if (S_ISREG(inode->i_mode)) {
...@@ -602,7 +624,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -602,7 +624,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
goto fail_gunlock; goto fail_gunlock;
} }
arq = error = gfs2_diradd_alloc_required(dir, name); error = gfs2_diradd_alloc_required(dir, name, &da);
if (error < 0) if (error < 0)
goto fail_gunlock; goto fail_gunlock;
...@@ -690,7 +712,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -690,7 +712,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
if (error) if (error)
goto fail_gunlock3; goto fail_gunlock3;
error = link_dinode(dip, name, ip, arq); error = link_dinode(dip, name, ip, &da);
if (error) if (error)
goto fail_gunlock3; goto fail_gunlock3;
...@@ -719,6 +741,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -719,6 +741,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
free_inode_nonrcu(inode); free_inode_nonrcu(inode);
inode = NULL; inode = NULL;
fail_gunlock: fail_gunlock:
gfs2_dir_no_add(&da);
gfs2_glock_dq_uninit(ghs); gfs2_glock_dq_uninit(ghs);
if (inode && !IS_ERR(inode)) { if (inode && !IS_ERR(inode)) {
clear_nlink(inode); clear_nlink(inode);
...@@ -779,6 +802,11 @@ static struct dentry *__gfs2_lookup(struct inode *dir, struct dentry *dentry, ...@@ -779,6 +802,11 @@ static struct dentry *__gfs2_lookup(struct inode *dir, struct dentry *dentry,
} }
d = d_splice_alias(inode, dentry); d = d_splice_alias(inode, dentry);
if (IS_ERR(d)) {
iput(inode);
gfs2_glock_dq_uninit(&gh);
return d;
}
if (file && S_ISREG(inode->i_mode)) if (file && S_ISREG(inode->i_mode))
error = finish_open(file, dentry, gfs2_open_common, opened); error = finish_open(file, dentry, gfs2_open_common, opened);
...@@ -817,7 +845,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -817,7 +845,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder ghs[2]; struct gfs2_holder ghs[2];
struct buffer_head *dibh; struct buffer_head *dibh;
int alloc_required; struct gfs2_diradd da = { .bh = NULL, };
int error; int error;
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
...@@ -872,13 +900,12 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -872,13 +900,12 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
if (ip->i_inode.i_nlink == (u32)-1) if (ip->i_inode.i_nlink == (u32)-1)
goto out_gunlock; goto out_gunlock;
alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name); error = gfs2_diradd_alloc_required(dir, &dentry->d_name, &da);
if (error < 0) if (error < 0)
goto out_gunlock; goto out_gunlock;
error = 0;
if (alloc_required) { if (da.nr_blocks) {
struct gfs2_alloc_parms ap = { .target = sdp->sd_max_dirres, }; struct gfs2_alloc_parms ap = { .target = da.nr_blocks, };
error = gfs2_quota_lock_check(dip); error = gfs2_quota_lock_check(dip);
if (error) if (error)
goto out_gunlock; goto out_gunlock;
...@@ -887,10 +914,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -887,10 +914,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
if (error) if (error)
goto out_gunlock_q; goto out_gunlock_q;
error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + error = gfs2_trans_begin(sdp, gfs2_trans_da_blks(dip, &da, 2), 0);
gfs2_rg_blocks(dip, sdp->sd_max_dirres) +
2 * RES_DINODE + RES_STATFS +
RES_QUOTA, 0);
if (error) if (error)
goto out_ipres; goto out_ipres;
} else { } else {
...@@ -903,7 +927,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -903,7 +927,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
if (error) if (error)
goto out_end_trans; goto out_end_trans;
error = gfs2_dir_add(dir, &dentry->d_name, ip); error = gfs2_dir_add(dir, &dentry->d_name, ip, &da);
if (error) if (error)
goto out_brelse; goto out_brelse;
...@@ -919,12 +943,13 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -919,12 +943,13 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
out_end_trans: out_end_trans:
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
out_ipres: out_ipres:
if (alloc_required) if (da.nr_blocks)
gfs2_inplace_release(dip); gfs2_inplace_release(dip);
out_gunlock_q: out_gunlock_q:
if (alloc_required) if (da.nr_blocks)
gfs2_quota_unlock(dip); gfs2_quota_unlock(dip);
out_gunlock: out_gunlock:
gfs2_dir_no_add(&da);
gfs2_glock_dq(ghs + 1); gfs2_glock_dq(ghs + 1);
out_child: out_child:
gfs2_glock_dq(ghs); gfs2_glock_dq(ghs);
...@@ -1254,7 +1279,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1254,7 +1279,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
struct gfs2_rgrpd *nrgd; struct gfs2_rgrpd *nrgd;
unsigned int num_gh; unsigned int num_gh;
int dir_rename = 0; int dir_rename = 0;
int alloc_required = 0; struct gfs2_diradd da = { .nr_blocks = 0, };
unsigned int x; unsigned int x;
int error; int error;
...@@ -1388,14 +1413,14 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1388,14 +1413,14 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
goto out_gunlock; goto out_gunlock;
} }
if (nip == NULL) if (nip == NULL) {
alloc_required = gfs2_diradd_alloc_required(ndir, &ndentry->d_name); error = gfs2_diradd_alloc_required(ndir, &ndentry->d_name, &da);
error = alloc_required; if (error)
if (error < 0) goto out_gunlock;
goto out_gunlock; }
if (alloc_required) { if (da.nr_blocks) {
struct gfs2_alloc_parms ap = { .target = sdp->sd_max_dirres, }; struct gfs2_alloc_parms ap = { .target = da.nr_blocks, };
error = gfs2_quota_lock_check(ndip); error = gfs2_quota_lock_check(ndip);
if (error) if (error)
goto out_gunlock; goto out_gunlock;
...@@ -1404,10 +1429,8 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1404,10 +1429,8 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
if (error) if (error)
goto out_gunlock_q; goto out_gunlock_q;
error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + error = gfs2_trans_begin(sdp, gfs2_trans_da_blks(ndip, &da, 4) +
gfs2_rg_blocks(ndip, sdp->sd_max_dirres) + 4 * RES_LEAF + 4, 0);
4 * RES_DINODE + 4 * RES_LEAF +
RES_STATFS + RES_QUOTA + 4, 0);
if (error) if (error)
goto out_ipreserv; goto out_ipreserv;
} else { } else {
...@@ -1441,19 +1464,20 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1441,19 +1464,20 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
if (error) if (error)
goto out_end_trans; goto out_end_trans;
error = gfs2_dir_add(ndir, &ndentry->d_name, ip); error = gfs2_dir_add(ndir, &ndentry->d_name, ip, &da);
if (error) if (error)
goto out_end_trans; goto out_end_trans;
out_end_trans: out_end_trans:
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
out_ipreserv: out_ipreserv:
if (alloc_required) if (da.nr_blocks)
gfs2_inplace_release(ndip); gfs2_inplace_release(ndip);
out_gunlock_q: out_gunlock_q:
if (alloc_required) if (da.nr_blocks)
gfs2_quota_unlock(ndip); gfs2_quota_unlock(ndip);
out_gunlock: out_gunlock:
gfs2_dir_no_add(&da);
while (x--) { while (x--) {
gfs2_glock_dq(ghs + x); gfs2_glock_dq(ghs + x);
gfs2_holder_uninit(ghs + x); gfs2_holder_uninit(ghs + x);
...@@ -1607,10 +1631,22 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) ...@@ -1607,10 +1631,22 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
if (!(attr->ia_valid & ATTR_GID) || gid_eq(ogid, ngid)) if (!(attr->ia_valid & ATTR_GID) || gid_eq(ogid, ngid))
ogid = ngid = NO_GID_QUOTA_CHANGE; ogid = ngid = NO_GID_QUOTA_CHANGE;
error = gfs2_quota_lock(ip, nuid, ngid); error = get_write_access(inode);
if (error) if (error)
return error; return error;
error = gfs2_rs_alloc(ip);
if (error)
goto out;
error = gfs2_rindex_update(sdp);
if (error)
goto out;
error = gfs2_quota_lock(ip, nuid, ngid);
if (error)
goto out;
if (!uid_eq(ouid, NO_UID_QUOTA_CHANGE) || if (!uid_eq(ouid, NO_UID_QUOTA_CHANGE) ||
!gid_eq(ogid, NO_GID_QUOTA_CHANGE)) { !gid_eq(ogid, NO_GID_QUOTA_CHANGE)) {
error = gfs2_quota_check(ip, nuid, ngid); error = gfs2_quota_check(ip, nuid, ngid);
...@@ -1637,6 +1673,8 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) ...@@ -1637,6 +1673,8 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
out_gunlock_q: out_gunlock_q:
gfs2_quota_unlock(ip); gfs2_quota_unlock(ip);
out:
put_write_access(inode);
return error; return error;
} }
......
...@@ -83,6 +83,7 @@ static void maybe_release_space(struct gfs2_bufdata *bd) ...@@ -83,6 +83,7 @@ static void maybe_release_space(struct gfs2_bufdata *bd)
bd->bd_bh->b_data + bi->bi_offset, bi->bi_len); bd->bd_bh->b_data + bi->bi_offset, bi->bi_len);
clear_bit(GBF_FULL, &bi->bi_flags); clear_bit(GBF_FULL, &bi->bi_flags);
rgd->rd_free_clone = rgd->rd_free; rgd->rd_free_clone = rgd->rd_free;
rgd->rd_extfail_pt = rgd->rd_free;
} }
/** /**
...@@ -588,8 +589,12 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, ...@@ -588,8 +589,12 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
static void gfs2_meta_sync(struct gfs2_glock *gl) static void gfs2_meta_sync(struct gfs2_glock *gl)
{ {
struct address_space *mapping = gfs2_glock2aspace(gl); struct address_space *mapping = gfs2_glock2aspace(gl);
struct gfs2_sbd *sdp = gl->gl_sbd;
int error; int error;
if (mapping == NULL)
mapping = &sdp->sd_aspace;
filemap_fdatawrite(mapping); filemap_fdatawrite(mapping);
error = filemap_fdatawait(mapping); error = filemap_fdatawait(mapping);
......
...@@ -76,6 +76,7 @@ static int __init init_gfs2_fs(void) ...@@ -76,6 +76,7 @@ static int __init init_gfs2_fs(void)
gfs2_str2qstr(&gfs2_qdot, "."); gfs2_str2qstr(&gfs2_qdot, ".");
gfs2_str2qstr(&gfs2_qdotdot, ".."); gfs2_str2qstr(&gfs2_qdotdot, "..");
gfs2_quota_hash_init();
error = gfs2_sys_init(); error = gfs2_sys_init();
if (error) if (error)
......
...@@ -116,6 +116,9 @@ struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno, int create) ...@@ -116,6 +116,9 @@ struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno, int create)
unsigned long index; unsigned long index;
unsigned int bufnum; unsigned int bufnum;
if (mapping == NULL)
mapping = &sdp->sd_aspace;
shift = PAGE_CACHE_SHIFT - sdp->sd_sb.sb_bsize_shift; shift = PAGE_CACHE_SHIFT - sdp->sd_sb.sb_bsize_shift;
index = blkno >> shift; /* convert block to page */ index = blkno >> shift; /* convert block to page */
bufnum = blkno - (index << shift); /* block buf index within page */ bufnum = blkno - (index << shift); /* block buf index within page */
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "log.h" #include "log.h"
#include "quota.h" #include "quota.h"
#include "dir.h" #include "dir.h"
#include "meta_io.h"
#include "trace_gfs2.h" #include "trace_gfs2.h"
#define DO 0 #define DO 0
...@@ -62,6 +63,7 @@ static void gfs2_tune_init(struct gfs2_tune *gt) ...@@ -62,6 +63,7 @@ static void gfs2_tune_init(struct gfs2_tune *gt)
static struct gfs2_sbd *init_sbd(struct super_block *sb) static struct gfs2_sbd *init_sbd(struct super_block *sb)
{ {
struct gfs2_sbd *sdp; struct gfs2_sbd *sdp;
struct address_space *mapping;
sdp = kzalloc(sizeof(struct gfs2_sbd), GFP_KERNEL); sdp = kzalloc(sizeof(struct gfs2_sbd), GFP_KERNEL);
if (!sdp) if (!sdp)
...@@ -97,6 +99,18 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) ...@@ -97,6 +99,18 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
init_waitqueue_head(&sdp->sd_quota_wait); init_waitqueue_head(&sdp->sd_quota_wait);
INIT_LIST_HEAD(&sdp->sd_trunc_list); INIT_LIST_HEAD(&sdp->sd_trunc_list);
spin_lock_init(&sdp->sd_trunc_lock); spin_lock_init(&sdp->sd_trunc_lock);
spin_lock_init(&sdp->sd_bitmap_lock);
mapping = &sdp->sd_aspace;
address_space_init_once(mapping);
mapping->a_ops = &gfs2_meta_aops;
mapping->host = sb->s_bdev->bd_inode;
mapping->flags = 0;
mapping_set_gfp_mask(mapping, GFP_NOFS);
mapping->private_data = NULL;
mapping->backing_dev_info = sb->s_bdi;
mapping->writeback_index = 0;
spin_lock_init(&sdp->sd_log_lock); spin_lock_init(&sdp->sd_log_lock);
atomic_set(&sdp->sd_log_pinned, 0); atomic_set(&sdp->sd_log_pinned, 0);
...@@ -217,7 +231,7 @@ static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector, int silent) ...@@ -217,7 +231,7 @@ static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector, int silent)
page = alloc_page(GFP_NOFS); page = alloc_page(GFP_NOFS);
if (unlikely(!page)) if (unlikely(!page))
return -ENOBUFS; return -ENOMEM;
ClearPageUptodate(page); ClearPageUptodate(page);
ClearPageDirty(page); ClearPageDirty(page);
...@@ -956,40 +970,6 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) ...@@ -956,40 +970,6 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo)
return error; return error;
} }
static int init_threads(struct gfs2_sbd *sdp, int undo)
{
struct task_struct *p;
int error = 0;
if (undo)
goto fail_quotad;
p = kthread_run(gfs2_logd, sdp, "gfs2_logd");
if (IS_ERR(p)) {
error = PTR_ERR(p);
fs_err(sdp, "can't start logd thread: %d\n", error);
return error;
}
sdp->sd_logd_process = p;
p = kthread_run(gfs2_quotad, sdp, "gfs2_quotad");
if (IS_ERR(p)) {
error = PTR_ERR(p);
fs_err(sdp, "can't start quotad thread: %d\n", error);
goto fail;
}
sdp->sd_quotad_process = p;
return 0;
fail_quotad:
kthread_stop(sdp->sd_quotad_process);
fail:
kthread_stop(sdp->sd_logd_process);
return error;
}
static const match_table_t nolock_tokens = { static const match_table_t nolock_tokens = {
{ Opt_jid, "jid=%d\n", }, { Opt_jid, "jid=%d\n", },
{ Opt_err, NULL }, { Opt_err, NULL },
...@@ -1254,15 +1234,11 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent ...@@ -1254,15 +1234,11 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
goto fail_per_node; goto fail_per_node;
} }
error = init_threads(sdp, DO);
if (error)
goto fail_per_node;
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
error = gfs2_make_fs_rw(sdp); error = gfs2_make_fs_rw(sdp);
if (error) { if (error) {
fs_err(sdp, "can't make FS RW: %d\n", error); fs_err(sdp, "can't make FS RW: %d\n", error);
goto fail_threads; goto fail_per_node;
} }
} }
...@@ -1270,8 +1246,6 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent ...@@ -1270,8 +1246,6 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
gfs2_online_uevent(sdp); gfs2_online_uevent(sdp);
return 0; return 0;
fail_threads:
init_threads(sdp, UNDO);
fail_per_node: fail_per_node:
init_per_node(sdp, UNDO); init_per_node(sdp, UNDO);
fail_inodes: fail_inodes:
......
This diff is collapsed.
...@@ -57,5 +57,6 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip) ...@@ -57,5 +57,6 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip)
extern const struct quotactl_ops gfs2_quotactl_ops; extern const struct quotactl_ops gfs2_quotactl_ops;
extern struct shrinker gfs2_qd_shrinker; extern struct shrinker gfs2_qd_shrinker;
extern struct list_lru gfs2_qd_lru; extern struct list_lru gfs2_qd_lru;
extern void __init gfs2_quota_hash_init(void);
#endif /* __QUOTA_DOT_H__ */ #endif /* __QUOTA_DOT_H__ */
This diff is collapsed.
...@@ -68,7 +68,7 @@ extern void gfs2_rlist_add(struct gfs2_inode *ip, struct gfs2_rgrp_list *rlist, ...@@ -68,7 +68,7 @@ extern void gfs2_rlist_add(struct gfs2_inode *ip, struct gfs2_rgrp_list *rlist,
extern void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state); extern void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state);
extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist); extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist);
extern u64 gfs2_ri_total(struct gfs2_sbd *sdp); extern u64 gfs2_ri_total(struct gfs2_sbd *sdp);
extern int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl); extern void gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl);
extern int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, extern int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
struct buffer_head *bh, struct buffer_head *bh,
const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed); const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed);
......
...@@ -369,6 +369,33 @@ int gfs2_jdesc_check(struct gfs2_jdesc *jd) ...@@ -369,6 +369,33 @@ int gfs2_jdesc_check(struct gfs2_jdesc *jd)
return 0; return 0;
} }
static int init_threads(struct gfs2_sbd *sdp)
{
struct task_struct *p;
int error = 0;
p = kthread_run(gfs2_logd, sdp, "gfs2_logd");
if (IS_ERR(p)) {
error = PTR_ERR(p);
fs_err(sdp, "can't start logd thread: %d\n", error);
return error;
}
sdp->sd_logd_process = p;
p = kthread_run(gfs2_quotad, sdp, "gfs2_quotad");
if (IS_ERR(p)) {
error = PTR_ERR(p);
fs_err(sdp, "can't start quotad thread: %d\n", error);
goto fail;
}
sdp->sd_quotad_process = p;
return 0;
fail:
kthread_stop(sdp->sd_logd_process);
return error;
}
/** /**
* gfs2_make_fs_rw - Turn a Read-Only FS into a Read-Write one * gfs2_make_fs_rw - Turn a Read-Only FS into a Read-Write one
* @sdp: the filesystem * @sdp: the filesystem
...@@ -384,10 +411,14 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) ...@@ -384,10 +411,14 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
struct gfs2_log_header_host head; struct gfs2_log_header_host head;
int error; int error;
error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, 0, &t_gh); error = init_threads(sdp);
if (error) if (error)
return error; return error;
error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, 0, &t_gh);
if (error)
goto fail_threads;
j_gl->gl_ops->go_inval(j_gl, DIO_METADATA); j_gl->gl_ops->go_inval(j_gl, DIO_METADATA);
error = gfs2_find_jhead(sdp->sd_jdesc, &head); error = gfs2_find_jhead(sdp->sd_jdesc, &head);
...@@ -417,7 +448,9 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) ...@@ -417,7 +448,9 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
fail: fail:
t_gh.gh_flags |= GL_NOCACHE; t_gh.gh_flags |= GL_NOCACHE;
gfs2_glock_dq_uninit(&t_gh); gfs2_glock_dq_uninit(&t_gh);
fail_threads:
kthread_stop(sdp->sd_quotad_process);
kthread_stop(sdp->sd_logd_process);
return error; return error;
} }
...@@ -800,6 +833,9 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) ...@@ -800,6 +833,9 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
struct gfs2_holder t_gh; struct gfs2_holder t_gh;
int error; int error;
kthread_stop(sdp->sd_quotad_process);
kthread_stop(sdp->sd_logd_process);
flush_workqueue(gfs2_delete_workqueue); flush_workqueue(gfs2_delete_workqueue);
gfs2_quota_sync(sdp->sd_vfs, 0); gfs2_quota_sync(sdp->sd_vfs, 0);
gfs2_statfs_sync(sdp->sd_vfs, 0); gfs2_statfs_sync(sdp->sd_vfs, 0);
...@@ -857,9 +893,6 @@ static void gfs2_put_super(struct super_block *sb) ...@@ -857,9 +893,6 @@ static void gfs2_put_super(struct super_block *sb)
} }
spin_unlock(&sdp->sd_jindex_spin); spin_unlock(&sdp->sd_jindex_spin);
kthread_stop(sdp->sd_quotad_process);
kthread_stop(sdp->sd_logd_process);
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
error = gfs2_make_fs_ro(sdp); error = gfs2_make_fs_ro(sdp);
if (error) if (error)
......
...@@ -319,7 +319,16 @@ struct gfs2_leaf { ...@@ -319,7 +319,16 @@ struct gfs2_leaf {
__be32 lf_dirent_format; /* Format of the dirents */ __be32 lf_dirent_format; /* Format of the dirents */
__be64 lf_next; /* Next leaf, if overflow */ __be64 lf_next; /* Next leaf, if overflow */
__u8 lf_reserved[64]; union {
__u8 lf_reserved[64];
struct {
__be64 lf_inode; /* Dir inode number */
__be32 lf_dist; /* Dist from inode on chain */
__be32 lf_nsec; /* Last ins/del usecs */
__be64 lf_sec; /* Last ins/del in secs */
__u8 lf_reserved2[40];
};
};
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment