Commit 3c1c0ae1 authored by Steven Whitehouse's avatar Steven Whitehouse

GFS2: Add directory addition info structure

The intent is that this structure will hold the information
required when adding entries to a directory (linking). To
start with, it will contain only the number of blocks which
are required to link the new entry into the directory. The
current calculation returns either 0 or the maximim number of
blocks that can ever be requested by such a transaction.

The intent is that in a later patch, we can update the dir
code to calculate this value more accurately. In addition
further patches will also add further fields to the new
structure to increase its utility.

In addition this patch fixes a bug where the link used during
inode creation was adding requesting too many blocks in
some cases. This is harmless unless the fs is close to being
full.
Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent 70d4ee94
...@@ -2017,18 +2017,24 @@ int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip) ...@@ -2017,18 +2017,24 @@ 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_sbd *sdp = GFS2_SB(inode);
struct gfs2_dirent *dent; struct gfs2_dirent *dent;
struct buffer_head *bh; struct buffer_head *bh;
da->nr_blocks = 0;
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;
return 0;
} }
if (IS_ERR(dent)) if (IS_ERR(dent))
return PTR_ERR(dent); return PTR_ERR(dent);
......
...@@ -17,6 +17,10 @@ struct inode; ...@@ -17,6 +17,10 @@ struct inode;
struct gfs2_inode; struct gfs2_inode;
struct gfs2_inum; struct gfs2_inum;
struct gfs2_diradd {
unsigned nr_blocks;
};
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,
bool fail_on_exist); bool fail_on_exist);
...@@ -33,7 +37,8 @@ extern int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, ...@@ -33,7 +37,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);
......
...@@ -470,13 +470,13 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_inode *ip, ...@@ -470,13 +470,13 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_inode *ip,
} }
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,8 +485,8 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, ...@@ -485,8 +485,8 @@ 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, da->nr_blocks +
dip->i_rgd->rd_length + gfs2_rg_blocks(dip, da->nr_blocks) +
2 * RES_DINODE + 2 * RES_DINODE +
RES_STATFS + RES_QUOTA, 0); RES_STATFS + RES_QUOTA, 0);
if (error) if (error)
...@@ -560,7 +560,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -560,7 +560,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;
if (!name->len || name->len > GFS2_FNAMESIZE) if (!name->len || name->len > GFS2_FNAMESIZE)
return -ENAMETOOLONG; return -ENAMETOOLONG;
...@@ -602,7 +602,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -602,7 +602,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 +690,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -690,7 +690,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;
...@@ -817,7 +817,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -817,7 +817,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;
int error; int error;
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
...@@ -872,13 +872,12 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -872,13 +872,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,8 +886,8 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -887,8 +886,8 @@ 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, da.nr_blocks +
gfs2_rg_blocks(dip, sdp->sd_max_dirres) + gfs2_rg_blocks(dip, da.nr_blocks) +
2 * RES_DINODE + RES_STATFS + 2 * RES_DINODE + RES_STATFS +
RES_QUOTA, 0); RES_QUOTA, 0);
if (error) if (error)
...@@ -919,10 +918,10 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -919,10 +918,10 @@ 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_glock_dq(ghs + 1); gfs2_glock_dq(ghs + 1);
...@@ -1254,7 +1253,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1254,7 +1253,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 +1387,14 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1388,14 +1387,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,8 +1403,8 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1404,8 +1403,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, da.nr_blocks +
gfs2_rg_blocks(ndip, sdp->sd_max_dirres) + gfs2_rg_blocks(ndip, da.nr_blocks) +
4 * RES_DINODE + 4 * RES_LEAF + 4 * RES_DINODE + 4 * RES_LEAF +
RES_STATFS + RES_QUOTA + 4, 0); RES_STATFS + RES_QUOTA + 4, 0);
if (error) if (error)
...@@ -1448,10 +1447,10 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1448,10 +1447,10 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
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:
while (x--) { while (x--) {
......
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