Hello. Following patch fixes bug in dquot_transfer() - while we were sleeping i_blocks might change and so number quota was miscounted. Patches are against 2.2.16 and 2.4.0-test6 (but should apply well on newer versions). Honza
--- linux/fs/dquot.c Tue Aug 29 11:01:00 2000 +++ linux/fs/dquot.c Sat Sep 2 23:01:04 2000 @@ -1260,14 +1260,6 @@ if (!inode) return -ENOENT; /* - * Find out if this filesystem uses i_blocks. - */ - if (inode->i_blksize == 0) - blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE); - else - blocks = (inode->i_blocks / 2); - - /* * Build the transfer_from and transfer_to lists and check quotas to see * if operation is permitted. */ @@ -1326,13 +1318,25 @@ * dqget() could block and so the first structure might got * invalidated or locked... */ - if (!transfer_to[cnt]->dq_mnt || !transfer_from[cnt]->dq_mnt || - check_idq(transfer_to[cnt], cnt, 1, initiator, tty) == NO_QUOTA || - check_bdq(transfer_to[cnt], cnt, blocks, initiator, tty, 0) == NO_QUOTA) { + if (!transfer_to[cnt]->dq_mnt || !transfer_from[cnt]->dq_mnt) { cnt++; goto put_all; } } + + /* + * Find out if this filesystem uses i_blocks. + */ + if (inode->i_blksize == 0) + blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE); + else + blocks = (inode->i_blocks / 2); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + if (check_idq(transfer_to[cnt], cnt, 1, initiator, tty) == NO_QUOTA || + check_bdq(transfer_to[cnt], cnt, blocks, initiator, tty, 0) == +NO_QUOTA) { + cnt = MAXQUOTAS; + goto put_all; + } if ((error = notify_change(dentry, iattr))) goto put_all;
--- linux/fs/dquot.c Mon Aug 28 20:12:25 2000 +++ linux/fs/dquot.c Sat Sep 2 23:10:29 2000 @@ -1214,14 +1214,6 @@ lock_kernel(); /* - * Find out if this filesystem uses i_blocks. - */ - if (!inode->i_sb->s_blocksize) - blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE_BITS); - else - blocks = (inode->i_blocks >> 1); - - /* * Build the transfer_from and transfer_to lists and check quotas to see * if operation is permitted. */ @@ -1280,13 +1272,25 @@ * dqget() could block and so the first structure might got * invalidated or locked... */ - if (!transfer_to[cnt]->dq_sb || !transfer_from[cnt]->dq_sb || - check_idq(transfer_to[cnt], 1) == NO_QUOTA || - check_bdq(transfer_to[cnt], blocks, 0) == NO_QUOTA) { + if (!transfer_to[cnt]->dq_sb || !transfer_from[cnt]->dq_sb) { cnt++; goto put_all; } } + + /* + * Find out if this filesystem uses i_blocks. + */ + if (!inode->i_sb->s_blocksize) + blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE_BITS); + else + blocks = (inode->i_blocks >> 1); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + if (check_idq(transfer_to[cnt], 1) == NO_QUOTA || + check_bdq(transfer_to[cnt], blocks, 0) == NO_QUOTA) { + cnt = MAXQUOTAS; + goto put_all; + } if ((error = notify_change(dentry, iattr))) goto put_all;