Commit 66cf300c authored by Dave Kleikamp's avatar Dave Kleikamp

JFS: disk quota support

This patch adds disk quota support to jfs.

A patch is required for quota-tools to work with jfs.  It can be
found at http://oss.software.ibm.com/jfs/project/pub/quota-tools.patch
Quota tools source can be downloaded from
https://sourceforge.net/projects/linuxquota/

Written by: Karl Rister & Dave Kleikamp
Signed-off-by: default avatarDave Kleikamp <shaggy@austin.ibm.com>
parent 4d802161
/*
* Copyright (c) International Business Machines Corp., 2002
* Copyright (c) Andreas Gruenbacher, 2001
* Copyright (c) Linus Torvalds, 1991, 1992
* Copyright (C) International Business Machines Corp., 2002-2004
* Copyright (C) Andreas Gruenbacher, 2001
* Copyright (C) Linus Torvalds, 1991, 1992
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -20,6 +20,7 @@
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/quotaops.h>
#include "jfs_incore.h"
#include "jfs_xattr.h"
#include "jfs_acl.h"
......@@ -281,6 +282,12 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
if (rc)
return rc;
if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
(iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) {
if (DQUOT_TRANSFER(inode, iattr))
return -EDQUOT;
}
rc = inode_setattr(inode, iattr);
if (!rc && (iattr->ia_valid & ATTR_MODE))
......
/*
* Copyright (c) International Business Machines Corp., 2000-2002
* Portions Copyright (c) Christoph Hellwig, 2001-2002
* Copyright (C) International Business Machines Corp., 2000-2004
* Portions Copyright (C) Christoph Hellwig, 2001-2002
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -21,6 +21,7 @@
#include <linux/mpage.h>
#include <linux/buffer_head.h>
#include <linux/pagemap.h>
#include <linux/quotaops.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_imap.h"
......@@ -134,6 +135,13 @@ void jfs_delete_inode(struct inode *inode)
diFree(inode);
/*
* Free the inode from the quota allocation.
*/
DQUOT_INIT(inode);
DQUOT_FREE_INODE(inode);
DQUOT_DROP(inode);
clear_inode(inode);
}
......
......@@ -101,6 +101,7 @@
*/
#include <linux/fs.h>
#include <linux/quotaops.h>
#include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_filsys.h"
......@@ -380,7 +381,8 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
* It's time to move the inline table to an external
* page and begin to build the xtree
*/
if (dbAlloc(ip, 0, sbi->nbperpage, &xaddr))
if (DQUOT_ALLOC_BLOCK(ip, sbi->nbperpage) ||
dbAlloc(ip, 0, sbi->nbperpage, &xaddr))
goto clean_up; /* No space */
/*
......@@ -405,7 +407,6 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
goto clean_up;
}
ip->i_size = PSIZE;
ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage);
if ((mp = get_index_page(ip, 0)) == 0) {
jfs_err("add_index: get_metapage failed!");
......@@ -447,7 +448,6 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
goto clean_up;
}
ip->i_size += PSIZE;
ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage);
if ((mp = get_index_page(ip, blkno)))
memset(mp->data, 0, PSIZE); /* Just looks better */
......@@ -946,6 +946,7 @@ static int dtSplitUp(tid_t tid,
struct dt_lock *dtlck;
struct tlock *tlck;
struct lv *lv;
int quota_allocation = 0;
/* get split page */
smp = split->mp;
......@@ -992,7 +993,9 @@ static int dtSplitUp(tid_t tid,
split->pxdlist = &pxdlist;
rc = dtSplitRoot(tid, ip, split, &rmp);
if (!rc)
if (rc)
dbFree(ip, xaddr, xlen);
else
DT_PUTPAGE(rmp);
DT_PUTPAGE(smp);
......@@ -1017,6 +1020,14 @@ static int dtSplitUp(tid_t tid,
n = xlen + (xlen << 1);
else
n = xlen;
/* Allocate blocks to quota. */
if (DQUOT_ALLOC_BLOCK(ip, n)) {
rc = -EDQUOT;
goto extendOut;
}
quota_allocation += n;
if ((rc = dbReAlloc(sbi->ipbmap, xaddr, (s64) xlen,
(s64) n, &nxaddr)))
goto extendOut;
......@@ -1285,6 +1296,10 @@ static int dtSplitUp(tid_t tid,
freeKeyName:
kfree(key.name);
/* Rollback quota allocation */
if (rc && quota_allocation)
DQUOT_FREE_BLOCK(ip, quota_allocation);
dtSplitUp_Exit:
return rc;
......@@ -1305,7 +1320,6 @@ static int dtSplitUp(tid_t tid,
static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
struct metapage ** rmpp, dtpage_t ** rpp, pxd_t * rpxdp)
{
struct super_block *sb = ip->i_sb;
int rc = 0;
struct metapage *smp;
dtpage_t *sp;
......@@ -1344,6 +1358,12 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
if (rmp == NULL)
return -EIO;
/* Allocate blocks to quota. */
if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) {
release_metapage(rmp);
return -EDQUOT;
}
jfs_info("dtSplitPage: ip:0x%p smp:0x%p rmp:0x%p", ip, smp, rmp);
BT_MARK_DIRTY(rmp, ip);
......@@ -1593,8 +1613,6 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
*rmpp = rmp;
*rpxdp = *pxd;
ip->i_blocks += LBLK2PBLK(sb, lengthPXD(pxd));
return rc;
}
......@@ -1823,16 +1841,6 @@ static int dtExtendPage(tid_t tid,
tpxd = (pxd_t *) & pp->slot[1];
*tpxd = *pxd;
/* Since the directory might have an EA and/or ACL associated with it
* we need to make sure we take that into account when setting the
* i_nblocks
*/
ip->i_blocks = LBLK2PBLK(ip->i_sb, xlen +
((JFS_IP(ip)->ea.flag & DXD_EXTENT) ?
lengthDXD(&JFS_IP(ip)->ea) : 0) +
((JFS_IP(ip)->acl.flag & DXD_EXTENT) ?
lengthDXD(&JFS_IP(ip)->acl) : 0));
DT_PUTPAGE(pmp);
return 0;
}
......@@ -1900,6 +1908,12 @@ static int dtSplitRoot(tid_t tid,
rp = rmp->data;
/* Allocate blocks to quota. */
if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) {
release_metapage(rmp);
return -EDQUOT;
}
BT_MARK_DIRTY(rmp, ip);
/*
* acquire a transaction lock on the new right page
......@@ -2042,7 +2056,6 @@ static int dtSplitRoot(tid_t tid,
*rmpp = rmp;
ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd));
return 0;
}
......@@ -2265,7 +2278,9 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
}
xlen = lengthPXD(&fp->header.self);
ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen);
/* Free quota allocation. */
DQUOT_FREE_BLOCK(ip, xlen);
/* free/invalidate its buffer page */
discard_metapage(fmp);
......@@ -2339,7 +2354,9 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
}
xlen = lengthPXD(&p->header.self);
ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen);
/* Free quota allocation */
DQUOT_FREE_BLOCK(ip, xlen);
/* free/invalidate its buffer page */
discard_metapage(mp);
......@@ -2877,14 +2894,6 @@ void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot)
/* init '..' entry */
p->header.idotdot = cpu_to_le32(idotdot);
#if 0
ip->i_blocks = LBLK2PBLK(ip->i_sb,
((jfs_ip->ea.flag & DXD_EXTENT) ?
lengthDXD(&jfs_ip->ea) : 0) +
((jfs_ip->acl.flag & DXD_EXTENT) ?
lengthDXD(&jfs_ip->acl) : 0));
#endif
return;
}
......
/*
* Copyright (C) International Business Machines Corp., 2000-2003
* Copyright (C) International Business Machines Corp., 2000-2004
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -17,6 +17,7 @@
*/
#include <linux/fs.h>
#include <linux/quotaops.h>
#include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_dmap.h"
......@@ -144,6 +145,13 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
return (rc);
}
/* Allocate blocks to quota. */
if (DQUOT_ALLOC_BLOCK(ip, nxlen)) {
dbFree(ip, nxaddr, (s64) nxlen);
up(&JFS_IP(ip)->commit_sem);
return -EDQUOT;
}
/* determine the value of the extent flag */
xflag = (abnr == TRUE) ? XAD_NOTRECORDED : 0;
......@@ -161,13 +169,11 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
*/
if (rc) {
dbFree(ip, nxaddr, nxlen);
DQUOT_FREE_BLOCK(ip, nxlen);
up(&JFS_IP(ip)->commit_sem);
return (rc);
}
/* update the number of blocks allocated to the file */
ip->i_blocks += LBLK2PBLK(ip->i_sb, nxlen);
/* set the results of the extent allocation */
XADaddress(xp, nxaddr);
XADlength(xp, nxlen);
......@@ -254,6 +260,13 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr)
if ((rc = extBrealloc(ip, xaddr, xlen, &nxlen, &nxaddr)))
goto exit;
/* Allocat blocks to quota. */
if (DQUOT_ALLOC_BLOCK(ip, nxlen)) {
dbFree(ip, nxaddr, (s64) nxlen);
up(&JFS_IP(ip)->commit_sem);
return -EDQUOT;
}
delta = nxlen - xlen;
/* check if the extend page is not abnr but the request is abnr
......@@ -289,6 +302,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr)
/* extend the extent */
if ((rc = xtExtend(0, ip, xoff + xlen, (int) nextend, 0))) {
dbFree(ip, xaddr + xlen, delta);
DQUOT_FREE_BLOCK(ip, nxlen);
goto exit;
}
} else {
......@@ -299,6 +313,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr)
*/
if ((rc = xtTailgate(0, ip, xoff, (int) ntail, nxaddr, 0))) {
dbFree(ip, nxaddr, nxlen);
DQUOT_FREE_BLOCK(ip, nxlen);
goto exit;
}
}
......@@ -320,9 +335,6 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr)
}
}
/* update the inode with the number of blocks allocated */
ip->i_blocks += LBLK2PBLK(sb, delta);
/* set the return results */
XADaddress(xp, nxaddr);
XADlength(xp, nxlen);
......
/*
* Copyright (C) International Business Machines Corp., 2000-2003
* Copyright (C) International Business Machines Corp., 2000-2004
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -44,6 +44,7 @@
#include <linux/fs.h>
#include <linux/buffer_head.h>
#include <linux/pagemap.h>
#include <linux/quotaops.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
......@@ -504,6 +505,9 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
ip->i_mapping->a_ops = &jfs_aops;
mapping_set_gfp_mask(ip->i_mapping, GFP_NOFS);
/* Allocations to metadata inodes should not affect quotas */
ip->i_flags |= S_NOQUOTA;
if ((inum == FILESYSTEM_I) && (JFS_IP(ip)->ipimap == sbi->ipaimap)) {
sbi->gengen = le32_to_cpu(dp->di_gengen);
sbi->inostamp = le32_to_cpu(dp->di_inostamp);
......@@ -2601,28 +2605,11 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
iagp->inosmap[i] = ONES;
flush_metapage(mp);
#ifdef _STILL_TO_PORT
/* synchronously write the iag page */
if (bmWrite(bp)) {
/* Free the blocks allocated for the iag since it was
* not successfully added to the inode map
*/
dbFree(ipimap, xaddr, (s64) xlen);
/* release the inode map lock */
IWRITE_UNLOCK(ipimap);
rc = -EIO;
goto out;
}
/* Now the iag is on disk */
/*
* start tyransaction of update of the inode map
* addressing structure pointing to the new iag page;
*/
#endif /* _STILL_TO_PORT */
tid = txBegin(sb, COMMIT_FORCE);
down(&JFS_IP(ipimap)->commit_sem);
......@@ -2644,7 +2631,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
/* update the inode map's inode to reflect the extension */
ipimap->i_size += PSIZE;
ipimap->i_blocks += LBLK2PBLK(sb, xlen);
inode_add_bytes(ipimap, PSIZE);
/*
* txCommit(COMMIT_FORCE) will synchronously write address
......@@ -3085,7 +3072,7 @@ static void duplicateIXtree(struct super_block *sb, s64 blkno,
}
/* update the inode map's inode to reflect the extension */
ip->i_size += PSIZE;
ip->i_blocks += LBLK2PBLK(sb, xlen);
inode_add_bytes(ip, PSIZE);
txCommit(tid, 1, &ip, COMMIT_FORCE);
cleanup:
txEnd(tid);
......
/*
* Copyright (c) International Business Machines Corp., 2000-2002
* Copyright (C) International Business Machines Corp., 2000-2004
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -17,6 +17,7 @@
*/
#include <linux/fs.h>
#include <linux/quotaops.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_imap.h"
......@@ -60,6 +61,17 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
} else
inode->i_gid = current->fsgid;
/*
* Allocate inode to quota.
*/
if (DQUOT_ALLOC_INODE(inode)) {
DQUOT_DROP(inode);
inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
iput(inode);
return NULL;
}
inode->i_mode = mode;
if (S_ISDIR(mode))
jfs_inode->mode2 = IDIRECTORY | mode;
......
......@@ -2622,8 +2622,6 @@ void txAbort(tid_t tid, int dirty)
struct tblock *tblk = tid_to_tblock(tid);
struct tlock *tlck;
jfs_warn("txAbort: tid:%d dirty:0x%x", tid, dirty);
/*
* free tlocks of the transaction
*/
......
/*
* Copyright (C) International Business Machines Corp., 2000-2003
* Copyright (C) International Business Machines Corp., 2000-2004
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -20,6 +20,7 @@
*/
#include <linux/fs.h>
#include <linux/quotaops.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_metapage.h"
......@@ -829,8 +830,12 @@ int xtInsert(tid_t tid, /* transaction id */
hint = addressXAD(xad) + lengthXAD(xad) - 1;
} else
hint = 0;
if ((rc = dbAlloc(ip, hint, (s64) xlen, &xaddr)))
if ((rc = DQUOT_ALLOC_BLOCK(ip, xlen)))
goto out;
if ((rc = dbAlloc(ip, hint, (s64) xlen, &xaddr))) {
DQUOT_FREE_BLOCK(ip, xlen);
goto out;
}
}
/*
......@@ -855,8 +860,10 @@ int xtInsert(tid_t tid, /* transaction id */
split.pxdlist = NULL;
if ((rc = xtSplitUp(tid, ip, &split, &btstack))) {
/* undo data extent allocation */
if (*xaddrp == 0)
if (*xaddrp == 0) {
dbFree(ip, xaddr, (s64) xlen);
DQUOT_FREE_BLOCK(ip, xlen);
}
return rc;
}
......@@ -1214,22 +1221,34 @@ xtSplitPage(tid_t tid, struct inode *ip,
pxd_t *pxd;
struct tlock *tlck;
struct xtlock *sxtlck = NULL, *rxtlck = NULL;
int quota_allocation = 0;
smp = split->mp;
sp = XT_PAGE(ip, smp);
INCREMENT(xtStat.split);
/*
* allocate the new right page for the split
*/
pxdlist = split->pxdlist;
pxd = &pxdlist->pxd[pxdlist->npxd];
pxdlist->npxd++;
rbn = addressPXD(pxd);
/* Allocate blocks to quota. */
if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) {
rc = -EDQUOT;
goto clean_up;
}
quota_allocation += lengthPXD(pxd);
/*
* allocate the new right page for the split
*/
rmp = get_metapage(ip, rbn, PSIZE, 1);
if (rmp == NULL)
return -EIO;
if (rmp == NULL) {
rc = -EIO;
goto clean_up;
}
jfs_info("xtSplitPage: ip:0x%p smp:0x%p rmp:0x%p", ip, smp, rmp);
......@@ -1304,8 +1323,6 @@ xtSplitPage(tid_t tid, struct inode *ip,
*rmpp = rmp;
*rbnp = rbn;
ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd));
jfs_info("xtSplitPage: sp:0x%p rp:0x%p", sp, rp);
return 0;
}
......@@ -1321,7 +1338,7 @@ xtSplitPage(tid_t tid, struct inode *ip,
XT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc);
if (rc) {
XT_PUTPAGE(rmp);
return rc;
goto clean_up;
}
BT_MARK_DIRTY(mp, ip);
......@@ -1420,10 +1437,16 @@ xtSplitPage(tid_t tid, struct inode *ip,
*rmpp = rmp;
*rbnp = rbn;
ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd));
jfs_info("xtSplitPage: sp:0x%p rp:0x%p", sp, rp);
return rc;
clean_up:
/* Rollback quota allocation. */
if (quota_allocation)
DQUOT_FREE_BLOCK(ip, quota_allocation);
return (rc);
}
......@@ -1478,6 +1501,12 @@ xtSplitRoot(tid_t tid,
if (rmp == NULL)
return -EIO;
/* Allocate blocks to quota. */
if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) {
release_metapage(rmp);
return -EDQUOT;
}
jfs_info("xtSplitRoot: ip:0x%p rmp:0x%p", ip, rmp);
/*
......@@ -1561,8 +1590,6 @@ xtSplitRoot(tid_t tid,
*rmpp = rmp;
ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd));
jfs_info("xtSplitRoot: sp:0x%p rp:0x%p", sp, rp);
return 0;
}
......@@ -3909,8 +3936,8 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
else
ip->i_size = newsize;
/* update nblocks to reflect freed blocks */
ip->i_blocks -= LBLK2PBLK(ip->i_sb, nfreed);
/* update quota allocation to reflect freed blocks */
DQUOT_FREE_BLOCK(ip, nfreed);
/*
* free tlock of invalidated pages
......
......@@ -19,6 +19,7 @@
#include <linux/fs.h>
#include <linux/ctype.h>
#include <linux/quotaops.h>
#include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_inode.h"
......@@ -123,10 +124,10 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
*/
ino = ip->i_ino;
if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
jfs_err("jfs_create: dtInsert returned %d", rc);
if (rc == -EIO)
if (rc == -EIO) {
jfs_err("jfs_create: dtInsert returned -EIO");
txAbort(tid, 1); /* Marks Filesystem dirty */
else
} else
txAbort(tid, 0); /* Filesystem full */
goto out3;
}
......@@ -250,11 +251,10 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
*/
ino = ip->i_ino;
if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
jfs_err("jfs_mkdir: dtInsert returned %d", rc);
if (rc == -EIO)
if (rc == -EIO) {
jfs_err("jfs_mkdir: dtInsert returned -EIO");
txAbort(tid, 1); /* Marks Filesystem dirty */
else
} else
txAbort(tid, 0); /* Filesystem full */
goto out3;
}
......@@ -330,6 +330,9 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
jfs_info("jfs_rmdir: dip:0x%p name:%s", dip, dentry->d_name.name);
/* Init inode for quota operations. */
DQUOT_INIT(ip);
/* directory must be empty to be removed */
if (!dtEmpty(ip)) {
rc = -ENOTEMPTY;
......@@ -455,6 +458,9 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
jfs_info("jfs_unlink: dip:0x%p name:%s", dip, dentry->d_name.name);
/* Init inode for quota operations. */
DQUOT_INIT(ip);
if ((rc = get_UCSname(&dname, dentry)))
goto out;
......@@ -813,7 +819,10 @@ static int jfs_link(struct dentry *old_dentry,
iplist[1] = dir;
rc = txCommit(tid, 2, &iplist[0], 0);
if (!rc)
if (rc) {
ip->i_nlink--;
iput(ip);
} else
d_instantiate(dentry, ip);
free_dname:
......@@ -964,7 +973,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
mp = get_metapage(ip, xaddr, PSIZE, 1);
if (mp == NULL) {
dbFree(ip, extent, xlen);
xtTruncate(tid, ip, 0, COMMIT_PWMAP);
rc = -EIO;
txAbort(tid, 0);
goto out3;
......@@ -975,7 +984,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
name += copy_size;
xaddr += JFS_SBI(sb)->nbperpage;
}
ip->i_blocks = LBLK2PBLK(sb, xlen);
}
/*
......@@ -988,7 +996,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
}
if (rc) {
if (xlen)
dbFree(ip, extent, xlen);
xtTruncate(tid, ip, 0, COMMIT_PWMAP);
txAbort(tid, 0);
/* discard new inode */
goto out3;
......@@ -1104,8 +1112,11 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
rc = -EMLINK;
goto out3;
}
} else if (new_ip)
} else if (new_ip) {
IWRITE_LOCK(new_ip);
/* Init inode for quota operations. */
DQUOT_INIT(new_ip);
}
/*
* The real work starts here
......@@ -1174,8 +1185,8 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
ino = old_ip->i_ino;
rc = dtInsert(tid, new_dir, &new_dname, &ino, &btstack);
if (rc) {
jfs_err("jfs_rename: dtInsert failed w/rc = %d",
rc);
if (rc == -EIO)
jfs_err("jfs_rename: dtInsert returned -EIO");
goto out4;
}
if (S_ISDIR(old_ip->i_mode))
......
/*
* Copyright (C) International Business Machines Corp., 2000-2003
* Copyright (C) International Business Machines Corp., 2000-2004
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -18,6 +18,7 @@
#include <linux/fs.h>
#include <linux/buffer_head.h>
#include <linux/quotaops.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_metapage.h"
......@@ -390,7 +391,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
}
/* update bmap file size */
ipbmap->i_size += xlen << sbi->l2bsize;
ipbmap->i_blocks += LBLK2PBLK(sb, xlen);
inode_add_bytes(ipbmap, xlen << sbi->l2bsize);
iplist[0] = ipbmap;
rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
......
/*
* Copyright (C) International Business Machines Corp., 2000-2003
* Copyright (C) International Business Machines Corp., 2000-2004
* Copyright (C) Christoph Hellwig, 2002
*
* This program is free software; you can redistribute it and/or modify
......@@ -19,6 +19,7 @@
#include <linux/fs.h>
#include <linux/xattr.h>
#include <linux/quotaops.h>
#include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_dmap.h"
......@@ -251,9 +252,17 @@ static int ea_write(struct inode *ip, struct jfs_ea_list *ealist, int size,
/* figure out how many blocks we need */
nblocks = (size + (sb->s_blocksize - 1)) >> sb->s_blocksize_bits;
/* Allocate new blocks to quota. */
if (DQUOT_ALLOC_BLOCK(ip, nblocks)) {
return -EDQUOT;
}
rc = dbAlloc(ip, INOHINT(ip), nblocks, &blkno);
if (rc)
if (rc) {
/*Rollback quota allocation. */
DQUOT_FREE_BLOCK(ip, nblocks);
return rc;
}
/*
* Now have nblocks worth of storage to stuff into the FEALIST.
......@@ -315,6 +324,9 @@ static int ea_write(struct inode *ip, struct jfs_ea_list *ealist, int size,
return 0;
failed:
/* Rollback quota allocation. */
DQUOT_FREE_BLOCK(ip, nblocks);
dbFree(ip, blkno, nblocks);
return rc;
}
......@@ -448,6 +460,7 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
int blocks_needed, current_blocks;
s64 blkno;
int rc;
int quota_allocation = 0;
/* When fsck.jfs clears a bad ea, it doesn't clear the size */
if (ji->ea.flag == 0)
......@@ -517,10 +530,16 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
sb->s_blocksize_bits;
if (blocks_needed > current_blocks) {
/* Allocate new blocks to quota. */
if (DQUOT_ALLOC_BLOCK(inode, blocks_needed))
return -EDQUOT;
quota_allocation = blocks_needed;
rc = dbAlloc(inode, INOHINT(inode), (s64) blocks_needed,
&blkno);
if (rc)
return rc;
goto clean_up;
DXDlength(&ea_buf->new_ea, blocks_needed);
DXDaddress(&ea_buf->new_ea, blkno);
......@@ -534,7 +553,8 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
1);
if (ea_buf->mp == NULL) {
dbFree(inode, blkno, (s64) blocks_needed);
return -EIO;
rc = -EIO;
goto clean_up;
}
ea_buf->xattr = ea_buf->mp->data;
ea_buf->max_size = (min_size + sb->s_blocksize - 1) &
......@@ -544,7 +564,7 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
if ((rc = ea_read(inode, ea_buf->xattr))) {
discard_metapage(ea_buf->mp);
dbFree(inode, blkno, (s64) blocks_needed);
return rc;
goto clean_up;
}
goto size_check;
}
......@@ -552,8 +572,10 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
ea_buf->mp = read_metapage(inode, addressDXD(&ji->ea),
lengthDXD(&ji->ea) << sb->s_blocksize_bits,
1);
if (ea_buf->mp == NULL)
return -EIO;
if (ea_buf->mp == NULL) {
rc = -EIO;
goto clean_up;
}
ea_buf->xattr = ea_buf->mp->data;
ea_buf->max_size = (ea_size + sb->s_blocksize - 1) &
~(sb->s_blocksize - 1);
......@@ -563,10 +585,18 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
printk(KERN_ERR "ea_get: invalid extended attribute\n");
dump_mem("xattr", ea_buf->xattr, ea_size);
ea_release(inode, ea_buf);
return -EIO;
rc = -EIO;
goto clean_up;
}
return ea_size;
clean_up:
/* Rollback quota allocation */
if (quota_allocation)
DQUOT_FREE_BLOCK(inode, quota_allocation);
return (rc);
}
static void ea_release(struct inode *inode, struct ea_buffer *ea_buf)
......@@ -640,7 +670,10 @@ static int ea_put(struct inode *inode, struct ea_buffer *ea_buf, int new_size)
ji->ea.size = 0;
}
inode->i_blocks += LBLK2PBLK(inode->i_sb, new_blocks - old_blocks);
/* If old blocks exist, they must be removed from quota allocation. */
if (old_blocks)
DQUOT_FREE_BLOCK(inode, old_blocks);
inode->i_ctime = CURRENT_TIME;
rc = txCommit(tid, 1, &inode, 0);
txEnd(tid);
......
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