+++ /dev/null
-Index: linux-2.6.9/fs/ext3/inode.c
-===================================================================
---- linux-2.6.9.orig/fs/ext3/inode.c 2006-08-25 16:39:10.000000000 +0800
-+++ linux-2.6.9/fs/ext3/inode.c 2006-09-14 11:44:29.000000000 +0800
-@@ -1028,7 +1028,7 @@
- return ret;
- }
-
--static int
-+int
- ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh)
- {
- int err = journal_dirty_data(handle, bh);
-Index: linux-2.6.9/fs/ext3/super.c
-===================================================================
---- linux-2.6.9.orig/fs/ext3/super.c 2006-08-25 16:39:48.000000000 +0800
-+++ linux-2.6.9/fs/ext3/super.c 2006-09-14 11:51:48.000000000 +0800
-@@ -529,7 +529,10 @@
- static int ext3_write_info(struct super_block *sb, int type);
- static int ext3_quota_on(struct super_block *sb, int type, int format_id, char *path);
- static int ext3_quota_on_mount(struct super_block *sb, int type);
--static int ext3_quota_off_mount(struct super_block *sb, int type);
-+static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data,
-+ size_t len, loff_t off);
-+static ssize_t ext3_quota_write(struct super_block *sb, int type,
-+ const char *data, size_t len, loff_t off);
-
- static struct dquot_operations ext3_quota_operations = {
- .initialize = ext3_dquot_initialize,
-@@ -572,6 +575,10 @@
- .statfs = ext3_statfs,
- .remount_fs = ext3_remount,
- .clear_inode = ext3_clear_inode,
-+#ifdef CONFIG_QUOTA
-+ .quota_read = ext3_quota_read,
-+ .quota_write = ext3_quota_write,
-+#endif
- };
-
- static struct dentry *ext3_get_dentry(struct super_block *sb, void *vobjp)
-@@ -713,6 +720,7 @@
- int option;
- #ifdef CONFIG_QUOTA
- int qtype;
-+ char *qname;
- #endif
-
- if (!options)
-@@ -891,19 +899,22 @@
- "quota options when quota turned on.\n");
- return 0;
- }
-- if (sbi->s_qf_names[qtype]) {
-+ qname = match_strdup(&args[0]);
-+ if (!qname) {
- printk(KERN_ERR
-- "EXT3-fs: %s quota file already "
-- "specified.\n", QTYPE2NAME(qtype));
-+ "EXT3-fs: not enough memory for "
-+ "storing quotafile name.\n");
- return 0;
- }
-- sbi->s_qf_names[qtype] = match_strdup(&args[0]);
-- if (!sbi->s_qf_names[qtype]) {
-+ if (sbi->s_qf_names[qtype] &&
-+ strcmp(sbi->s_qf_names[qtype], qname)) {
- printk(KERN_ERR
-- "EXT3-fs: not enough memory for "
-- "storing quotafile name.\n");
-+ "EXT3-fs: %s quota file already "
-+ "specified.\n", QTYPE2NAME(qtype));
-+ kfree(qname);
- return 0;
- }
-+ sbi->s_qf_names[qtype] = qname;
- if (strchr(sbi->s_qf_names[qtype], '/')) {
- printk(KERN_ERR
- "EXT3-fs: quotafile must be on "
-@@ -1223,7 +1234,7 @@
- /* Turn quotas off */
- for (i = 0; i < MAXQUOTAS; i++) {
- if (sb_dqopt(sb)->files[i])
-- ext3_quota_off_mount(sb, i);
-+ vfs_quota_off(sb, i);
- }
- #endif
- sb->s_flags = s_flags; /* Restore MS_RDONLY status */
-@@ -2240,7 +2251,7 @@
-
- static inline struct inode *dquot_to_inode(struct dquot *dquot)
- {
-- return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]->f_dentry->d_inode;
-+ return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
- }
-
- static int ext3_dquot_initialize(struct inode *inode, int type)
-@@ -2279,8 +2290,10 @@
- {
- int ret, err;
- handle_t *handle;
-+ struct inode *inode;
-
-- handle = ext3_journal_start(dquot_to_inode(dquot),
-+ inode = dquot_to_inode(dquot);
-+ handle = ext3_journal_start(inode,
- EXT3_QUOTA_TRANS_BLOCKS);
- if (IS_ERR(handle))
- return PTR_ERR(handle);
-@@ -2367,22 +2380,9 @@
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
- err = vfs_quota_on_mount(type, EXT3_SB(sb)->s_jquota_fmt, dentry);
-- if (err)
-- dput(dentry);
-- /* We keep the dentry reference if everything went ok - we drop it
-- * on quota_off time */
-- return err;
--}
--
--/* Turn quotas off during mount time */
--static int ext3_quota_off_mount(struct super_block *sb, int type)
--{
-- int err;
-- struct dentry *dentry;
--
-- dentry = sb_dqopt(sb)->files[type]->f_dentry;
-- err = vfs_quota_off_mount(sb, type);
-- /* We invalidate dentry - it has at least wrong hash... */
-+ /* Now invalidate and put the dentry - quota got its own reference
-+ * to inode and dentry has at least wrong hash so we had better
-+ * throw it away */
- d_invalidate(dentry);
- dput(dentry);
- return err;
-@@ -2405,20 +2405,121 @@
- if (err)
- return err;
- /* Quotafile not on the same filesystem? */
-- if (nd.mnt->mnt_sb != sb)
-+ if (nd.mnt->mnt_sb != sb) {
-+ path_release(&nd);
- return -EXDEV;
-+ }
- /* Quotafile not of fs root? */
- if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode)
- printk(KERN_WARNING
- "EXT3-fs: Quota file not on filesystem root. "
- "Journalled quota will not work.\n");
-- if (!ext3_should_journal_data(nd.dentry->d_inode))
-- printk(KERN_WARNING "EXT3-fs: Quota file does not have "
-- "data-journalling. Journalled quota will not work.\n");
- path_release(&nd);
- return vfs_quota_on(sb, type, format_id, path);
- }
-
-+/* Read data from quotafile - avoid pagecache and such because we cannot afford
-+ * acquiring the locks... As quota files are never truncated and quota code
-+ * itself serializes the operations (and noone else should touch the files)
-+ * we don't have to be afraid of races */
-+static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data,
-+ size_t len, loff_t off)
-+{
-+ struct inode *inode = sb_dqopt(sb)->files[type];
-+ sector_t blk = off >> EXT3_BLOCK_SIZE_BITS(sb);
-+ int err = 0;
-+ int offset = off & (sb->s_blocksize - 1);
-+ int tocopy;
-+ size_t toread;
-+ struct buffer_head *bh;
-+ loff_t i_size = i_size_read(inode);
-+
-+ if (off > i_size)
-+ return 0;
-+ if (off+len > i_size)
-+ len = i_size-off;
-+ toread = len;
-+ while (toread > 0) {
-+ tocopy = sb->s_blocksize - offset < toread ?
-+ sb->s_blocksize - offset : toread;
-+ bh = ext3_bread(NULL, inode, blk, 0, &err);
-+ if (err)
-+ return err;
-+ if (!bh) /* A hole? */
-+ memset(data, 0, tocopy);
-+ else
-+ memcpy(data, bh->b_data+offset, tocopy);
-+ brelse(bh);
-+ offset = 0;
-+ toread -= tocopy;
-+ data += tocopy;
-+ blk++;
-+ }
-+ return len;
-+}
-+
-+/* Write to quotafile (we know the transaction is already started and has
-+ * enough credits) */
-+static ssize_t ext3_quota_write(struct super_block *sb, int type,
-+ const char *data, size_t len, loff_t off)
-+{
-+ struct inode *inode = sb_dqopt(sb)->files[type];
-+ sector_t blk = off >> EXT3_BLOCK_SIZE_BITS(sb);
-+ int err = 0;
-+ int offset = off & (sb->s_blocksize - 1);
-+ int tocopy;
-+ int journal_quota = EXT3_SB(sb)->s_qf_names[type] != NULL;
-+ size_t towrite = len;
-+ struct buffer_head *bh;
-+ handle_t *handle = journal_current_handle();
-+
-+ down(&inode->i_sem);
-+ while (towrite > 0) {
-+ tocopy = sb->s_blocksize - offset < towrite ?
-+ sb->s_blocksize - offset : towrite;
-+ bh = ext3_bread(handle, inode, blk, 1, &err);
-+ if (!bh)
-+ goto out;
-+ if (journal_quota) {
-+ err = ext3_journal_get_write_access(handle, bh);
-+ if (err) {
-+ brelse(bh);
-+ goto out;
-+ }
-+ }
-+ lock_buffer(bh);
-+ memcpy(bh->b_data+offset, data, tocopy);
-+ flush_dcache_page(bh->b_page);
-+ unlock_buffer(bh);
-+ if (journal_quota)
-+ err = ext3_journal_dirty_metadata(handle, bh);
-+ else {
-+ /* Always do at least ordered writes for quotas */
-+ err = ext3_journal_dirty_data(handle, bh);
-+ mark_buffer_dirty(bh);
-+ }
-+ brelse(bh);
-+ if (err)
-+ goto out;
-+ offset = 0;
-+ towrite -= tocopy;
-+ data += tocopy;
-+ blk++;
-+ }
-+out:
-+ if (len == towrite)
-+ return err;
-+ if (inode->i_size < off+len-towrite) {
-+ i_size_write(inode, off+len-towrite);
-+ EXT3_I(inode)->i_disksize = inode->i_size;
-+ }
-+ inode->i_version++;
-+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-+ ext3_mark_inode_dirty(handle, inode);
-+ up(&inode->i_sem);
-+ return len - towrite;
-+}
-+
- #endif
-
- static struct super_block *ext3_get_sb(struct file_system_type *fs_type,
-Index: linux-2.6.9/include/linux/ext3_jbd.h
-===================================================================
---- linux-2.6.9.orig/include/linux/ext3_jbd.h 2006-08-25 16:39:09.000000000 +0800
-+++ linux-2.6.9/include/linux/ext3_jbd.h 2006-09-14 11:44:29.000000000 +0800
-@@ -193,6 +193,8 @@
- #define ext3_journal_forget(handle, bh) \
- __ext3_journal_forget(__FUNCTION__, (handle), (bh))
-
-+int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh);
-+
- handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks);
- int __ext3_journal_stop(const char *where, handle_t *handle);
-