From: Jan Kara Attached patch adds functions ufs_quota_read() and ufs_quota_write() to the UFS code. So quotas for UFS should work again (they were broken by the quota io redesign). I don't actually think the patch is too much important as I'm not sure anybody uses quotas on UFS but we're in the "stable" branch so just dropping a support did not seem right to me. Signed-off-by: Jan Kara Signed-off-by: Andrew Morton --- 25-akpm/fs/ufs/super.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 99 insertions(+) diff -puN fs/ufs/super.c~fix-ufs-quota fs/ufs/super.c --- 25/fs/ufs/super.c~fix-ufs-quota 2005-02-14 10:05:19.000000000 -0800 +++ 25-akpm/fs/ufs/super.c 2005-02-14 10:05:19.000000000 -0800 @@ -1196,6 +1196,11 @@ static void destroy_inodecache(void) printk(KERN_INFO "ufs_inode_cache: not all structures were freed\n"); } +#ifdef CONFIG_QUOTA +static ssize_t ufs_quota_read(struct super_block *, int, char *,size_t, loff_t); +static ssize_t ufs_quota_write(struct super_block *, int, const char *, size_t, loff_t); +#endif + static struct super_operations ufs_super_ops = { .alloc_inode = ufs_alloc_inode, .destroy_inode = ufs_destroy_inode, @@ -1206,8 +1211,102 @@ static struct super_operations ufs_super .write_super = ufs_write_super, .statfs = ufs_statfs, .remount_fs = ufs_remount, +#ifdef CONFIG_QUOTA + .quota_read = ufs_quota_read, + .quota_write = ufs_quota_write, +#endif }; +#ifdef CONFIG_QUOTA + +/* 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 ufs_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 >> sb->s_blocksize_bits; + 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 = ufs_bread(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 */ +static ssize_t ufs_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 >> sb->s_blocksize_bits; + int err = 0; + int offset = off & (sb->s_blocksize - 1); + int tocopy; + size_t towrite = len; + struct buffer_head *bh; + + down(&inode->i_sem); + while (towrite > 0) { + tocopy = sb->s_blocksize - offset < towrite ? + sb->s_blocksize - offset : towrite; + + bh = ufs_bread(inode, blk, 1, &err); + if (!bh) + goto out; + lock_buffer(bh); + memcpy(bh->b_data+offset, data, tocopy); + flush_dcache_page(bh->b_page); + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + unlock_buffer(bh); + brelse(bh); + 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); + inode->i_version++; + inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; + mark_inode_dirty(inode); + up(&inode->i_sem); + return len - towrite; +} + +#endif + static struct super_block *ufs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { _