Commit 2125f957 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://oss.sgi.com:8090/xfs-linux-2.6

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 5bc4b4bd 4f2063ff
...@@ -116,17 +116,10 @@ __linvfs_write( ...@@ -116,17 +116,10 @@ __linvfs_write(
ssize_t rval; ssize_t rval;
BUG_ON(iocb->ki_pos != pos); BUG_ON(iocb->ki_pos != pos);
if (unlikely(file->f_flags & O_DIRECT)) { if (unlikely(file->f_flags & O_DIRECT))
ioflags |= IO_ISDIRECT; ioflags |= IO_ISDIRECT;
VOP_WRITE(vp, iocb, &iov, 1, &iocb->ki_pos,
ioflags, NULL, rval);
} else {
down(&inode->i_sem);
VOP_WRITE(vp, iocb, &iov, 1, &iocb->ki_pos,
ioflags, NULL, rval);
up(&inode->i_sem);
}
VOP_WRITE(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL, rval);
return rval; return rval;
} }
...@@ -214,17 +207,10 @@ __linvfs_writev( ...@@ -214,17 +207,10 @@ __linvfs_writev(
init_sync_kiocb(&kiocb, file); init_sync_kiocb(&kiocb, file);
kiocb.ki_pos = *ppos; kiocb.ki_pos = *ppos;
if (unlikely(file->f_flags & O_DIRECT)) { if (unlikely(file->f_flags & O_DIRECT))
ioflags |= IO_ISDIRECT; ioflags |= IO_ISDIRECT;
VOP_WRITE(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos,
ioflags, NULL, rval);
} else {
down(&inode->i_sem);
VOP_WRITE(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos,
ioflags, NULL, rval);
up(&inode->i_sem);
}
VOP_WRITE(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, ioflags, NULL, rval);
if (rval == -EIOCBQUEUED) if (rval == -EIOCBQUEUED)
rval = wait_on_sync_kiocb(&kiocb); rval = wait_on_sync_kiocb(&kiocb);
......
...@@ -45,8 +45,7 @@ ...@@ -45,8 +45,7 @@
#if defined(CONFIG_IA64) || defined(CONFIG_X86_64) #if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
#define BROKEN_X86_ALIGNMENT #define BROKEN_X86_ALIGNMENT
#endif #else
typedef struct xfs_fsop_bulkreq32 { typedef struct xfs_fsop_bulkreq32 {
compat_uptr_t lastip; /* last inode # pointer */ compat_uptr_t lastip; /* last inode # pointer */
...@@ -77,6 +76,7 @@ xfs_ioctl32_bulkstat( ...@@ -77,6 +76,7 @@ xfs_ioctl32_bulkstat(
return sys_ioctl(fd, cmd, (unsigned long)p); return sys_ioctl(fd, cmd, (unsigned long)p);
} }
#endif
struct ioctl_trans xfs_ioctl32_trans[] = { struct ioctl_trans xfs_ioctl32_trans[] = {
{ XFS_IOC_DIOINFO, }, { XFS_IOC_DIOINFO, },
......
...@@ -74,6 +74,7 @@ ...@@ -74,6 +74,7 @@
#include "xfs_iomap.h" #include "xfs_iomap.h"
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/writeback.h>
#if defined(XFS_RW_TRACE) #if defined(XFS_RW_TRACE)
...@@ -225,40 +226,11 @@ xfs_inval_cached_pages( ...@@ -225,40 +226,11 @@ xfs_inval_cached_pages(
int write, int write,
int relock) int relock)
{ {
xfs_mount_t *mp; if (VN_CACHED(vp)) {
if (!VN_CACHED(vp)) {
return;
}
mp = io->io_mount;
/*
* We need to get the I/O lock exclusively in order
* to safely invalidate pages and mappings.
*/
if (relock) {
XFS_IUNLOCK(mp, io, XFS_IOLOCK_SHARED);
XFS_ILOCK(mp, io, XFS_IOLOCK_EXCL);
}
/* Writing beyond EOF creates a hole that must be zeroed */
if (write && (offset > XFS_SIZE(mp, io))) {
xfs_fsize_t isize;
XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
isize = XFS_SIZE(mp, io);
if (offset > isize) {
xfs_zero_eof(vp, io, offset, isize, offset);
}
XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
}
xfs_inval_cached_trace(io, offset, -1, ctooff(offtoct(offset)), -1); xfs_inval_cached_trace(io, offset, -1, ctooff(offtoct(offset)), -1);
VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(offset)), -1, FI_REMAPF_LOCKED); VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(offset)), -1, FI_REMAPF_LOCKED);
if (relock) {
XFS_ILOCK_DEMOTE(mp, io, XFS_IOLOCK_EXCL);
} }
} }
ssize_t /* bytes read, or (-) error */ ssize_t /* bytes read, or (-) error */
...@@ -637,32 +609,34 @@ xfs_write( ...@@ -637,32 +609,34 @@ xfs_write(
bhv_desc_t *bdp, bhv_desc_t *bdp,
struct kiocb *iocb, struct kiocb *iocb,
const struct iovec *iovp, const struct iovec *iovp,
unsigned int segs, unsigned int nsegs,
loff_t *offset, loff_t *offset,
int ioflags, int ioflags,
cred_t *credp) cred_t *credp)
{ {
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
size_t size = 0; struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
unsigned long segs = nsegs;
xfs_inode_t *xip; xfs_inode_t *xip;
xfs_mount_t *mp; xfs_mount_t *mp;
ssize_t ret; ssize_t ret = 0, error = 0;
int error = 0;
xfs_fsize_t isize, new_size; xfs_fsize_t isize, new_size;
xfs_fsize_t n, limit;
xfs_iocore_t *io; xfs_iocore_t *io;
vnode_t *vp; vnode_t *vp;
unsigned long seg; unsigned long seg;
int iolock; int iolock;
int eventsent = 0; int eventsent = 0;
vrwlock_t locktype; vrwlock_t locktype;
size_t ocount = 0, count;
loff_t pos;
int need_isem = 1, need_flush = 0;
XFS_STATS_INC(xs_write_calls); XFS_STATS_INC(xs_write_calls);
vp = BHV_TO_VNODE(bdp); vp = BHV_TO_VNODE(bdp);
xip = XFS_BHVTOI(bdp); xip = XFS_BHVTOI(bdp);
/* START copy & waste from filemap.c */
for (seg = 0; seg < segs; seg++) { for (seg = 0; seg < segs; seg++) {
const struct iovec *iv = &iovp[seg]; const struct iovec *iv = &iovp[seg];
...@@ -670,73 +644,90 @@ xfs_write( ...@@ -670,73 +644,90 @@ xfs_write(
* If any segment has a negative length, or the cumulative * If any segment has a negative length, or the cumulative
* length ever wraps negative then return -EINVAL. * length ever wraps negative then return -EINVAL.
*/ */
size += iv->iov_len; ocount += iv->iov_len;
if (unlikely((ssize_t)(size|iv->iov_len) < 0)) if (unlikely((ssize_t)(ocount|iv->iov_len) < 0))
return XFS_ERROR(-EINVAL); return -EINVAL;
if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
continue;
if (seg == 0)
return -EFAULT;
segs = seg;
ocount -= iv->iov_len; /* This segment is no good */
break;
} }
/* END copy & waste from filemap.c */
if (size == 0) count = ocount;
pos = *offset;
if (count == 0)
return 0; return 0;
io = &xip->i_iocore; io = &xip->i_iocore;
mp = io->io_mount; mp = io->io_mount;
if (XFS_FORCED_SHUTDOWN(mp)) { if (XFS_FORCED_SHUTDOWN(mp))
return -EIO; return -EIO;
}
if (ioflags & IO_ISDIRECT) { if (ioflags & IO_ISDIRECT) {
xfs_buftarg_t *target = xfs_buftarg_t *target =
(xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
mp->m_rtdev_targp : mp->m_ddev_targp; mp->m_rtdev_targp : mp->m_ddev_targp;
if ((*offset & target->pbr_smask) || if ((pos & target->pbr_smask) || (count & target->pbr_smask))
(size & target->pbr_smask)) {
return XFS_ERROR(-EINVAL); return XFS_ERROR(-EINVAL);
if (!VN_CACHED(vp) && pos < i_size_read(inode))
need_isem = 0;
if (VN_CACHED(vp))
need_flush = 1;
} }
iolock = XFS_IOLOCK_SHARED;
locktype = VRWLOCK_WRITE_DIRECT; relock:
} else { if (need_isem) {
iolock = XFS_IOLOCK_EXCL; iolock = XFS_IOLOCK_EXCL;
locktype = VRWLOCK_WRITE; locktype = VRWLOCK_WRITE;
down(&inode->i_sem);
} else {
iolock = XFS_IOLOCK_SHARED;
locktype = VRWLOCK_WRITE_DIRECT;
} }
xfs_ilock(xip, XFS_ILOCK_EXCL|iolock); xfs_ilock(xip, XFS_ILOCK_EXCL|iolock);
isize = xip->i_d.di_size; isize = i_size_read(inode);
limit = XFS_MAXIOFFSET(mp);
if (file->f_flags & O_APPEND) if (file->f_flags & O_APPEND)
*offset = isize; *offset = isize;
start: start:
n = limit - *offset; error = -generic_write_checks(file, &pos, &count,
if (n <= 0) { S_ISBLK(inode->i_mode));
if (error) {
xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
return -EFBIG; goto out_unlock_isem;
} }
if (n < size) new_size = pos + count;
size = n; if (new_size > isize)
new_size = *offset + size;
if (new_size > isize) {
io->io_new_size = new_size; io->io_new_size = new_size;
}
if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) && if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) &&
!(ioflags & IO_INVIS) && !eventsent)) { !(ioflags & IO_INVIS) && !eventsent)) {
loff_t savedsize = *offset; loff_t savedsize = pos;
int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG_RD(ioflags); int dmflags = FILP_DELAY_FLAG(file);
if (need_isem)
dmflags |= DM_FLAGS_ISEM;
xfs_iunlock(xip, XFS_ILOCK_EXCL); xfs_iunlock(xip, XFS_ILOCK_EXCL);
error = XFS_SEND_DATA(xip->i_mount, DM_EVENT_WRITE, vp, error = XFS_SEND_DATA(xip->i_mount, DM_EVENT_WRITE, vp,
*offset, size, pos, count,
dmflags, &locktype); dmflags, &locktype);
if (error) { if (error) {
xfs_iunlock(xip, iolock); xfs_iunlock(xip, iolock);
return -error; goto out_unlock_isem;
} }
xfs_ilock(xip, XFS_ILOCK_EXCL); xfs_ilock(xip, XFS_ILOCK_EXCL);
eventsent = 1; eventsent = 1;
...@@ -748,9 +739,8 @@ xfs_write( ...@@ -748,9 +739,8 @@ xfs_write(
* event prevents another call to XFS_SEND_DATA, which is * event prevents another call to XFS_SEND_DATA, which is
* what allows the size to change in the first place. * what allows the size to change in the first place.
*/ */
if ((file->f_flags & O_APPEND) && if ((file->f_flags & O_APPEND) && savedsize != isize) {
savedsize != xip->i_d.di_size) { pos = isize = xip->i_d.di_size;
*offset = isize = xip->i_d.di_size;
goto start; goto start;
} }
} }
...@@ -761,8 +751,10 @@ xfs_write( ...@@ -761,8 +751,10 @@ xfs_write(
* *
* We must update xfs' times since revalidate will overcopy xfs. * We must update xfs' times since revalidate will overcopy xfs.
*/ */
if (size && !(ioflags & IO_INVIS)) if (!(ioflags & IO_INVIS)) {
xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
inode_update_time(inode, 1);
}
/* /*
* If the offset is beyond the size of the file, we have a couple * If the offset is beyond the size of the file, we have a couple
...@@ -773,12 +765,12 @@ xfs_write( ...@@ -773,12 +765,12 @@ xfs_write(
* to zero it out up to the new size. * to zero it out up to the new size.
*/ */
if (!(ioflags & IO_ISDIRECT) && (*offset > isize && isize)) { if (pos > isize) {
error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, *offset, error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos,
isize, *offset + size); isize, pos + count);
if (error) { if (error) {
xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
return(-error); goto out_unlock_isem;
} }
} }
xfs_iunlock(xip, XFS_ILOCK_EXCL); xfs_iunlock(xip, XFS_ILOCK_EXCL);
...@@ -795,22 +787,64 @@ xfs_write( ...@@ -795,22 +787,64 @@ xfs_write(
(S_ISGID | S_IXGRP))) && (S_ISGID | S_IXGRP))) &&
!capable(CAP_FSETID)) { !capable(CAP_FSETID)) {
error = xfs_write_clear_setuid(xip); error = xfs_write_clear_setuid(xip);
if (error) { if (likely(!error))
error = -remove_suid(file->f_dentry);
if (unlikely(error)) {
xfs_iunlock(xip, iolock); xfs_iunlock(xip, iolock);
return -error; goto out_unlock_isem;
} }
} }
retry: retry:
if (ioflags & IO_ISDIRECT) { /* We can write back this queue in page reclaim */
xfs_inval_cached_pages(vp, io, *offset, 1, 1); current->backing_dev_info = mapping->backing_dev_info;
xfs_rw_enter_trace(XFS_DIOWR_ENTER,
io, (void *)iovp, segs, *offset, ioflags); if ((ioflags & IO_ISDIRECT)) {
if (need_flush) {
xfs_inval_cached_trace(io, pos, -1,
ctooff(offtoct(pos)), -1);
VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(pos)),
-1, FI_REMAPF_LOCKED);
}
if (need_isem) {
/* demote the lock now the cached pages are gone */
XFS_ILOCK_DEMOTE(mp, io, XFS_IOLOCK_EXCL);
up(&inode->i_sem);
iolock = XFS_IOLOCK_SHARED;
locktype = VRWLOCK_WRITE_DIRECT;
need_isem = 0;
}
xfs_rw_enter_trace(XFS_DIOWR_ENTER, io, (void *)iovp, segs,
*offset, ioflags);
ret = generic_file_direct_write(iocb, iovp,
&segs, pos, offset, count, ocount);
/*
* direct-io write to a hole: fall through to buffered I/O
* for completing the rest of the request.
*/
if (ret >= 0 && ret != count) {
XFS_STATS_ADD(xs_write_bytes, ret);
pos += ret;
count -= ret;
need_isem = 1;
ioflags &= ~IO_ISDIRECT;
xfs_iunlock(xip, iolock);
goto relock;
}
} else { } else {
xfs_rw_enter_trace(XFS_WRITE_ENTER, xfs_rw_enter_trace(XFS_WRITE_ENTER, io, (void *)iovp, segs,
io, (void *)iovp, segs, *offset, ioflags); *offset, ioflags);
ret = generic_file_buffered_write(iocb, iovp, segs,
pos, offset, count, ret);
} }
ret = generic_file_aio_write_nolock(iocb, iovp, segs, offset);
current->backing_dev_info = NULL;
if ((ret == -ENOSPC) && if ((ret == -ENOSPC) &&
DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_NOSPACE) && DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_NOSPACE) &&
...@@ -821,17 +855,15 @@ xfs_write( ...@@ -821,17 +855,15 @@ xfs_write(
DM_RIGHT_NULL, vp, DM_RIGHT_NULL, NULL, NULL, DM_RIGHT_NULL, vp, DM_RIGHT_NULL, NULL, NULL,
0, 0, 0); /* Delay flag intentionally unused */ 0, 0, 0); /* Delay flag intentionally unused */
if (error) if (error)
return -error; goto out_unlock_isem;
xfs_rwlock(bdp, locktype); xfs_rwlock(bdp, locktype);
*offset = xip->i_d.di_size; pos = xip->i_d.di_size;
goto retry; goto retry;
} }
if (*offset > xip->i_d.di_size) { if (*offset > xip->i_d.di_size) {
xfs_ilock(xip, XFS_ILOCK_EXCL); xfs_ilock(xip, XFS_ILOCK_EXCL);
if (*offset > xip->i_d.di_size) { if (*offset > xip->i_d.di_size) {
struct inode *inode = LINVFS_GET_IP(vp);
xip->i_d.di_size = *offset; xip->i_d.di_size = *offset;
i_size_write(inode, *offset); i_size_write(inode, *offset);
xip->i_update_core = 1; xip->i_update_core = 1;
...@@ -840,23 +872,22 @@ xfs_write( ...@@ -840,23 +872,22 @@ xfs_write(
xfs_iunlock(xip, XFS_ILOCK_EXCL); xfs_iunlock(xip, XFS_ILOCK_EXCL);
} }
if (ret <= 0) { error = -ret;
xfs_rwunlock(bdp, locktype); if (ret <= 0)
return ret; goto out_unlock_internal;
}
XFS_STATS_ADD(xs_write_bytes, ret); XFS_STATS_ADD(xs_write_bytes, ret);
/* Handle various SYNC-type writes */ /* Handle various SYNC-type writes */
if ((file->f_flags & O_SYNC) || IS_SYNC(file->f_dentry->d_inode)) { if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) {
/* /*
* If we're treating this as O_DSYNC and we have not updated the * If we're treating this as O_DSYNC and we have not updated the
* size, force the log. * size, force the log.
*/ */
if (!(mp->m_flags & XFS_MOUNT_OSYNCISOSYNC) &&
!(xip->i_update_size)) {
xfs_inode_log_item_t *iip = xip->i_itemp;
if (!(mp->m_flags & XFS_MOUNT_OSYNCISOSYNC)
&& !(xip->i_update_size)) {
/* /*
* If an allocation transaction occurred * If an allocation transaction occurred
* without extending the size, then we have to force * without extending the size, then we have to force
...@@ -876,14 +907,8 @@ xfs_write( ...@@ -876,14 +907,8 @@ xfs_write(
* all changes affecting the inode are permanent * all changes affecting the inode are permanent
* when we return. * when we return.
*/ */
xfs_inode_log_item_t *iip;
xfs_lsn_t lsn;
iip = xip->i_itemp;
if (iip && iip->ili_last_lsn) { if (iip && iip->ili_last_lsn) {
lsn = iip->ili_last_lsn; xfs_log_force(mp, iip->ili_last_lsn,
xfs_log_force(mp, lsn,
XFS_LOG_FORCE | XFS_LOG_SYNC); XFS_LOG_FORCE | XFS_LOG_SYNC);
} else if (xfs_ipincount(xip) > 0) { } else if (xfs_ipincount(xip) > 0) {
xfs_log_force(mp, (xfs_lsn_t)0, xfs_log_force(mp, (xfs_lsn_t)0,
...@@ -924,12 +949,25 @@ xfs_write( ...@@ -924,12 +949,25 @@ xfs_write(
xfs_trans_set_sync(tp); xfs_trans_set_sync(tp);
error = xfs_trans_commit(tp, 0, NULL); error = xfs_trans_commit(tp, 0, NULL);
xfs_iunlock(xip, XFS_ILOCK_EXCL); xfs_iunlock(xip, XFS_ILOCK_EXCL);
if (error)
goto out_unlock_internal;
} }
} }
} /* (ioflags & O_SYNC) */
xfs_rwunlock(bdp, locktype); xfs_rwunlock(bdp, locktype);
return(ret);
error = sync_page_range(inode, mapping, pos, ret);
if (!error)
error = -ret;
goto out_unlock_isem;
}
out_unlock_internal:
xfs_rwunlock(bdp, locktype);
out_unlock_isem:
if (need_isem)
up(&inode->i_sem);
return -error;
} }
/* /*
......
...@@ -249,6 +249,36 @@ __xfs_dqtrace_entry( ...@@ -249,6 +249,36 @@ __xfs_dqtrace_entry(
#endif #endif
/*
* If default limits are in force, push them into the dquot now.
* We overwrite the dquot limits only if they are zero and this
* is not the root dquot.
*/
void
xfs_qm_adjust_dqlimits(
xfs_mount_t *mp,
xfs_disk_dquot_t *d)
{
xfs_quotainfo_t *q = mp->m_quotainfo;
ASSERT(!INT_ISZERO(d->d_id, ARCH_CONVERT));
if (q->qi_bsoftlimit && INT_ISZERO(d->d_blk_softlimit, ARCH_CONVERT))
INT_SET(d->d_blk_softlimit, ARCH_CONVERT, q->qi_bsoftlimit);
if (q->qi_bhardlimit && INT_ISZERO(d->d_blk_hardlimit, ARCH_CONVERT))
INT_SET(d->d_blk_hardlimit, ARCH_CONVERT, q->qi_bhardlimit);
if (q->qi_isoftlimit && INT_ISZERO(d->d_ino_softlimit, ARCH_CONVERT))
INT_SET(d->d_ino_softlimit, ARCH_CONVERT, q->qi_isoftlimit);
if (q->qi_ihardlimit && INT_ISZERO(d->d_ino_hardlimit, ARCH_CONVERT))
INT_SET(d->d_ino_hardlimit, ARCH_CONVERT, q->qi_ihardlimit);
if (q->qi_rtbsoftlimit &&
INT_ISZERO(d->d_rtb_softlimit, ARCH_CONVERT))
INT_SET(d->d_rtb_softlimit, ARCH_CONVERT, q->qi_rtbsoftlimit);
if (q->qi_rtbhardlimit &&
INT_ISZERO(d->d_rtb_hardlimit, ARCH_CONVERT))
INT_SET(d->d_rtb_hardlimit, ARCH_CONVERT, q->qi_rtbhardlimit);
}
/* /*
* Check the limits and timers of a dquot and start or reset timers * Check the limits and timers of a dquot and start or reset timers
* if necessary. * if necessary.
...@@ -265,53 +295,81 @@ xfs_qm_adjust_dqtimers( ...@@ -265,53 +295,81 @@ xfs_qm_adjust_dqtimers(
xfs_mount_t *mp, xfs_mount_t *mp,
xfs_disk_dquot_t *d) xfs_disk_dquot_t *d)
{ {
/* ASSERT(!INT_ISZERO(d->d_id, ARCH_CONVERT));
* The dquot had better be locked. We are modifying it here.
*/
/*
* root's limits are not real limits.
*/
if (INT_ISZERO(d->d_id, ARCH_CONVERT))
return;
#ifdef QUOTADEBUG #ifdef QUOTADEBUG
if (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)) if (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT))
ASSERT(INT_GET(d->d_blk_softlimit, ARCH_CONVERT) <= INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)); ASSERT(INT_GET(d->d_blk_softlimit, ARCH_CONVERT) <=
INT_GET(d->d_blk_hardlimit, ARCH_CONVERT));
if (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)) if (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT))
ASSERT(INT_GET(d->d_ino_softlimit, ARCH_CONVERT) <= INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)); ASSERT(INT_GET(d->d_ino_softlimit, ARCH_CONVERT) <=
INT_GET(d->d_ino_hardlimit, ARCH_CONVERT));
if (INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT))
ASSERT(INT_GET(d->d_rtb_softlimit, ARCH_CONVERT) <=
INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT));
#endif #endif
if (INT_ISZERO(d->d_btimer, ARCH_CONVERT)) { if (INT_ISZERO(d->d_btimer, ARCH_CONVERT)) {
if ((INT_GET(d->d_blk_softlimit, ARCH_CONVERT) && if ((INT_GET(d->d_blk_softlimit, ARCH_CONVERT) &&
(INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) || (INT_GET(d->d_bcount, ARCH_CONVERT) >=
INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) ||
(INT_GET(d->d_blk_hardlimit, ARCH_CONVERT) && (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT) &&
(INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) { (INT_GET(d->d_bcount, ARCH_CONVERT) >=
INT_SET(d->d_btimer, ARCH_CONVERT, get_seconds() + XFS_QI_BTIMELIMIT(mp)); INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) {
INT_SET(d->d_btimer, ARCH_CONVERT,
get_seconds() + XFS_QI_BTIMELIMIT(mp));
} }
} else { } else {
if ((INT_ISZERO(d->d_blk_softlimit, ARCH_CONVERT) || if ((INT_ISZERO(d->d_blk_softlimit, ARCH_CONVERT) ||
(INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) && (INT_GET(d->d_bcount, ARCH_CONVERT) <
INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) &&
(INT_ISZERO(d->d_blk_hardlimit, ARCH_CONVERT) || (INT_ISZERO(d->d_blk_hardlimit, ARCH_CONVERT) ||
(INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) { (INT_GET(d->d_bcount, ARCH_CONVERT) <
INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) {
INT_ZERO(d->d_btimer, ARCH_CONVERT); INT_ZERO(d->d_btimer, ARCH_CONVERT);
} }
} }
if (INT_ISZERO(d->d_itimer, ARCH_CONVERT)) { if (INT_ISZERO(d->d_itimer, ARCH_CONVERT)) {
if ((INT_GET(d->d_ino_softlimit, ARCH_CONVERT) && if ((INT_GET(d->d_ino_softlimit, ARCH_CONVERT) &&
(INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) || (INT_GET(d->d_icount, ARCH_CONVERT) >=
INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) ||
(INT_GET(d->d_ino_hardlimit, ARCH_CONVERT) && (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT) &&
(INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) { (INT_GET(d->d_icount, ARCH_CONVERT) >=
INT_SET(d->d_itimer, ARCH_CONVERT, get_seconds() + XFS_QI_ITIMELIMIT(mp)); INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) {
INT_SET(d->d_itimer, ARCH_CONVERT,
get_seconds() + XFS_QI_ITIMELIMIT(mp));
} }
} else { } else {
if ((INT_ISZERO(d->d_ino_softlimit, ARCH_CONVERT) || if ((INT_ISZERO(d->d_ino_softlimit, ARCH_CONVERT) ||
(INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) && (INT_GET(d->d_icount, ARCH_CONVERT) <
INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) &&
(INT_ISZERO(d->d_ino_hardlimit, ARCH_CONVERT) || (INT_ISZERO(d->d_ino_hardlimit, ARCH_CONVERT) ||
(INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) { (INT_GET(d->d_icount, ARCH_CONVERT) <
INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) {
INT_ZERO(d->d_itimer, ARCH_CONVERT); INT_ZERO(d->d_itimer, ARCH_CONVERT);
} }
} }
if (INT_ISZERO(d->d_rtbtimer, ARCH_CONVERT)) {
if ((INT_GET(d->d_rtb_softlimit, ARCH_CONVERT) &&
(INT_GET(d->d_rtbcount, ARCH_CONVERT) >=
INT_GET(d->d_rtb_softlimit, ARCH_CONVERT))) ||
(INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT) &&
(INT_GET(d->d_rtbcount, ARCH_CONVERT) >=
INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT)))) {
INT_SET(d->d_rtbtimer, ARCH_CONVERT,
get_seconds() + XFS_QI_RTBTIMELIMIT(mp));
}
} else {
if ((INT_ISZERO(d->d_rtb_softlimit, ARCH_CONVERT) ||
(INT_GET(d->d_rtbcount, ARCH_CONVERT) <
INT_GET(d->d_rtb_softlimit, ARCH_CONVERT))) &&
(INT_ISZERO(d->d_rtb_hardlimit, ARCH_CONVERT) ||
(INT_GET(d->d_rtbcount, ARCH_CONVERT) <
INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT)))) {
INT_ZERO(d->d_rtbtimer, ARCH_CONVERT);
}
}
} }
/* /*
......
...@@ -209,6 +209,8 @@ extern int xfs_qm_dqflock_nowait(xfs_dquot_t *); ...@@ -209,6 +209,8 @@ extern int xfs_qm_dqflock_nowait(xfs_dquot_t *);
extern void xfs_qm_dqflock_pushbuf_wait(xfs_dquot_t *dqp); extern void xfs_qm_dqflock_pushbuf_wait(xfs_dquot_t *dqp);
extern void xfs_qm_adjust_dqtimers(xfs_mount_t *, extern void xfs_qm_adjust_dqtimers(xfs_mount_t *,
xfs_disk_dquot_t *); xfs_disk_dquot_t *);
extern void xfs_qm_adjust_dqlimits(xfs_mount_t *,
xfs_disk_dquot_t *);
extern int xfs_qm_dqwarn(xfs_disk_dquot_t *, uint); extern int xfs_qm_dqwarn(xfs_disk_dquot_t *, uint);
extern int xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *, extern int xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *,
xfs_dqid_t, uint, uint, xfs_dquot_t **); xfs_dqid_t, uint, uint, xfs_dquot_t **);
......
...@@ -1213,21 +1213,45 @@ xfs_qm_init_quotainfo( ...@@ -1213,21 +1213,45 @@ xfs_qm_init_quotainfo(
XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN, XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN,
&dqp); &dqp);
if (! error) { if (! error) {
xfs_disk_dquot_t *ddqp = &dqp->q_core;
/* /*
* The warnings and timers set the grace period given to * The warnings and timers set the grace period given to
* a user or group before he or she can not perform any * a user or group before he or she can not perform any
* more writing. If it is zero, a default is used. * more writing. If it is zero, a default is used.
*/ */
qinf->qi_btimelimit = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) ? qinf->qi_btimelimit =
INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) : XFS_QM_BTIMELIMIT; INT_GET(ddqp->d_btimer, ARCH_CONVERT) ?
qinf->qi_itimelimit = INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) ? INT_GET(ddqp->d_btimer, ARCH_CONVERT) :
INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) : XFS_QM_ITIMELIMIT; XFS_QM_BTIMELIMIT;
qinf->qi_rtbtimelimit = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) ? qinf->qi_itimelimit =
INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) : XFS_QM_RTBTIMELIMIT; INT_GET(ddqp->d_itimer, ARCH_CONVERT) ?
qinf->qi_bwarnlimit = INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) ? INT_GET(ddqp->d_itimer, ARCH_CONVERT) :
INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) : XFS_QM_BWARNLIMIT; XFS_QM_ITIMELIMIT;
qinf->qi_iwarnlimit = INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) ? qinf->qi_rtbtimelimit =
INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) : XFS_QM_IWARNLIMIT; INT_GET(ddqp->d_rtbtimer, ARCH_CONVERT) ?
INT_GET(ddqp->d_rtbtimer, ARCH_CONVERT) :
XFS_QM_RTBTIMELIMIT;
qinf->qi_bwarnlimit =
INT_GET(ddqp->d_bwarns, ARCH_CONVERT) ?
INT_GET(ddqp->d_bwarns, ARCH_CONVERT) :
XFS_QM_BWARNLIMIT;
qinf->qi_iwarnlimit =
INT_GET(ddqp->d_iwarns, ARCH_CONVERT) ?
INT_GET(ddqp->d_iwarns, ARCH_CONVERT) :
XFS_QM_IWARNLIMIT;
qinf->qi_bhardlimit =
INT_GET(ddqp->d_blk_hardlimit, ARCH_CONVERT);
qinf->qi_bsoftlimit =
INT_GET(ddqp->d_blk_softlimit, ARCH_CONVERT);
qinf->qi_ihardlimit =
INT_GET(ddqp->d_ino_hardlimit, ARCH_CONVERT);
qinf->qi_isoftlimit =
INT_GET(ddqp->d_ino_softlimit, ARCH_CONVERT);
qinf->qi_rtbhardlimit =
INT_GET(ddqp->d_rtb_hardlimit, ARCH_CONVERT);
qinf->qi_rtbsoftlimit =
INT_GET(ddqp->d_rtb_softlimit, ARCH_CONVERT);
/* /*
* We sent the XFS_QMOPT_DQSUSER flag to dqget because * We sent the XFS_QMOPT_DQSUSER flag to dqget because
...@@ -1688,10 +1712,12 @@ xfs_qm_quotacheck_dqadjust( ...@@ -1688,10 +1712,12 @@ xfs_qm_quotacheck_dqadjust(
} }
/* /*
* Adjust the timers since we just changed usages * Set default limits, adjust timers (since we changed usages)
*/ */
if (! XFS_IS_SUSER_DQUOT(dqp)) if (! XFS_IS_SUSER_DQUOT(dqp)) {
xfs_qm_adjust_dqlimits(dqp->q_mount, &dqp->q_core);
xfs_qm_adjust_dqtimers(dqp->q_mount, &dqp->q_core); xfs_qm_adjust_dqtimers(dqp->q_mount, &dqp->q_core);
}
dqp->dq_flags |= XFS_DQ_DIRTY; dqp->dq_flags |= XFS_DQ_DIRTY;
} }
......
...@@ -136,9 +136,14 @@ typedef struct xfs_quotainfo { ...@@ -136,9 +136,14 @@ typedef struct xfs_quotainfo {
xfs_qwarncnt_t qi_bwarnlimit; /* limit for num warnings */ xfs_qwarncnt_t qi_bwarnlimit; /* limit for num warnings */
xfs_qwarncnt_t qi_iwarnlimit; /* limit for num warnings */ xfs_qwarncnt_t qi_iwarnlimit; /* limit for num warnings */
mutex_t qi_quotaofflock;/* to serialize quotaoff */ mutex_t qi_quotaofflock;/* to serialize quotaoff */
/* Some useful precalculated constants */
xfs_filblks_t qi_dqchunklen; /* # BBs in a chunk of dqs */ xfs_filblks_t qi_dqchunklen; /* # BBs in a chunk of dqs */
uint qi_dqperchunk; /* # ondisk dqs in above chunk */ uint qi_dqperchunk; /* # ondisk dqs in above chunk */
xfs_qcnt_t qi_bhardlimit; /* default data blk hard limit */
xfs_qcnt_t qi_bsoftlimit; /* default data blk soft limit */
xfs_qcnt_t qi_ihardlimit; /* default inode count hard limit */
xfs_qcnt_t qi_isoftlimit; /* default inode count soft limit */
xfs_qcnt_t qi_rtbhardlimit;/* default realtime blk hard limit */
xfs_qcnt_t qi_rtbsoftlimit;/* default realtime blk soft limit */
} xfs_quotainfo_t; } xfs_quotainfo_t;
......
...@@ -648,8 +648,11 @@ xfs_qm_scall_setqlim( ...@@ -648,8 +648,11 @@ xfs_qm_scall_setqlim(
if (hard == 0 || hard >= soft) { if (hard == 0 || hard >= soft) {
INT_SET(ddq->d_blk_hardlimit, ARCH_CONVERT, hard); INT_SET(ddq->d_blk_hardlimit, ARCH_CONVERT, hard);
INT_SET(ddq->d_blk_softlimit, ARCH_CONVERT, soft); INT_SET(ddq->d_blk_softlimit, ARCH_CONVERT, soft);
if (id == 0) {
mp->m_quotainfo->qi_bhardlimit = hard;
mp->m_quotainfo->qi_bsoftlimit = soft;
} }
else { } else {
qdprintk("blkhard %Ld < blksoft %Ld\n", hard, soft); qdprintk("blkhard %Ld < blksoft %Ld\n", hard, soft);
} }
hard = (newlim->d_fieldmask & FS_DQ_RTBHARD) ? hard = (newlim->d_fieldmask & FS_DQ_RTBHARD) ?
...@@ -661,9 +664,13 @@ xfs_qm_scall_setqlim( ...@@ -661,9 +664,13 @@ xfs_qm_scall_setqlim(
if (hard == 0 || hard >= soft) { if (hard == 0 || hard >= soft) {
INT_SET(ddq->d_rtb_hardlimit, ARCH_CONVERT, hard); INT_SET(ddq->d_rtb_hardlimit, ARCH_CONVERT, hard);
INT_SET(ddq->d_rtb_softlimit, ARCH_CONVERT, soft); INT_SET(ddq->d_rtb_softlimit, ARCH_CONVERT, soft);
if (id == 0) {
mp->m_quotainfo->qi_rtbhardlimit = hard;
mp->m_quotainfo->qi_rtbsoftlimit = soft;
} }
else } else {
qdprintk("rtbhard %Ld < rtbsoft %Ld\n", hard, soft); qdprintk("rtbhard %Ld < rtbsoft %Ld\n", hard, soft);
}
hard = (newlim->d_fieldmask & FS_DQ_IHARD) ? hard = (newlim->d_fieldmask & FS_DQ_IHARD) ?
(xfs_qcnt_t) newlim->d_ino_hardlimit : (xfs_qcnt_t) newlim->d_ino_hardlimit :
...@@ -674,27 +681,32 @@ xfs_qm_scall_setqlim( ...@@ -674,27 +681,32 @@ xfs_qm_scall_setqlim(
if (hard == 0 || hard >= soft) { if (hard == 0 || hard >= soft) {
INT_SET(ddq->d_ino_hardlimit, ARCH_CONVERT, hard); INT_SET(ddq->d_ino_hardlimit, ARCH_CONVERT, hard);
INT_SET(ddq->d_ino_softlimit, ARCH_CONVERT, soft); INT_SET(ddq->d_ino_softlimit, ARCH_CONVERT, soft);
if (id == 0) {
mp->m_quotainfo->qi_ihardlimit = hard;
mp->m_quotainfo->qi_isoftlimit = soft;
} }
else } else {
qdprintk("ihard %Ld < isoft %Ld\n", hard, soft); qdprintk("ihard %Ld < isoft %Ld\n", hard, soft);
}
if (id == 0) { if (id == 0) {
/* /*
* Timelimits for the super user set the relative time * Timelimits for the super user set the relative time
* the other users can be over quota for this file system. * the other users can be over quota for this file system.
* If it is zero a default is used. * If it is zero a default is used. Ditto for the default
* soft and hard limit values (already done, above).
*/ */
if (newlim->d_fieldmask & FS_DQ_BTIMER) { if (newlim->d_fieldmask & FS_DQ_BTIMER) {
mp->m_quotainfo->qi_btimelimit = newlim->d_btimer; mp->m_quotainfo->qi_btimelimit = newlim->d_btimer;
INT_SET(dqp->q_core.d_btimer, ARCH_CONVERT, newlim->d_btimer); INT_SET(ddq->d_btimer, ARCH_CONVERT, newlim->d_btimer);
} }
if (newlim->d_fieldmask & FS_DQ_ITIMER) { if (newlim->d_fieldmask & FS_DQ_ITIMER) {
mp->m_quotainfo->qi_itimelimit = newlim->d_itimer; mp->m_quotainfo->qi_itimelimit = newlim->d_itimer;
INT_SET(dqp->q_core.d_itimer, ARCH_CONVERT, newlim->d_itimer); INT_SET(ddq->d_itimer, ARCH_CONVERT, newlim->d_itimer);
} }
if (newlim->d_fieldmask & FS_DQ_RTBTIMER) { if (newlim->d_fieldmask & FS_DQ_RTBTIMER) {
mp->m_quotainfo->qi_rtbtimelimit = newlim->d_rtbtimer; mp->m_quotainfo->qi_rtbtimelimit = newlim->d_rtbtimer;
INT_SET(dqp->q_core.d_rtbtimer, ARCH_CONVERT, newlim->d_rtbtimer); INT_SET(ddq->d_rtbtimer, ARCH_CONVERT, newlim->d_rtbtimer);
} }
} else /* if (XFS_IS_QUOTA_ENFORCED(mp)) */ { } else /* if (XFS_IS_QUOTA_ENFORCED(mp)) */ {
/* /*
......
...@@ -452,9 +452,13 @@ xfs_trans_apply_dquot_deltas( ...@@ -452,9 +452,13 @@ xfs_trans_apply_dquot_deltas(
INT_MOD(d->d_rtbcount, ARCH_CONVERT, (xfs_qcnt_t)totalrtbdelta); INT_MOD(d->d_rtbcount, ARCH_CONVERT, (xfs_qcnt_t)totalrtbdelta);
/* /*
* Get any default limits in use.
* Start/reset the timer(s) if needed. * Start/reset the timer(s) if needed.
*/ */
if (!INT_ISZERO(d->d_id, ARCH_CONVERT)) {
xfs_qm_adjust_dqlimits(tp->t_mountp, d);
xfs_qm_adjust_dqtimers(tp->t_mountp, d); xfs_qm_adjust_dqtimers(tp->t_mountp, d);
}
dqp->dq_flags |= XFS_DQ_DIRTY; dqp->dq_flags |= XFS_DQ_DIRTY;
/* /*
...@@ -625,6 +629,7 @@ xfs_trans_unreserve_and_mod_dquots( ...@@ -625,6 +629,7 @@ xfs_trans_unreserve_and_mod_dquots(
STATIC int STATIC int
xfs_trans_dqresv( xfs_trans_dqresv(
xfs_trans_t *tp, xfs_trans_t *tp,
xfs_mount_t *mp,
xfs_dquot_t *dqp, xfs_dquot_t *dqp,
long nblks, long nblks,
long ninos, long ninos,
...@@ -635,6 +640,7 @@ xfs_trans_dqresv( ...@@ -635,6 +640,7 @@ xfs_trans_dqresv(
xfs_qcnt_t softlimit; xfs_qcnt_t softlimit;
time_t btimer; time_t btimer;
xfs_qcnt_t *resbcountp; xfs_qcnt_t *resbcountp;
xfs_quotainfo_t *q = mp->m_quotainfo;
if (! (flags & XFS_QMOPT_DQLOCK)) { if (! (flags & XFS_QMOPT_DQLOCK)) {
xfs_dqlock(dqp); xfs_dqlock(dqp);
...@@ -642,13 +648,21 @@ xfs_trans_dqresv( ...@@ -642,13 +648,21 @@ xfs_trans_dqresv(
ASSERT(XFS_DQ_IS_LOCKED(dqp)); ASSERT(XFS_DQ_IS_LOCKED(dqp));
if (flags & XFS_TRANS_DQ_RES_BLKS) { if (flags & XFS_TRANS_DQ_RES_BLKS) {
hardlimit = INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT); hardlimit = INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT);
if (!hardlimit)
hardlimit = q->qi_bhardlimit;
softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT); softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT);
if (!softlimit)
softlimit = q->qi_bsoftlimit;
btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT); btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT);
resbcountp = &dqp->q_res_bcount; resbcountp = &dqp->q_res_bcount;
} else { } else {
ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS); ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS);
hardlimit = INT_GET(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT); hardlimit = INT_GET(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT);
if (!hardlimit)
hardlimit = q->qi_rtbhardlimit;
softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT); softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT);
if (!softlimit)
softlimit = q->qi_rtbsoftlimit;
btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT); btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT);
resbcountp = &dqp->q_res_rtbcount; resbcountp = &dqp->q_res_rtbcount;
} }
...@@ -689,14 +703,18 @@ xfs_trans_dqresv( ...@@ -689,14 +703,18 @@ xfs_trans_dqresv(
} }
} }
if (ninos > 0) { if (ninos > 0) {
if (INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) > 0ULL && hardlimit = INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT);
INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= if (!hardlimit)
INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT)) { hardlimit = q->qi_ihardlimit;
softlimit = INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT);
if (!softlimit)
softlimit = q->qi_isoftlimit;
if (hardlimit > 0ULL &&
INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= hardlimit) {
error = EDQUOT; error = EDQUOT;
goto error_return; goto error_return;
} else if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) > 0ULL && } else if (softlimit > 0ULL &&
INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= softlimit) {
INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) {
/* /*
* If timer or warnings has expired, * If timer or warnings has expired,
* return EDQUOT * return EDQUOT
...@@ -786,19 +804,20 @@ xfs_trans_reserve_quota_bydquots( ...@@ -786,19 +804,20 @@ xfs_trans_reserve_quota_bydquots(
resvd = 0; resvd = 0;
if (udqp) { if (udqp) {
if (xfs_trans_dqresv(tp, udqp, nblks, ninos, flags)) if (xfs_trans_dqresv(tp, mp, udqp, nblks, ninos, flags))
return (EDQUOT); return (EDQUOT);
resvd = 1; resvd = 1;
} }
if (gdqp) { if (gdqp) {
if (xfs_trans_dqresv(tp, gdqp, nblks, ninos, flags)) { if (xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos, flags)) {
/* /*
* can't do it, so backout previous reservation * can't do it, so backout previous reservation
*/ */
if (resvd) { if (resvd) {
xfs_trans_dqresv(tp, udqp, -nblks, -ninos, flags |= XFS_QMOPT_FORCE_RES;
flags); xfs_trans_dqresv(tp, mp, udqp,
-nblks, -ninos, flags);
} }
return (EDQUOT); return (EDQUOT);
} }
......
...@@ -3427,19 +3427,20 @@ xfs_bmap_do_search_extents( ...@@ -3427,19 +3427,20 @@ xfs_bmap_do_search_extents(
int high; /* high index of binary search */ int high; /* high index of binary search */
int low; /* low index of binary search */ int low; /* low index of binary search */
/* Initialize the extent entry structure to catch access to /*
* Initialize the extent entry structure to catch access to
* uninitialized br_startblock field. * uninitialized br_startblock field.
*/ */
got.br_startoff = 0xffa5a5a5a5a5a5a5LL;
got.br_startoff = 0xffa5a5a5a5a5a5a5; got.br_blockcount = 0xa55a5a5a5a5a5a5aLL;
got.br_blockcount = 0xa55a5a5a5a5a5a5a;
got.br_state = XFS_EXT_INVALID; got.br_state = XFS_EXT_INVALID;
#if XFS_BIG_BLKNOS #if XFS_BIG_BLKNOS
got.br_startblock = 0xffffa5a5a5a5a5a5; got.br_startblock = 0xffffa5a5a5a5a5a5LL;
#else #else
got.br_startblock = 0xffffa5a5; got.br_startblock = 0xffffa5a5;
#endif #endif
if (lastx != NULLEXTNUM && lastx < nextents) if (lastx != NULLEXTNUM && lastx < nextents)
ep = base + lastx; ep = base + lastx;
else else
......
...@@ -142,6 +142,7 @@ xfs_growfs_data_private( ...@@ -142,6 +142,7 @@ xfs_growfs_data_private(
int dpct; int dpct;
int error; int error;
xfs_agnumber_t nagcount; xfs_agnumber_t nagcount;
xfs_agnumber_t nagimax = 0;
xfs_rfsblock_t nb, nb_mod; xfs_rfsblock_t nb, nb_mod;
xfs_rfsblock_t new; xfs_rfsblock_t new;
xfs_rfsblock_t nfree; xfs_rfsblock_t nfree;
...@@ -183,7 +184,7 @@ xfs_growfs_data_private( ...@@ -183,7 +184,7 @@ xfs_growfs_data_private(
memset(&mp->m_perag[oagcount], 0, memset(&mp->m_perag[oagcount], 0,
(nagcount - oagcount) * sizeof(xfs_perag_t)); (nagcount - oagcount) * sizeof(xfs_perag_t));
mp->m_flags |= XFS_MOUNT_32BITINODES; mp->m_flags |= XFS_MOUNT_32BITINODES;
xfs_initialize_perag(mp, nagcount); nagimax = xfs_initialize_perag(mp, nagcount);
up_write(&mp->m_peraglock); up_write(&mp->m_peraglock);
} }
tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS); tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS);
...@@ -372,6 +373,9 @@ xfs_growfs_data_private( ...@@ -372,6 +373,9 @@ xfs_growfs_data_private(
if (error) { if (error) {
return error; return error;
} }
/* New allocation groups fully initialized, so update mount struct */
if (nagimax)
mp->m_maxagi = nagimax;
if (mp->m_sb.sb_imax_pct) { if (mp->m_sb.sb_imax_pct) {
__uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct; __uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct;
do_div(icount, 100); do_div(icount, 100);
......
...@@ -2047,12 +2047,11 @@ xfs_qm_dqcheck( ...@@ -2047,12 +2047,11 @@ xfs_qm_dqcheck(
errs++; errs++;
} }
if (! errs) { if (! errs && !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) {
if (INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT) && if (INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT) &&
INT_GET(ddq->d_bcount, ARCH_CONVERT) >= INT_GET(ddq->d_bcount, ARCH_CONVERT) >=
INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT)) { INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT)) {
if (INT_ISZERO(ddq->d_btimer, ARCH_CONVERT) && if (INT_ISZERO(ddq->d_btimer, ARCH_CONVERT)) {
!INT_ISZERO(ddq->d_id, ARCH_CONVERT)) {
if (flags & XFS_QMOPT_DOWARN) if (flags & XFS_QMOPT_DOWARN)
cmn_err(CE_ALERT, cmn_err(CE_ALERT,
"%s : Dquot ID 0x%x (0x%p) " "%s : Dquot ID 0x%x (0x%p) "
...@@ -2065,8 +2064,7 @@ xfs_qm_dqcheck( ...@@ -2065,8 +2064,7 @@ xfs_qm_dqcheck(
if (INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT) && if (INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT) &&
INT_GET(ddq->d_icount, ARCH_CONVERT) >= INT_GET(ddq->d_icount, ARCH_CONVERT) >=
INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT)) { INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT)) {
if (INT_ISZERO(ddq->d_itimer, ARCH_CONVERT) && if (INT_ISZERO(ddq->d_itimer, ARCH_CONVERT)) {
!INT_ISZERO(ddq->d_id, ARCH_CONVERT)) {
if (flags & XFS_QMOPT_DOWARN) if (flags & XFS_QMOPT_DOWARN)
cmn_err(CE_ALERT, cmn_err(CE_ALERT,
"%s : Dquot ID 0x%x (0x%p) " "%s : Dquot ID 0x%x (0x%p) "
...@@ -2076,6 +2074,19 @@ xfs_qm_dqcheck( ...@@ -2076,6 +2074,19 @@ xfs_qm_dqcheck(
errs++; errs++;
} }
} }
if (INT_GET(ddq->d_rtb_softlimit, ARCH_CONVERT) &&
INT_GET(ddq->d_rtbcount, ARCH_CONVERT) >=
INT_GET(ddq->d_rtb_softlimit, ARCH_CONVERT)) {
if (INT_ISZERO(ddq->d_rtbtimer, ARCH_CONVERT)) {
if (flags & XFS_QMOPT_DOWARN)
cmn_err(CE_ALERT,
"%s : Dquot ID 0x%x (0x%p) "
"RTBLK TIMER NOT STARTED",
str, (int)
INT_GET(ddq->d_id, ARCH_CONVERT), ddq);
errs++;
}
}
} }
if (!errs || !(flags & XFS_QMOPT_DQREPAIR)) if (!errs || !(flags & XFS_QMOPT_DQREPAIR))
......
...@@ -318,10 +318,10 @@ xfs_mount_validate_sb( ...@@ -318,10 +318,10 @@ xfs_mount_validate_sb(
return 0; return 0;
} }
void xfs_agnumber_t
xfs_initialize_perag(xfs_mount_t *mp, int agcount) xfs_initialize_perag(xfs_mount_t *mp, xfs_agnumber_t agcount)
{ {
int index, max_metadata; xfs_agnumber_t index, max_metadata;
xfs_perag_t *pag; xfs_perag_t *pag;
xfs_agino_t agino; xfs_agino_t agino;
xfs_ino_t ino; xfs_ino_t ino;
...@@ -377,7 +377,7 @@ xfs_initialize_perag(xfs_mount_t *mp, int agcount) ...@@ -377,7 +377,7 @@ xfs_initialize_perag(xfs_mount_t *mp, int agcount)
pag->pagi_inodeok = 1; pag->pagi_inodeok = 1;
} }
} }
mp->m_maxagi = index; return index;
} }
/* /*
...@@ -951,7 +951,7 @@ xfs_mountfs( ...@@ -951,7 +951,7 @@ xfs_mountfs(
mp->m_perag = mp->m_perag =
kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t), KM_SLEEP); kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t), KM_SLEEP);
xfs_initialize_perag(mp, sbp->sb_agcount); mp->m_maxagi = xfs_initialize_perag(mp, sbp->sb_agcount);
/* /*
* log's mount-time initialization. Perform 1st part recovery if needed * log's mount-time initialization. Perform 1st part recovery if needed
......
...@@ -551,7 +551,7 @@ extern int xfs_readsb(xfs_mount_t *mp); ...@@ -551,7 +551,7 @@ extern int xfs_readsb(xfs_mount_t *mp);
extern void xfs_freesb(xfs_mount_t *); extern void xfs_freesb(xfs_mount_t *);
extern void xfs_do_force_shutdown(bhv_desc_t *, int, char *, int); extern void xfs_do_force_shutdown(bhv_desc_t *, int, char *, int);
extern int xfs_syncsub(xfs_mount_t *, int, int, int *); extern int xfs_syncsub(xfs_mount_t *, int, int, int *);
extern void xfs_initialize_perag(xfs_mount_t *, int); extern xfs_agnumber_t xfs_initialize_perag(xfs_mount_t *, xfs_agnumber_t);
extern void xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t, extern void xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t,
__int64_t); __int64_t);
......
...@@ -283,7 +283,7 @@ xfs_getattr( ...@@ -283,7 +283,7 @@ xfs_getattr(
/* /*
* xfs_setattr * xfs_setattr
*/ */
STATIC int int
xfs_setattr( xfs_setattr(
bhv_desc_t *bdp, bhv_desc_t *bdp,
vattr_t *vap, vattr_t *vap,
...@@ -305,6 +305,7 @@ xfs_setattr( ...@@ -305,6 +305,7 @@ xfs_setattr(
int mandlock_before, mandlock_after; int mandlock_before, mandlock_after;
struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2;
int file_owner; int file_owner;
int need_iolock = (flags & ATTR_DMI) == 0;
vp = BHV_TO_VNODE(bdp); vp = BHV_TO_VNODE(bdp);
vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
...@@ -406,6 +407,7 @@ xfs_setattr( ...@@ -406,6 +407,7 @@ xfs_setattr(
goto error_return; goto error_return;
} }
} }
if (need_iolock)
lock_flags |= XFS_IOLOCK_EXCL; lock_flags |= XFS_IOLOCK_EXCL;
} }
...@@ -678,6 +680,7 @@ xfs_setattr( ...@@ -678,6 +680,7 @@ xfs_setattr(
XFS_TRANS_PERM_LOG_RES, XFS_TRANS_PERM_LOG_RES,
XFS_ITRUNCATE_LOG_COUNT))) { XFS_ITRUNCATE_LOG_COUNT))) {
xfs_trans_cancel(tp, 0); xfs_trans_cancel(tp, 0);
if (need_iolock)
xfs_iunlock(ip, XFS_IOLOCK_EXCL); xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return code; return code;
} }
...@@ -4297,6 +4300,7 @@ xfs_free_file_space( ...@@ -4297,6 +4300,7 @@ xfs_free_file_space(
int rt; int rt;
xfs_fileoff_t startoffset_fsb; xfs_fileoff_t startoffset_fsb;
xfs_trans_t *tp; xfs_trans_t *tp;
int need_iolock = (attr_flags & ATTR_DMI) == 0;
vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address); vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address);
mp = ip->i_mount; mp = ip->i_mount;
...@@ -4324,6 +4328,7 @@ xfs_free_file_space( ...@@ -4324,6 +4328,7 @@ xfs_free_file_space(
return(error); return(error);
} }
if (need_iolock)
xfs_ilock(ip, XFS_IOLOCK_EXCL); xfs_ilock(ip, XFS_IOLOCK_EXCL);
rounding = MAX((__uint8_t)(1 << mp->m_sb.sb_blocklog), rounding = MAX((__uint8_t)(1 << mp->m_sb.sb_blocklog),
(__uint8_t)NBPP); (__uint8_t)NBPP);
...@@ -4342,10 +4347,8 @@ xfs_free_file_space( ...@@ -4342,10 +4347,8 @@ xfs_free_file_space(
nimap = 1; nimap = 1;
error = xfs_bmapi(NULL, ip, startoffset_fsb, 1, 0, NULL, 0, error = xfs_bmapi(NULL, ip, startoffset_fsb, 1, 0, NULL, 0,
&imap, &nimap, NULL); &imap, &nimap, NULL);
if (error) { if (error)
xfs_iunlock(ip, XFS_IOLOCK_EXCL); goto out_unlock_iolock;
return error;
}
ASSERT(nimap == 0 || nimap == 1); ASSERT(nimap == 0 || nimap == 1);
if (nimap && imap.br_startblock != HOLESTARTBLOCK) { if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
xfs_daddr_t block; xfs_daddr_t block;
...@@ -4359,10 +4362,8 @@ xfs_free_file_space( ...@@ -4359,10 +4362,8 @@ xfs_free_file_space(
nimap = 1; nimap = 1;
error = xfs_bmapi(NULL, ip, endoffset_fsb - 1, 1, 0, NULL, 0, error = xfs_bmapi(NULL, ip, endoffset_fsb - 1, 1, 0, NULL, 0,
&imap, &nimap, NULL); &imap, &nimap, NULL);
if (error) { if (error)
xfs_iunlock(ip, XFS_IOLOCK_EXCL); goto out_unlock_iolock;
return error;
}
ASSERT(nimap == 0 || nimap == 1); ASSERT(nimap == 0 || nimap == 1);
if (nimap && imap.br_startblock != HOLESTARTBLOCK) { if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
ASSERT(imap.br_startblock != DELAYSTARTBLOCK); ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
...@@ -4451,6 +4452,8 @@ xfs_free_file_space( ...@@ -4451,6 +4452,8 @@ xfs_free_file_space(
xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(ip, XFS_ILOCK_EXCL);
} }
out_unlock_iolock:
if (need_iolock)
xfs_iunlock(ip, XFS_IOLOCK_EXCL); xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return error; return error;
...@@ -4458,7 +4461,8 @@ xfs_free_file_space( ...@@ -4458,7 +4461,8 @@ xfs_free_file_space(
xfs_bmap_cancel(&free_list); xfs_bmap_cancel(&free_list);
error1: error1:
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); xfs_iunlock(ip, need_iolock ? (XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL) :
XFS_ILOCK_EXCL);
return error; return error;
} }
...@@ -4615,6 +4619,7 @@ xfs_change_file_space( ...@@ -4615,6 +4619,7 @@ xfs_change_file_space(
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
xfs_trans_ihold(tp, ip); xfs_trans_ihold(tp, ip);
if ((attr_flags & ATTR_DMI) == 0) {
ip->i_d.di_mode &= ~S_ISUID; ip->i_d.di_mode &= ~S_ISUID;
/* /*
...@@ -4628,7 +4633,7 @@ xfs_change_file_space( ...@@ -4628,7 +4633,7 @@ xfs_change_file_space(
ip->i_d.di_mode &= ~S_ISGID; ip->i_d.di_mode &= ~S_ISGID;
xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
}
if (setprealloc) if (setprealloc)
ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC;
else if (clrprealloc) else if (clrprealloc)
......
...@@ -277,6 +277,7 @@ int sync_page_range(struct inode *inode, struct address_space *mapping, ...@@ -277,6 +277,7 @@ int sync_page_range(struct inode *inode, struct address_space *mapping,
ret = wait_on_page_writeback_range(mapping, start, end); ret = wait_on_page_writeback_range(mapping, start, end);
return ret; return ret;
} }
EXPORT_SYMBOL(sync_page_range);
/** /**
* filemap_fdatawait - walk the list of under-writeback pages of the given * filemap_fdatawait - walk the list of under-writeback pages of the given
......
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