]> git.hungrycats.org Git - linux/commitdiff
[XFS] Separate the quota source into its own subdirectory ala dmapi.
authorChristoph Hellwig <hch@sgi.com>
Wed, 26 Mar 2003 20:04:20 +0000 (21:04 +0100)
committerNathan Scott <nathans@sgi.com>
Wed, 26 Mar 2003 20:04:20 +0000 (21:04 +0100)
Push a bunch of quota- and dmapi-specific code down into these
subdirs which previously was compiled into the core XFS code,
and don't descend into these subdirs if options config'd off.

SGI Modid: 2.5.x-xfs:slinx:141850a

51 files changed:
fs/xfs/Makefile
fs/xfs/linux/xfs_file.c
fs/xfs/linux/xfs_globals.c
fs/xfs/linux/xfs_globals.h
fs/xfs/linux/xfs_iomap.c
fs/xfs/linux/xfs_lrw.c
fs/xfs/linux/xfs_stats.c
fs/xfs/linux/xfs_stats.h
fs/xfs/linux/xfs_super.c
fs/xfs/linux/xfs_super.h
fs/xfs/linux/xfs_vfs.c
fs/xfs/linux/xfs_vfs.h
fs/xfs/quota/xfs_dquot.c [new file with mode: 0644]
fs/xfs/quota/xfs_dquot.h [new file with mode: 0644]
fs/xfs/quota/xfs_dquot_item.c [new file with mode: 0644]
fs/xfs/quota/xfs_dquot_item.h [new file with mode: 0644]
fs/xfs/quota/xfs_qm.c [new file with mode: 0644]
fs/xfs/quota/xfs_qm.h [new file with mode: 0644]
fs/xfs/quota/xfs_qm_bhv.c [new file with mode: 0644]
fs/xfs/quota/xfs_qm_stats.c [new file with mode: 0644]
fs/xfs/quota/xfs_qm_stats.h [new file with mode: 0644]
fs/xfs/quota/xfs_qm_syscalls.c [new file with mode: 0644]
fs/xfs/quota/xfs_quota_priv.h [new file with mode: 0644]
fs/xfs/quota/xfs_trans_dquot.c [new file with mode: 0644]
fs/xfs/xfs.h
fs/xfs/xfs_attr.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_bmap_btree.c
fs/xfs/xfs_dmapi.h
fs/xfs/xfs_dmops.c
fs/xfs/xfs_dquot.c [deleted file]
fs/xfs/xfs_dquot.h [deleted file]
fs/xfs/xfs_dquot_item.c [deleted file]
fs/xfs/xfs_dquot_item.h [deleted file]
fs/xfs/xfs_iget.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_qm.c [deleted file]
fs/xfs/xfs_qm.h [deleted file]
fs/xfs/xfs_qm_syscalls.c [deleted file]
fs/xfs/xfs_qmops.c
fs/xfs/xfs_quota.h
fs/xfs/xfs_quota_priv.h [deleted file]
fs/xfs/xfs_rename.c
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans_dquot.c [deleted file]
fs/xfs/xfs_utils.c
fs/xfs/xfs_vfsops.c
fs/xfs/xfs_vnodeops.c
fs/xfs/xfsidbg.c

index 15b2ed01ae30c14e0089a791f5e47f0c3a4eb852..738ebec594dc80a7645684d6358e4b5ba9e1d307 100644 (file)
@@ -29,8 +29,6 @@
 #
 # http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
 #
-# Makefile for XFS on Linux.
-#
 
 EXTRA_CFLAGS +=         -Ifs/xfs -funsigned-char
 
@@ -44,18 +42,22 @@ endif
 obj-$(CONFIG_XFS_FS)           += xfs.o
 
 
-xfs-$(CONFIG_XFS_RT)           += xfs_rtalloc.o
-
-xfs-$(CONFIG_XFS_QUOTA)                += xfs_dquot.o \
+xfs-$(CONFIG_XFS_QUOTA)                += $(addprefix quota/, \
+                                  xfs_dquot.o \
                                   xfs_dquot_item.o \
                                   xfs_trans_dquot.o \
                                   xfs_qm_syscalls.o \
-                                  xfs_qmops.o \
-                                  xfs_qm.o
+                                  xfs_qm_bhv.o \
+                                  xfs_qm.o)
 
+ifeq ($(CONFIG_XFS_QUOTA),y)
+xfs-$(CONFIG_PROC_FS)          += quota/xfs_qm_stats.o
+endif
+
+xfs-$(CONFIG_XFS_RT)           += xfs_rtalloc.o
 xfs-$(CONFIG_XFS_POSIX_ACL)    += xfs_acl.o
-xfs-$(CONFIG_FS_POSIX_CAP)     += xfs_cap.o
-xfs-$(CONFIG_FS_POSIX_MAC)     += xfs_mac.o
+xfs-$(CONFIG_XFS_POSIX_CAP)    += xfs_cap.o
+xfs-$(CONFIG_XFS_POSIX_MAC)    += xfs_mac.o
 xfs-$(CONFIG_PROC_FS)          += linux/xfs_stats.o
 xfs-$(CONFIG_SYSCTL)           += linux/xfs_sysctl.o
 
@@ -137,6 +139,10 @@ xfs-y                              += $(addprefix support/, \
                                   qsort.o \
                                   uuid.o)
 
+# Quota and DMAPI stubs
+xfs-y                          += xfs_dmops.o \
+                                  xfs_qmops.o
+
 # If both xfs and kdb modules are built in then xfsidbg is built in.  If xfs is
 # a module and kdb modules are being compiled then xfsidbg must be a module, to
 # follow xfs.  If xfs is built in then xfsidbg tracks the kdb module state.
index 25d6df57e0ab13c66008c9db033659080f955e36..0331e582c8305b30565adbfee049e5d0ee865667 100644 (file)
@@ -299,7 +299,9 @@ linvfs_file_mmap(
        int             error;
 
        if ((vp->v_type == VREG) && (vp->v_vfsp->vfs_flag & VFS_DMI)) {
-               error = -xfs_dm_send_mmap_event(vma, 0);
+               xfs_mount_t     *mp = XFS_VFSTOM(vp->v_vfsp);
+
+               error = -XFS_SEND_MMAP(mp, vma, 0);
                if (error)
                        return error;
        }
@@ -345,8 +347,10 @@ linvfs_mprotect(
 
        if ((vp->v_type == VREG) && (vp->v_vfsp->vfs_flag & VFS_DMI)) {
                if ((vma->vm_flags & VM_MAYSHARE) &&
-                   (newflags & PROT_WRITE) && !(vma->vm_flags & PROT_WRITE)){
-                       error = xfs_dm_send_mmap_event(vma, VM_WRITE);
+                   (newflags & PROT_WRITE) && !(vma->vm_flags & PROT_WRITE)) {
+                       xfs_mount_t     *mp = XFS_VFSTOM(vp->v_vfsp);
+
+                       error = XFS_SEND_MMAP(mp, vma, VM_WRITE);
                    }
        }
        return error;
index 40fd5618f1002c6137cea620b0e9d009396d8612..6b253bfccc6045820f1c3ffa6a748ad482988277 100644 (file)
@@ -58,17 +58,7 @@ spinlock_t Atomic_spin = SPIN_LOCK_UNLOCKED;
  */
 cred_t sys_cred_val, *sys_cred = &sys_cred_val;
 
-/*
- * The global quota manager. There is only one of these for the entire
- * system, _not_ one per file system. XQM keeps track of the overall
- * quota functionality, including maintaining the freelist and hash
- * tables of dquots.
- */
-struct xfs_qm  *xfs_Gqm;
-mutex_t                xfs_Gqm_lock;
-
 /* Export XFS symbols used by xfsidbg */
-EXPORT_SYMBOL(xfs_Gqm);
 EXPORT_SYMBOL(xfs_next_bit);
 EXPORT_SYMBOL(xfs_contig_bits);
 EXPORT_SYMBOL(xfs_bmbt_get_all);
index 07c9856b1353192402ec1d4eaa7f2c5170965629..22999bcfdb3bfec9c9c032bcc3ce8c9a523f11fe 100644 (file)
@@ -43,7 +43,4 @@ extern unsigned long  xfs_physmem;
 
 extern struct cred *sys_cred;
 
-extern struct xfs_qm   *xfs_Gqm;
-extern mutex_t         xfs_Gqm_lock;
-
 #endif /* __XFS_GLOBALS_H__ */
index cc1ab771ede0ebb5ec90bcb6d8f13c7759fcb729..a96e2141e141c611c6c4e556fb086a0481007dce 100644 (file)
@@ -258,11 +258,10 @@ xfs_iomap_write_direct(
         * the ilock across a disk read.
         */
 
-       if (XFS_IS_QUOTA_ON(mp) && XFS_NOT_DQATTACHED(mp, ip)) {
-               if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED))) {
-                       return XFS_ERROR(error);
-               }
-       }
+       error = XFS_QM_DQATTACH(ip->i_mount, ip, XFS_QMOPT_ILOCKED);
+       if (error)
+               return XFS_ERROR(error);
+
        maps = min(XFS_WRITE_IMAPS, *nmaps);
        nimaps = maps;
 
@@ -291,7 +290,7 @@ xfs_iomap_write_direct(
         * determine if reserving space on
         * the data or realtime partition.
         */
-       if ((rt = ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) {
+       if ((rt = XFS_IS_REALTIME_INODE(ip))) {
                int     sbrtextsize, iprtextsize;
 
                sbrtextsize = mp->m_sb.sb_rextsize;
@@ -333,11 +332,9 @@ xfs_iomap_write_direct(
                goto error_out; /* Don't return in above if .. trans ..,
                                        need lock to return */
 
-       if (XFS_IS_QUOTA_ON(mp)) {
-               if (xfs_trans_reserve_blkquota(tp, ip, resblks)) {
-                       error = (EDQUOT);
-                       goto error1;
-               }
+       if (XFS_TRANS_RESERVE_BLKQUOTA(mp, tp, ip, resblks)) {
+               error = (EDQUOT);
+               goto error1;
        }
        nimaps = 1;
 
@@ -422,11 +419,9 @@ xfs_iomap_write_delay(
         * the ilock across a disk read.
         */
 
-       if (XFS_IS_QUOTA_ON(mp) && XFS_NOT_DQATTACHED(mp, ip)) {
-               if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED))) {
-                       return XFS_ERROR(error);
-               }
-       }
+       error = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED);
+       if (error)
+               return XFS_ERROR(error);
 
 retry:
        isize = ip->i_d.di_size;
@@ -538,11 +533,8 @@ xfs_iomap_write_allocate(
         * Make sure that the dquots are there.
         */
 
-       if (XFS_IS_QUOTA_ON(mp) && XFS_NOT_DQATTACHED(mp, ip)) {
-               if ((error = xfs_qm_dqattach(ip, 0))) {
-                       return XFS_ERROR(error);
-               }
-       }
+       if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+               return XFS_ERROR(error);
 
        offset_fsb = map->br_startoff;
        count_fsb = map->br_blockcount;
index 214ac45c2485e693002e3ef5d9723c51f4ecb009..2ee9f08d87216541ff56ef1f4e3a015e52dc51ef 100644 (file)
@@ -121,7 +121,8 @@ xfs_read(
        xfs_mount_t             *mp;
        vnode_t                 *vp;
        unsigned long           seg;
-       int                     direct = filp->f_flags & O_DIRECT;
+       int                     direct = (filp->f_flags & O_DIRECT);
+       int                     invisible = (filp->f_mode & FINVIS);
 
        ip = XFS_BHVTOI(bdp);
        vp = BHV_TO_VNODE(bdp);
@@ -180,13 +181,12 @@ xfs_read(
 
        xfs_ilock(ip, XFS_IOLOCK_SHARED);
 
-       if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) &&
-           !(filp->f_mode & FINVIS)) {
+       if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) && !invisible) {
                int error;
                vrwlock_t locktype = VRWLOCK_READ;
 
-               error = xfs_dm_send_data_event(DM_EVENT_READ, bdp, *offp,
-                               size, FILP_DELAY_FLAG(filp), &locktype);
+               error = XFS_SEND_DATA(mp, DM_EVENT_READ, bdp, *offp, size,
+                                     FILP_DELAY_FLAG(filp), &locktype);
                if (error) {
                        xfs_iunlock(ip, XFS_IOLOCK_SHARED);
                        return -error;
@@ -198,7 +198,7 @@ xfs_read(
 
        XFS_STATS_ADD(xfsstats.xs_read_bytes, ret);
 
-       if (!(filp->f_mode & FINVIS))
+       if (!invisible)
                xfs_ichgtime(ip, XFS_ICHGTIME_ACC);
 
        return ret;
@@ -217,11 +217,13 @@ xfs_sendfile(
        ssize_t                 ret;
        xfs_fsize_t             n;
        xfs_inode_t             *ip;
+       xfs_mount_t             *mp;
        vnode_t                 *vp;
        int                     invisible = (filp->f_mode & FINVIS);
 
        ip = XFS_BHVTOI(bdp);
        vp = BHV_TO_VNODE(bdp);
+       mp = ip->i_mount;
        vn_trace_entry(vp, "xfs_sendfile", (inst_t *)__return_address);
 
        XFS_STATS_INC(xfsstats.xs_read_calls);
@@ -241,8 +243,8 @@ xfs_sendfile(
                vrwlock_t locktype = VRWLOCK_READ;
                int error;
 
-               error = xfs_dm_send_data_event(DM_EVENT_READ, bdp, *offp,
-                               count, FILP_DELAY_FLAG(filp), &locktype);
+               error = XFS_SEND_DATA(mp, DM_EVENT_READ, bdp, *offp, count,
+                                     FILP_DELAY_FLAG(filp), &locktype);
                if (error) {
                        xfs_iunlock(ip, XFS_IOLOCK_SHARED);
                        return -error;
@@ -493,7 +495,8 @@ xfs_write(
        vnode_t                 *vp;
        unsigned long           seg;
        int                     iolock;
-       int                     direct = file->f_flags & O_DIRECT;
+       int                     direct = (file->f_flags & O_DIRECT);
+       int                     invisible = (file->f_mode & FINVIS);
        int                     eventsent = 0;
        vrwlock_t               locktype;
 
@@ -573,13 +576,13 @@ start:
        }
 
        if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) &&
-           !(file->f_mode & FINVIS) && !eventsent)) {
+           !invisible && !eventsent)) {
                loff_t          savedsize = *offset;
 
                xfs_iunlock(xip, XFS_ILOCK_EXCL);
-               error = xfs_dm_send_data_event(DM_EVENT_WRITE, bdp,
-                               *offset, size,
-                               FILP_DELAY_FLAG(file), &locktype);
+               error = XFS_SEND_DATA(xip->i_mount, DM_EVENT_WRITE, bdp,
+                                     *offset, size,
+                                     FILP_DELAY_FLAG(file), &locktype);
                if (error) {
                        xfs_iunlock(xip, iolock);
                        return -error;
@@ -588,12 +591,11 @@ start:
                eventsent = 1;
 
                /*
-                * The iolock was dropped and reaquired in
-                * xfs_dm_send_data_event so we have to recheck the size
-                *  when appending.  We will only "goto start;" once,
-                *  since having sent the event prevents another call
-                *  to xfs_dm_send_data_event, which is what
-                *  allows the size to change in the first place.
+                * The iolock was dropped and reaquired in XFS_SEND_DATA
+                * so we have to recheck the size when appending.
+                * We will only "goto start;" once, since having sent the
+                * event prevents another call to XFS_SEND_DATA, which is
+                * what allows the size to change in the first place.
                 */
                if ((file->f_flags & O_APPEND) &&
                    savedsize != xip->i_d.di_size) {
@@ -608,10 +610,8 @@ start:
         *
         * We must update xfs' times since revalidate will overcopy xfs.
         */
-       if (size) {
-               if (!(file->f_mode & FINVIS))
-                       xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-       }
+       if (size && !invisible)
+               xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 
        /*
         * If the offset is beyond the size of the file, we have a couple
@@ -658,11 +658,10 @@ retry:
        ret = generic_file_write_nolock(file, iovp, segs, offset);
 
        if ((ret == -ENOSPC) &&
-           DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_NOSPACE) &&
-           !(file->f_mode & FINVIS)) {
+           DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_NOSPACE) && !invisible) {
 
                xfs_rwunlock(bdp, locktype);
-               error = dm_send_namesp_event(DM_EVENT_NOSPACE, bdp,
+               error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, bdp,
                                DM_RIGHT_NULL, bdp, DM_RIGHT_NULL, NULL, NULL,
                                0, 0, 0); /* Delay flag intentionally  unused */
                if (error)
index 578d5bb0b4cfc4fa13c0edbadc70befea366241c..5face9af532be216ead0165bfb914e5d677df349 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -61,7 +61,6 @@ xfs_read_xfsstats(
                { "xstrat",             XFSSTAT_END_WRITE_CONVERT       },
                { "rw",                 XFSSTAT_END_READ_WRITE_OPS      },
                { "attr",               XFSSTAT_END_ATTRIBUTE_OPS       },
-               { "qm",                 XFSSTAT_END_QUOTA_OPS           },
                { "icluster",           XFSSTAT_END_INODE_CLUSTER       },
                { "vnodes",             XFSSTAT_END_VNODE_OPS           },
        };
@@ -95,50 +94,17 @@ xfs_read_xfsstats(
        return len;
 }
 
-STATIC int
-xfs_read_xfsquota(
-       char            *buffer,
-       char            **start,
-       off_t           offset,
-       int             count,
-       int             *eof,
-       void            *data)
-{
-       int             len;
-
-       /* maximum; incore; ratio free to inuse; freelist */
-       len = sprintf(buffer, "%d\t%d\t%d\t%u\n",
-                       ndquot,
-                       xfs_Gqm? atomic_read(&xfs_Gqm->qm_totaldquots) : 0,
-                       xfs_Gqm? xfs_Gqm->qm_dqfree_ratio : 0,
-                       xfs_Gqm? xfs_Gqm->qm_dqfreelist.qh_nelems : 0);
-
-       if (offset >= len) {
-               *start = buffer;
-               *eof = 1;
-               return 0;
-       }
-       *start = buffer + offset;
-       if ((len -= offset) > count)
-               return count;
-       *eof = 1;
-
-       return len;
-}
-
 void
 xfs_init_procfs(void)
 {
        if (!proc_mkdir("fs/xfs", 0))
                return;
        create_proc_read_entry("fs/xfs/stat", 0, 0, xfs_read_xfsstats, NULL);
-       create_proc_read_entry("fs/xfs/xqm", 0, 0, xfs_read_xfsquota, NULL);
 }
 
 void
 xfs_cleanup_procfs(void)
 {
        remove_proc_entry("fs/xfs/stat", NULL);
-       remove_proc_entry("fs/xfs/xqm", NULL);
        remove_proc_entry("fs/xfs", NULL);
 }
index c4192e35482bc86c18145f80409eaecc65ffd70a..c5eb3b848c5a28d4c12f7e27dc2057314b4274ce 100644 (file)
@@ -107,16 +107,7 @@ struct xfsstats {
        __uint32_t              xs_attr_set;
        __uint32_t              xs_attr_remove;
        __uint32_t              xs_attr_list;
-# define XFSSTAT_END_QUOTA_OPS         (XFSSTAT_END_ATTRIBUTE_OPS+8)
-       __uint32_t              xs_qm_dqreclaims;
-       __uint32_t              xs_qm_dqreclaim_misses;
-       __uint32_t              xs_qm_dquot_dups;
-       __uint32_t              xs_qm_dqcachemisses;
-       __uint32_t              xs_qm_dqcachehits;
-       __uint32_t              xs_qm_dqwants;
-       __uint32_t              xs_qm_dqshake_reclaims;
-       __uint32_t              xs_qm_dqinact_reclaims;
-# define XFSSTAT_END_INODE_CLUSTER     (XFSSTAT_END_QUOTA_OPS+3)
+# define XFSSTAT_END_INODE_CLUSTER     (XFSSTAT_END_ATTRIBUTE_OPS+3)
        __uint32_t              xs_iflush_count;
        __uint32_t              xs_icluster_flushcnt;
        __uint32_t              xs_icluster_flushinode;
index fdb38f6640b1644e14943b94e8d8a228a38aeecf..161c8f64b4c273effe3f1f3480be53aa634398ec 100644 (file)
@@ -953,33 +953,27 @@ init_xfs_fs( void )
        error = init_inodecache();
        if (error < 0)
                goto undo_inodecache;
+
        error = pagebuf_init();
        if (error < 0)
                goto undo_pagebuf;
 
        vn_init();
        xfs_init();
-
-       error = vfs_initdmapi();
-       if (error < 0)
-               goto undo_dmapi;
-       error = vfs_initquota();
-       if (error < 0)
-               goto undo_quota;
+       vfs_initdmapi();
+       vfs_initquota();
 
        error = register_filesystem(&xfs_fs_type);
        if (error)
-               goto undo_fs;
+               goto undo_register;
        return 0;
 
-undo_fs:
-       vfs_exitquota();
-undo_quota:
-       vfs_exitdmapi();
-undo_dmapi:
+undo_register:
        pagebuf_terminate();
+
 undo_pagebuf:
        destroy_inodecache();
+
 undo_inodecache:
        return error;
 }
index 49328bf8ef60783ed7d5d058a33cd82f36307369..a12506a0151fe0204578ba0e437c5b21139d817d 100644 (file)
 #ifndef __XFS_SUPER_H__
 #define __XFS_SUPER_H__
 
-#ifdef CONFIG_XFS_POSIX_ACL
-# define XFS_ACL_STRING                "ACLs, "
-# define set_posix_acl_flag(sb)        ((sb)->s_flags |= MS_POSIXACL)
-#else
-# define XFS_ACL_STRING
-# define set_posix_acl_flag(sb)        do { } while (0)
-#endif
-
 #ifdef CONFIG_XFS_DMAPI
-# define XFS_DMAPI_STRING      "DMAPI, "
-# define vfs_insertdmapi(vfs)  vfs_insertops(vfsp, &xfs_dmops_xfs)
-# define vfs_initdmapi()       (0)                     /* temporarily */
-# define vfs_exitdmapi()       do { } while (0)        /* temporarily */
+# define vfs_insertdmapi(vfs)  vfs_insertops(vfsp, &xfs_dmops)
+# define vfs_initdmapi()       xfs_dm_init()
+# define vfs_exitdmapi()       xfs_dm_exit()
 #else
-# define XFS_DMAPI_STRING
 # define vfs_insertdmapi(vfs)  do { } while (0)
-# define vfs_initdmapi()       (0)
+# define vfs_initdmapi()       do { } while (0)
 # define vfs_exitdmapi()       do { } while (0)
 #endif
 
 #ifdef CONFIG_XFS_QUOTA
-# define XFS_QUOTA_STRING      "quota, "
-# define vfs_insertquota(vfs)  vfs_insertops(vfsp, &xfs_qmops_xfs)
-# define vfs_initquota()       (0)                     /* temporarily */
-# define vfs_exitquota()       do { } while (0)        /* temporarily */
+# define vfs_insertquota(vfs)  vfs_insertops(vfsp, &xfs_qmops)
+# define vfs_initquota()       xfs_qm_init()
+# define vfs_exitquota()       xfs_qm_exit()
 #else
-# define XFS_QUOTA_STRING
 # define vfs_insertquota(vfs)  do { } while (0)
-# define vfs_initquota()       (0)
+# define vfs_initquota()       do { } while (0)
 # define vfs_exitquota()       do { } while (0)
 #endif
 
+#ifdef CONFIG_XFS_POSIX_ACL
+# define XFS_ACL_STRING                "ACLs, "
+# define set_posix_acl_flag(sb)        ((sb)->s_flags |= MS_POSIXACL)
+#else
+# define XFS_ACL_STRING
+# define set_posix_acl_flag(sb)        do { } while (0)
+#endif
+
 #ifdef CONFIG_XFS_RT
-# define XFS_RT_STRING         "realtime, "
+# define XFS_REALTIME_STRING   "realtime, "
 #else
-# define XFS_RT_STRING
+# define XFS_REALTIME_STRING
 #endif
 
 #ifdef CONFIG_XFS_VNODE_TRACING
@@ -82,9 +78,9 @@
 # define XFS_DBG_STRING                "no debug"
 #endif
 
-#define XFS_BUILD_OPTIONS      XFS_ACL_STRING XFS_DMAPI_STRING \
-                               XFS_RT_STRING \
-                               XFS_QUOTA_STRING XFS_VNTRACE_STRING \
+#define XFS_BUILD_OPTIONS      XFS_ACL_STRING \
+                               XFS_REALTIME_STRING \
+                               XFS_VNTRACE_STRING \
                                XFS_DBG_STRING /* DBG must be last */
 
 #define LINVFS_GET_VFS(s) \
index c4350b2118715d66f0b9a5f026f969e9599a3517..17e6988bc7f8d77d8f196bef620422058eaf8c15 100644 (file)
@@ -222,7 +222,7 @@ vfs_deallocate(
 void
 vfs_insertops(
        struct vfs              *vfsp,
-       struct vfsops           *vfsops)
+       struct bhv_vfsops       *vfsops)
 {
        struct bhv_desc         *bdp;
 
index 36ab51724c468ef0eda36bb8e2eb141ca8f429f8..b18e6424b67c8209f56607d018e0504bb0bc7af9 100644 (file)
@@ -165,9 +165,19 @@ extern int vfs_quotactl(bhv_desc_t *, int, int, caddr_t);
 extern void vfs_init_vnode(bhv_desc_t *, struct vnode *, bhv_desc_t *, int);
 extern void vfs_force_shutdown(bhv_desc_t *, int, char *, int);
 
+typedef struct bhv_vfsops {
+       struct vfsops           bhv_common;
+       void *                  bhv_custom;
+} bhv_vfsops_t;
+
+#define vfs_bhv_lookup(v, id)  ( bhv_lookup_range(&(v)->vfs_bh, (id), (id)) )
+#define vfs_bhv_custom(b)      ( ((bhv_vfsops_t *)BHV_OPS(b))->bhv_custom )
+#define vfs_bhv_set_custom(b,o)        ( (b)->bhv_custom = (void *)(o))
+#define vfs_bhv_clr_custom(b)  ( (b)->bhv_custom = NULL )
+
 extern vfs_t *vfs_allocate(void);
 extern void vfs_deallocate(vfs_t *);
-extern void vfs_insertops(vfs_t *, vfsops_t *);
+extern void vfs_insertops(vfs_t *, bhv_vfsops_t *);
 extern void vfs_insertbhv(vfs_t *, bhv_desc_t *, vfsops_t *, void *);
 
 extern void bhv_insert_all_vfsops(struct vfs *);
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c
new file mode 100644 (file)
index 0000000..bd7e1e6
--- /dev/null
@@ -0,0 +1,1552 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.         Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+#include "xfs_qm.h"
+
+
+/*
+   LOCK ORDER
+
+   inode lock              (ilock)
+   dquot hash-chain lock    (hashlock)
+   xqm dquot freelist lock  (freelistlock
+   mount's dquot list lock  (mplistlock)
+   user dquot lock - lock ordering among dquots is based on the uid or gid
+   group dquot lock - similar to udquots. Between the two dquots, the udquot
+                     has to be locked first.
+   pin lock - the dquot lock must be held to take this lock.
+   flush lock - ditto.
+*/
+
+STATIC void            xfs_qm_dqflush_done(xfs_buf_t *, xfs_dq_logitem_t *);
+
+#ifdef DEBUG
+dev_t xfs_dqerror_dev = 0;
+int xfs_do_dqerror = 0;
+int xfs_dqreq_num = 0;
+int xfs_dqerror_mod = 33;
+#endif
+
+/*
+ * Allocate and initialize a dquot. We don't always allocate fresh memory;
+ * we try to reclaim a free dquot if the number of incore dquots are above
+ * a threshold.
+ * The only field inside the core that gets initialized at this point
+ * is the d_id field. The idea is to fill in the entire q_core
+ * when we read in the on disk dquot.
+ */
+xfs_dquot_t *
+xfs_qm_dqinit(
+       xfs_mount_t  *mp,
+       xfs_dqid_t   id,
+       uint         type)
+{
+       xfs_dquot_t     *dqp;
+       boolean_t       brandnewdquot;
+
+       brandnewdquot = xfs_qm_dqalloc_incore(&dqp);
+       dqp->dq_flags = type;
+       INT_SET(dqp->q_core.d_id, ARCH_CONVERT, id);
+       dqp->q_mount = mp;
+
+       /*
+        * No need to re-initialize these if this is a reclaimed dquot.
+        */
+       if (brandnewdquot) {
+               dqp->dq_flnext = dqp->dq_flprev = dqp;
+               mutex_init(&dqp->q_qlock,  MUTEX_DEFAULT, "xdq");
+               initnsema(&dqp->q_flock, 1, "fdq");
+               sv_init(&dqp->q_pinwait, SV_DEFAULT, "pdq");
+
+#ifdef DQUOT_TRACING
+               dqp->q_trace = ktrace_alloc(DQUOT_TRACE_SIZE, KM_SLEEP);
+               xfs_dqtrace_entry(dqp, "DQINIT");
+#endif
+       } else {
+               /*
+                * Only the q_core portion was zeroed in dqreclaim_one().
+                * So, we need to reset others.
+                */
+                dqp->q_nrefs = 0;
+                dqp->q_blkno = 0;
+                dqp->MPL_NEXT = dqp->HL_NEXT = NULL;
+                dqp->HL_PREVP = dqp->MPL_PREVP = NULL;
+                dqp->q_bufoffset = 0;
+                dqp->q_fileoffset = 0;
+                dqp->q_transp = NULL;
+                dqp->q_gdquot = NULL;
+                dqp->q_res_bcount = 0;
+                dqp->q_res_icount = 0;
+                dqp->q_res_rtbcount = 0;
+                dqp->q_pincount = 0;
+                dqp->q_hash = 0;
+                ASSERT(dqp->dq_flnext == dqp->dq_flprev);
+
+#ifdef DQUOT_TRACING
+                ASSERT(dqp->q_trace);
+                xfs_dqtrace_entry(dqp, "DQRECLAIMED_INIT");
+#endif
+        }
+
+       /*
+        * log item gets initialized later
+        */
+       return (dqp);
+}
+
+/*
+ * This is called to free all the memory associated with a dquot
+ */
+void
+xfs_qm_dqdestroy(
+       xfs_dquot_t     *dqp)
+{
+       ASSERT(! XFS_DQ_IS_ON_FREELIST(dqp));
+
+       mutex_destroy(&dqp->q_qlock);
+       freesema(&dqp->q_flock);
+       sv_destroy(&dqp->q_pinwait);
+
+#ifdef DQUOT_TRACING
+       if (dqp->q_trace)
+            ktrace_free(dqp->q_trace);
+       dqp->q_trace = NULL;
+#endif
+       kmem_zone_free(xfs_Gqm->qm_dqzone, dqp);
+       atomic_dec(&xfs_Gqm->qm_totaldquots);
+}
+
+/*
+ * This is what a 'fresh' dquot inside a dquot chunk looks like on disk.
+ */
+STATIC void
+xfs_qm_dqinit_core(
+       xfs_dqid_t       id,
+       uint             type,
+       xfs_dqblk_t      *d)
+{
+       /*
+        * Caller has zero'd the entire dquot 'chunk' already.
+        */
+       INT_SET(d->dd_diskdq.d_magic, ARCH_CONVERT, XFS_DQUOT_MAGIC);
+       INT_SET(d->dd_diskdq.d_version, ARCH_CONVERT, XFS_DQUOT_VERSION);
+       INT_SET(d->dd_diskdq.d_id, ARCH_CONVERT, id);
+       INT_SET(d->dd_diskdq.d_flags, ARCH_CONVERT, type);
+}
+
+
+#ifdef DQUOT_TRACING
+/*
+ * Dquot tracing for debugging.
+ */
+/* ARGSUSED */
+void
+xfs_dqtrace_entry__(
+       xfs_dquot_t *dqp,
+       char *func,
+       void *retaddr,
+       xfs_inode_t *ip)
+{
+       xfs_dquot_t *udqp = NULL;
+       int ino;
+
+       ASSERT(dqp->q_trace);
+       if (ip) {
+               ino = ip->i_ino;
+               udqp = ip->i_udquot;
+       }
+       ktrace_enter(dqp->q_trace,
+                    (void *)(__psint_t)DQUOT_KTRACE_ENTRY,
+                    (void *)func,
+                    (void *)(__psint_t)dqp->q_nrefs,
+                    (void *)(__psint_t)dqp->dq_flags,
+                    (void *)(__psint_t)dqp->q_res_bcount,
+                    (void *)(__psint_t)INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT),
+                    (void *)(__psint_t)INT_GET(dqp->q_core.d_icount, ARCH_CONVERT),
+                    (void *)(__psint_t)INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT),
+                    (void *)(__psint_t)INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT),
+                    (void *)(__psint_t)INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT),
+                    (void *)(__psint_t)INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT),
+                    (void *)(__psint_t)INT_GET(dqp->q_core.d_id, ARCH_CONVERT), /* 11 */
+                    (void *)(__psint_t)current_pid(),
+                    (void *)(__psint_t)ino,
+                    (void *)(__psint_t)retaddr,
+                    (void *)(__psint_t)udqp);
+       return;
+}
+#endif
+
+
+/*
+ * Check the limits and timers of a dquot and start or reset timers
+ * if necessary.
+ * This gets called even when quota enforcement is OFF, which makes our
+ * life a little less complicated. (We just don't reject any quota
+ * reservations in that case, when enforcement is off).
+ * We also return 0 as the values of the timers in Q_GETQUOTA calls, when
+ * enforcement's off.
+ * In contrast, warnings are a little different in that they don't
+ * 'automatically' get started when limits get exceeded.
+ */
+void
+xfs_qm_adjust_dqtimers(
+       xfs_mount_t             *mp,
+       xfs_disk_dquot_t        *d)
+{
+       /*
+        * 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
+       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));
+       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));
+#endif
+       if (INT_ISZERO(d->d_btimer, 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_blk_hardlimit, ARCH_CONVERT) &&
+                   (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) {
+                       INT_SET(d->d_btimer, ARCH_CONVERT, get_seconds() + XFS_QI_BTIMELIMIT(mp));
+               }
+       } else {
+               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_ISZERO(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);
+               }
+       }
+
+       if (INT_ISZERO(d->d_itimer, 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_ino_hardlimit, ARCH_CONVERT) &&
+                   (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) {
+                       INT_SET(d->d_itimer, ARCH_CONVERT, get_seconds() + XFS_QI_ITIMELIMIT(mp));
+               }
+       } else {
+               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_ISZERO(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);
+               }
+       }
+}
+
+/*
+ * Increment or reset warnings of a given dquot.
+ */
+int
+xfs_qm_dqwarn(
+       xfs_disk_dquot_t        *d,
+       uint                    flags)
+{
+       int     warned;
+
+       /*
+        * root's limits are not real limits.
+        */
+       if (INT_ISZERO(d->d_id, ARCH_CONVERT))
+               return (0);
+
+       warned = 0;
+       if (INT_GET(d->d_blk_softlimit, ARCH_CONVERT) &&
+           (INT_GET(d->d_bcount, ARCH_CONVERT) >=
+            INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) {
+               if (flags & XFS_QMOPT_DOWARN) {
+                       INT_MOD(d->d_bwarns, ARCH_CONVERT, +1);
+                       warned++;
+               }
+       } else {
+               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_ZERO(d->d_bwarns, ARCH_CONVERT);
+               }
+       }
+
+       if (INT_GET(d->d_ino_softlimit, ARCH_CONVERT) > 0 &&
+           (INT_GET(d->d_icount, ARCH_CONVERT) >=
+            INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) {
+               if (flags & XFS_QMOPT_DOWARN) {
+                       INT_MOD(d->d_iwarns, ARCH_CONVERT, +1);
+                       warned++;
+               }
+       } else {
+               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_ZERO(d->d_iwarns, ARCH_CONVERT);
+               }
+       }
+#ifdef QUOTADEBUG
+       if (INT_GET(d->d_iwarns, ARCH_CONVERT))
+               cmn_err(CE_DEBUG,
+                       "--------@@Inode warnings running : %Lu >= %Lu",
+                       INT_GET(d->d_icount, ARCH_CONVERT),
+                       INT_GET(d->d_ino_softlimit, ARCH_CONVERT));
+       if (INT_GET(d->d_bwarns, ARCH_CONVERT))
+               cmn_err(CE_DEBUG,
+                       "--------@@Blks warnings running : %Lu >= %Lu",
+                       INT_GET(d->d_bcount, ARCH_CONVERT),
+                       INT_GET(d->d_blk_softlimit, ARCH_CONVERT));
+#endif
+       return (warned);
+}
+
+
+/*
+ * initialize a buffer full of dquots and log the whole thing
+ */
+STATIC void
+xfs_qm_init_dquot_blk(
+       xfs_trans_t     *tp,
+       xfs_mount_t     *mp,
+       xfs_dqid_t      id,
+       uint            type,
+       xfs_buf_t       *bp)
+{
+       xfs_dqblk_t     *d;
+       int             curid, i;
+
+       ASSERT(tp);
+       ASSERT(XFS_BUF_ISBUSY(bp));
+       ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
+
+       d = (xfs_dqblk_t *)XFS_BUF_PTR(bp);
+
+       /*
+        * ID of the first dquot in the block - id's are zero based.
+        */
+       curid = id - (id % XFS_QM_DQPERBLK(mp));
+       ASSERT(curid >= 0);
+       memset(d, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)));
+       for (i = 0; i < XFS_QM_DQPERBLK(mp); i++, d++, curid++)
+               xfs_qm_dqinit_core(curid, type, d);
+       xfs_trans_dquot_buf(tp, bp,
+                           type & XFS_DQ_USER ?
+                           XFS_BLI_UDQUOT_BUF :
+                           XFS_BLI_GDQUOT_BUF);
+       xfs_trans_log_buf(tp, bp, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1);
+}
+
+
+
+/*
+ * Allocate a block and fill it with dquots.
+ * This is called when the bmapi finds a hole.
+ */
+STATIC int
+xfs_qm_dqalloc(
+       xfs_trans_t     *tp,
+       xfs_mount_t     *mp,
+       xfs_dquot_t     *dqp,
+       xfs_inode_t     *quotip,
+       xfs_fileoff_t   offset_fsb,
+       xfs_buf_t       **O_bpp)
+{
+       xfs_fsblock_t   firstblock;
+       xfs_bmap_free_t flist;
+       xfs_bmbt_irec_t map;
+       int             nmaps, error, committed;
+       xfs_buf_t       *bp;
+
+       ASSERT(tp != NULL);
+       xfs_dqtrace_entry(dqp, "DQALLOC");
+
+       /*
+        * Initialize the bmap freelist prior to calling bmapi code.
+        */
+       XFS_BMAP_INIT(&flist, &firstblock);
+       xfs_ilock(quotip, XFS_ILOCK_EXCL);
+       /*
+        * Return if this type of quotas is turned off while we didn't
+        * have an inode lock
+        */
+       if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
+               xfs_iunlock(quotip, XFS_ILOCK_EXCL);
+               return (ESRCH);
+       }
+
+       /*
+        * xfs_trans_commit normally decrements the vnode ref count
+        * when it unlocks the inode. Since we want to keep the quota
+        * inode around, we bump the vnode ref count now.
+        */
+       VN_HOLD(XFS_ITOV(quotip));
+
+       xfs_trans_ijoin(tp, quotip, XFS_ILOCK_EXCL);
+       nmaps = 1;
+       if ((error = xfs_bmapi(tp, quotip,
+                             offset_fsb, XFS_DQUOT_CLUSTER_SIZE_FSB,
+                             XFS_BMAPI_METADATA | XFS_BMAPI_WRITE,
+                             &firstblock,
+                             XFS_QM_DQALLOC_SPACE_RES(mp),
+                             &map, &nmaps, &flist))) {
+               goto error0;
+       }
+       ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB);
+       ASSERT(nmaps == 1);
+       ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
+              (map.br_startblock != HOLESTARTBLOCK));
+
+       /*
+        * Keep track of the blkno to save a lookup later
+        */
+       dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock);
+
+       /* now we can just get the buffer (there's nothing to read yet) */
+       bp = xfs_trans_get_buf(tp, mp->m_ddev_targp,
+                              dqp->q_blkno,
+                              XFS_QI_DQCHUNKLEN(mp),
+                              0);
+       if (!bp || (error = XFS_BUF_GETERROR(bp)))
+               goto error1;
+       /*
+        * Make a chunk of dquots out of this buffer and log
+        * the entire thing.
+        */
+       xfs_qm_init_dquot_blk(tp, mp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT),
+                             dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP),
+                             bp);
+
+       if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) {
+               goto error1;
+       }
+
+       *O_bpp = bp;
+       return 0;
+
+      error1:
+       xfs_bmap_cancel(&flist);
+      error0:
+       xfs_iunlock(quotip, XFS_ILOCK_EXCL);
+
+       return (error);
+}
+
+/*
+ * Maps a dquot to the buffer containing its on-disk version.
+ * This returns a ptr to the buffer containing the on-disk dquot
+ * in the bpp param, and a ptr to the on-disk dquot within that buffer
+ */
+STATIC int
+xfs_qm_dqtobp(
+       xfs_trans_t             *tp,
+       xfs_dquot_t             *dqp,
+       xfs_disk_dquot_t        **O_ddpp,
+       xfs_buf_t               **O_bpp,
+       uint                    flags)
+{
+       xfs_bmbt_irec_t map;
+       int             nmaps, error;
+       xfs_buf_t       *bp;
+       xfs_inode_t     *quotip;
+       xfs_mount_t     *mp;
+       xfs_disk_dquot_t *ddq;
+       xfs_dqid_t      id;
+       boolean_t       newdquot;
+
+       mp = dqp->q_mount;
+       id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT);
+       nmaps = 1;
+       newdquot = B_FALSE;
+
+       /*
+        * If we don't know where the dquot lives, find out.
+        */
+       if (dqp->q_blkno == (xfs_daddr_t) 0) {
+               /* We use the id as an index */
+               dqp->q_fileoffset = (xfs_fileoff_t) ((uint)id /
+                                                    XFS_QM_DQPERBLK(mp));
+               nmaps = 1;
+               quotip = XFS_DQ_TO_QIP(dqp);
+               xfs_ilock(quotip, XFS_ILOCK_SHARED);
+               /*
+                * Return if this type of quotas is turned off while we didn't
+                * have an inode lock
+                */
+               if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
+                       xfs_iunlock(quotip, XFS_ILOCK_SHARED);
+                       return (ESRCH);
+               }
+               /*
+                * Find the block map; no allocations yet
+                */
+               error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset,
+                                 XFS_DQUOT_CLUSTER_SIZE_FSB,
+                                 XFS_BMAPI_METADATA,
+                                 NULL, 0, &map, &nmaps, NULL);
+
+               xfs_iunlock(quotip, XFS_ILOCK_SHARED);
+               if (error)
+                       return (error);
+               ASSERT(nmaps == 1);
+               ASSERT(map.br_blockcount == 1);
+
+               /*
+                * offset of dquot in the (fixed sized) dquot chunk.
+                */
+               dqp->q_bufoffset = (id % XFS_QM_DQPERBLK(mp)) *
+                       sizeof(xfs_dqblk_t);
+               if (map.br_startblock == HOLESTARTBLOCK) {
+                       /*
+                        * We don't allocate unless we're asked to
+                        */
+                       if (!(flags & XFS_QMOPT_DQALLOC))
+                               return (ENOENT);
+
+                       ASSERT(tp);
+                       if ((error = xfs_qm_dqalloc(tp, mp, dqp, quotip,
+                                               dqp->q_fileoffset, &bp)))
+                               return (error);
+                       newdquot = B_TRUE;
+               } else {
+                       /*
+                        * store the blkno etc so that we don't have to do the
+                        * mapping all the time
+                        */
+                       dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock);
+               }
+       }
+       ASSERT(dqp->q_blkno != DELAYSTARTBLOCK);
+       ASSERT(dqp->q_blkno != HOLESTARTBLOCK);
+
+       /*
+        * Read in the buffer, unless we've just done the allocation
+        * (in which case we already have the buf).
+        */
+       if (! newdquot) {
+               xfs_dqtrace_entry(dqp, "DQTOBP READBUF");
+               if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
+                                              dqp->q_blkno,
+                                              XFS_QI_DQCHUNKLEN(mp),
+                                              0, &bp))) {
+                       return (error);
+               }
+               if (error || !bp)
+                       return XFS_ERROR(error);
+       }
+       ASSERT(XFS_BUF_ISBUSY(bp));
+       ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
+
+       /*
+        * calculate the location of the dquot inside the buffer.
+        */
+       ddq = (xfs_disk_dquot_t *)((char *)XFS_BUF_PTR(bp) + dqp->q_bufoffset);
+
+       /*
+        * A simple sanity check in case we got a corrupted dquot...
+        */
+       if (xfs_qm_dqcheck(ddq, id,
+                          dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP),
+                          flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN),
+                          "dqtobp")) {
+               if (!(flags & XFS_QMOPT_DQREPAIR)) {
+                       xfs_trans_brelse(tp, bp);
+                       return XFS_ERROR(EIO);
+               }
+               XFS_BUF_BUSY(bp); /* We dirtied this */
+       }
+
+       *O_bpp = bp;
+       *O_ddpp = ddq;
+
+       return (0);
+}
+
+
+/*
+ * Read in the ondisk dquot using dqtobp() then copy it to an incore version,
+ * and release the buffer immediately.
+ *
+ */
+/* ARGSUSED */
+STATIC int
+xfs_qm_dqread(
+       xfs_trans_t     *tp,
+       xfs_dqid_t      id,
+       xfs_dquot_t     *dqp,   /* dquot to get filled in */
+       uint            flags)
+{
+       xfs_disk_dquot_t *ddqp;
+       xfs_buf_t        *bp;
+       int              error;
+
+       /*
+        * get a pointer to the on-disk dquot and the buffer containing it
+        * dqp already knows its own type (GROUP/USER).
+        */
+       xfs_dqtrace_entry(dqp, "DQREAD");
+       if ((error = xfs_qm_dqtobp(tp, dqp, &ddqp, &bp, flags))) {
+               return (error);
+       }
+
+       /* copy everything from disk dquot to the incore dquot */
+       memcpy(&dqp->q_core, ddqp, sizeof(xfs_disk_dquot_t));
+       ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id);
+       xfs_qm_dquot_logitem_init(dqp);
+
+       /*
+        * Reservation counters are defined as reservation plus current usage
+        * to avoid having to add everytime.
+        */
+       dqp->q_res_bcount = INT_GET(ddqp->d_bcount, ARCH_CONVERT);
+       dqp->q_res_icount = INT_GET(ddqp->d_icount, ARCH_CONVERT);
+       dqp->q_res_rtbcount = INT_GET(ddqp->d_rtbcount, ARCH_CONVERT);
+
+       /* Mark the buf so that this will stay incore a little longer */
+       XFS_BUF_SET_VTYPE_REF(bp, B_FS_DQUOT, XFS_DQUOT_REF);
+
+       /*
+        * We got the buffer with a xfs_trans_read_buf() (in dqtobp())
+        * So we need to release with xfs_trans_brelse().
+        * The strategy here is identical to that of inodes; we lock
+        * the dquot in xfs_qm_dqget() before making it accessible to
+        * others. This is because dquots, like inodes, need a good level of
+        * concurrency, and we don't want to take locks on the entire buffers
+        * for dquot accesses.
+        * Note also that the dquot buffer may even be dirty at this point, if
+        * this particular dquot was repaired. We still aren't afraid to
+        * brelse it because we have the changes incore.
+        */
+       ASSERT(XFS_BUF_ISBUSY(bp));
+       ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
+       xfs_trans_brelse(tp, bp);
+
+       return (error);
+}
+
+
+/*
+ * allocate an incore dquot from the kernel heap,
+ * and fill its core with quota information kept on disk.
+ * If XFS_QMOPT_DQALLOC is set, it'll allocate a dquot on disk
+ * if it wasn't already allocated.
+ */
+STATIC int
+xfs_qm_idtodq(
+       xfs_mount_t     *mp,
+       xfs_dqid_t      id,      /* gid or uid, depending on type */
+       uint            type,    /* UDQUOT or GDQUOT */
+       uint            flags,   /* DQALLOC, DQREPAIR */
+       xfs_dquot_t     **O_dqpp)/* OUT : incore dquot, not locked */
+{
+       xfs_dquot_t     *dqp;
+       int             error;
+       xfs_trans_t     *tp;
+       int             cancelflags=0;
+
+       dqp = xfs_qm_dqinit(mp, id, type);
+       tp = NULL;
+       if (flags & XFS_QMOPT_DQALLOC) {
+               tp = xfs_trans_alloc(mp, XFS_TRANS_QM_DQALLOC);
+               if ((error = xfs_trans_reserve(tp,
+                                      XFS_QM_DQALLOC_SPACE_RES(mp),
+                                      XFS_WRITE_LOG_RES(mp) +
+                                             BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1 +
+                                             128,
+                                      0,
+                                      XFS_TRANS_PERM_LOG_RES,
+                                      XFS_WRITE_LOG_COUNT))) {
+                       cancelflags = 0;
+                       goto error0;
+               }
+               cancelflags = XFS_TRANS_RELEASE_LOG_RES;
+       }
+
+       /*
+        * Read it from disk; xfs_dqread() takes care of
+        * all the necessary initialization of dquot's fields (locks, etc)
+        */
+       if ((error = xfs_qm_dqread(tp, id, dqp, flags))) {
+               /*
+                * This can happen if quotas got turned off (ESRCH),
+                * or if the dquot didn't exist on disk and we ask to
+                * allocate (ENOENT).
+                */
+               xfs_dqtrace_entry(dqp, "DQREAD FAIL");
+               cancelflags |= XFS_TRANS_ABORT;
+               goto error0;
+       }
+       if (tp) {
+               if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
+                                            NULL)))
+                       goto error1;
+       }
+
+       *O_dqpp = dqp;
+       ASSERT(! XFS_DQ_IS_LOCKED(dqp));
+       return (0);
+
+ error0:
+       ASSERT(error);
+       if (tp)
+               xfs_trans_cancel(tp, cancelflags);
+ error1:
+       xfs_qm_dqdestroy(dqp);
+       *O_dqpp = NULL;
+       return (error);
+}
+
+/*
+ * Lookup a dquot in the incore dquot hashtable. We keep two separate
+ * hashtables for user and group dquots; and, these are global tables
+ * inside the XQM, not per-filesystem tables.
+ * The hash chain must be locked by caller, and it is left locked
+ * on return. Returning dquot is locked.
+ */
+STATIC int
+xfs_qm_dqlookup(
+       xfs_mount_t             *mp,
+       xfs_dqid_t              id,
+       xfs_dqhash_t            *qh,
+       xfs_dquot_t             **O_dqpp)
+{
+       xfs_dquot_t             *dqp;
+       uint                    flist_locked;
+       xfs_dquot_t             *d;
+
+       ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
+
+       flist_locked = B_FALSE;
+
+       /*
+        * Traverse the hashchain looking for a match
+        */
+       for (dqp = qh->qh_next; dqp != NULL; dqp = dqp->HL_NEXT) {
+               /*
+                * We already have the hashlock. We don't need the
+                * dqlock to look at the id field of the dquot, since the
+                * id can't be modified without the hashlock anyway.
+                */
+               if (INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id && dqp->q_mount == mp) {
+                       xfs_dqtrace_entry(dqp, "DQFOUND BY LOOKUP");
+                       /*
+                        * All in core dquots must be on the dqlist of mp
+                        */
+                       ASSERT(dqp->MPL_PREVP != NULL);
+
+                       xfs_dqlock(dqp);
+                       if (dqp->q_nrefs == 0) {
+                               ASSERT (XFS_DQ_IS_ON_FREELIST(dqp));
+                               if (! xfs_qm_freelist_lock_nowait(xfs_Gqm)) {
+                                       xfs_dqtrace_entry(dqp, "DQLOOKUP: WANT");
+
+                                       /*
+                                        * We may have raced with dqreclaim_one()
+                                        * (and lost). So, flag that we don't
+                                        * want the dquot to be reclaimed.
+                                        */
+                                       dqp->dq_flags |= XFS_DQ_WANT;
+                                       xfs_dqunlock(dqp);
+                                       xfs_qm_freelist_lock(xfs_Gqm);
+                                       xfs_dqlock(dqp);
+                                       dqp->dq_flags &= ~(XFS_DQ_WANT);
+                               }
+                               flist_locked = B_TRUE;
+                       }
+
+                       /*
+                        * id couldn't have changed; we had the hashlock all
+                        * along
+                        */
+                       ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id);
+
+                       if (flist_locked) {
+                               if (dqp->q_nrefs != 0) {
+                                       xfs_qm_freelist_unlock(xfs_Gqm);
+                                       flist_locked = B_FALSE;
+                               } else {
+                                       /*
+                                        * take it off the freelist
+                                        */
+                                       xfs_dqtrace_entry(dqp,
+                                                       "DQLOOKUP: TAKEOFF FL");
+                                       XQM_FREELIST_REMOVE(dqp);
+                                       /* xfs_qm_freelist_print(&(xfs_Gqm->
+                                                       qm_dqfreelist),
+                                                       "after removal"); */
+                               }
+                       }
+
+                       /*
+                        * grab a reference
+                        */
+                       XFS_DQHOLD(dqp);
+
+                       if (flist_locked)
+                               xfs_qm_freelist_unlock(xfs_Gqm);
+                       /*
+                        * move the dquot to the front of the hashchain
+                        */
+                       ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
+                       if (dqp->HL_PREVP != &qh->qh_next) {
+                               xfs_dqtrace_entry(dqp,
+                                                 "DQLOOKUP: HASH MOVETOFRONT");
+                               if ((d = dqp->HL_NEXT))
+                                       d->HL_PREVP = dqp->HL_PREVP;
+                               *(dqp->HL_PREVP) = d;
+                               d = qh->qh_next;
+                               d->HL_PREVP = &dqp->HL_NEXT;
+                               dqp->HL_NEXT = d;
+                               dqp->HL_PREVP = &qh->qh_next;
+                               qh->qh_next = dqp;
+                       }
+                       xfs_dqtrace_entry(dqp, "LOOKUP END");
+                       *O_dqpp = dqp;
+                       ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
+                       return (0);
+               }
+       }
+
+       *O_dqpp = NULL;
+       ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
+       return (1);
+}
+
+/*
+ * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a
+ * a locked dquot, doing an allocation (if requested) as needed.
+ * When both an inode and an id are given, the inode's id takes precedence.
+ * That is, if the id changes while we don't hold the ilock inside this
+ * function, the new dquot is returned, not necessarily the one requested
+ * in the id argument.
+ */
+int
+xfs_qm_dqget(
+       xfs_mount_t     *mp,
+       xfs_inode_t     *ip,      /* locked inode (optional) */
+       xfs_dqid_t      id,       /* gid or uid, depending on type */
+       uint            type,     /* UDQUOT or GDQUOT */
+       uint            flags,    /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */
+       xfs_dquot_t     **O_dqpp) /* OUT : locked incore dquot */
+{
+       xfs_dquot_t     *dqp;
+       xfs_dqhash_t    *h;
+       uint            version;
+       int             error;
+
+       ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+       if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) ||
+           (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) {
+               return (ESRCH);
+       }
+       h = XFS_DQ_HASH(mp, id, type);
+
+#ifdef DEBUG
+       if (xfs_do_dqerror) {
+               if ((xfs_dqerror_dev == mp->m_dev) &&
+                   (xfs_dqreq_num++ % xfs_dqerror_mod) == 0) {
+                       cmn_err(CE_DEBUG, "Returning error in dqget");
+                       return (EIO);
+               }
+       }
+#endif
+
+ again:
+
+#ifdef DEBUG
+       ASSERT(type == XFS_DQ_USER || type == XFS_DQ_GROUP);
+       if (ip) {
+               ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+               if (type == XFS_DQ_USER)
+                       ASSERT(ip->i_udquot == NULL);
+               else
+                       ASSERT(ip->i_gdquot == NULL);
+       }
+#endif
+       XFS_DQ_HASH_LOCK(h);
+
+       /*
+        * Look in the cache (hashtable).
+        * The chain is kept locked during lookup.
+        */
+       if (xfs_qm_dqlookup(mp, id, h, O_dqpp) == 0) {
+               XQM_STATS_INC(xqmstats.xs_qm_dqcachehits);
+               /*
+                * The dquot was found, moved to the front of the chain,
+                * taken off the freelist if it was on it, and locked
+                * at this point. Just unlock the hashchain and return.
+                */
+               ASSERT(*O_dqpp);
+               ASSERT(XFS_DQ_IS_LOCKED(*O_dqpp));
+               XFS_DQ_HASH_UNLOCK(h);
+               xfs_dqtrace_entry(*O_dqpp, "DQGET DONE (FROM CACHE)");
+               return (0);     /* success */
+       }
+       XQM_STATS_INC(xqmstats.xs_qm_dqcachemisses);
+
+       /*
+        * Dquot cache miss. We don't want to keep the inode lock across
+        * a (potential) disk read. Also we don't want to deal with the lock
+        * ordering between quotainode and this inode. OTOH, dropping the inode
+        * lock here means dealing with a chown that can happen before
+        * we re-acquire the lock.
+        */
+       if (ip)
+               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+       /*
+        * Save the hashchain version stamp, and unlock the chain, so that
+        * we don't keep the lock across a disk read
+        */
+       version = h->qh_version;
+       XFS_DQ_HASH_UNLOCK(h);
+
+       /*
+        * Allocate the dquot on the kernel heap, and read the ondisk
+        * portion off the disk. Also, do all the necessary initialization
+        * This can return ENOENT if dquot didn't exist on disk and we didn't
+        * ask it to allocate; ESRCH if quotas got turned off suddenly.
+        */
+       if ((error = xfs_qm_idtodq(mp, id, type,
+                                 flags & (XFS_QMOPT_DQALLOC|XFS_QMOPT_DQREPAIR|
+                                          XFS_QMOPT_DOWARN),
+                                 &dqp))) {
+               if (ip)
+                       xfs_ilock(ip, XFS_ILOCK_EXCL);
+               return (error);
+       }
+
+       /*
+        * See if this is mount code calling to look at the overall quota limits
+        * which are stored in the id == 0 user or group's dquot.
+        * Since we may not have done a quotacheck by this point, just return
+        * the dquot without attaching it to any hashtables, lists, etc, or even
+        * taking a reference.
+        * The caller must dqdestroy this once done.
+        */
+       if (flags & XFS_QMOPT_DQSUSER) {
+               ASSERT(id == 0);
+               ASSERT(! ip);
+               goto dqret;
+       }
+
+       /*
+        * Dquot lock comes after hashlock in the lock ordering
+        */
+       ASSERT(! XFS_DQ_IS_LOCKED(dqp));
+       if (ip) {
+               xfs_ilock(ip, XFS_ILOCK_EXCL);
+               if (! XFS_IS_DQTYPE_ON(mp, type)) {
+                       /* inode stays locked on return */
+                       xfs_qm_dqdestroy(dqp);
+                       return XFS_ERROR(ESRCH);
+               }
+               /*
+                * A dquot could be attached to this inode by now, since
+                * we had dropped the ilock.
+                */
+               if (type == XFS_DQ_USER) {
+                       if (ip->i_udquot) {
+                               xfs_qm_dqdestroy(dqp);
+                               dqp = ip->i_udquot;
+                               xfs_dqlock(dqp);
+                               goto dqret;
+                       }
+               } else {
+                       if (ip->i_gdquot) {
+                               xfs_qm_dqdestroy(dqp);
+                               dqp = ip->i_gdquot;
+                               xfs_dqlock(dqp);
+                               goto dqret;
+                       }
+               }
+       }
+
+       /*
+        * Hashlock comes after ilock in lock order
+        */
+       XFS_DQ_HASH_LOCK(h);
+       if (version != h->qh_version) {
+               xfs_dquot_t *tmpdqp;
+               /*
+                * Now, see if somebody else put the dquot in the
+                * hashtable before us. This can happen because we didn't
+                * keep the hashchain lock. We don't have to worry about
+                * lock order between the two dquots here since dqp isn't
+                * on any findable lists yet.
+                */
+               if (xfs_qm_dqlookup(mp, id, h, &tmpdqp) == 0) {
+                       /*
+                        * Duplicate found. Just throw away the new dquot
+                        * and start over.
+                        */
+                       xfs_qm_dqput(tmpdqp);
+                       XFS_DQ_HASH_UNLOCK(h);
+                       xfs_qm_dqdestroy(dqp);
+                       XQM_STATS_INC(xqmstats.xs_qm_dquot_dups);
+                       goto again;
+               }
+       }
+
+       /*
+        * Put the dquot at the beginning of the hash-chain and mp's list
+        * LOCK ORDER: hashlock, freelistlock, mplistlock, udqlock, gdqlock ..
+        */
+       ASSERT(XFS_DQ_IS_HASH_LOCKED(h));
+       dqp->q_hash = h;
+       XQM_HASHLIST_INSERT(h, dqp);
+
+       /*
+        * Attach this dquot to this filesystem's list of all dquots,
+        * kept inside the mount structure in m_quotainfo field
+        */
+       xfs_qm_mplist_lock(mp);
+
+       /*
+        * We return a locked dquot to the caller, with a reference taken
+        */
+       xfs_dqlock(dqp);
+       dqp->q_nrefs = 1;
+
+       XQM_MPLIST_INSERT(&(XFS_QI_MPL_LIST(mp)), dqp);
+
+       xfs_qm_mplist_unlock(mp);
+       XFS_DQ_HASH_UNLOCK(h);
+ dqret:
+       ASSERT((ip == NULL) || XFS_ISLOCKED_INODE_EXCL(ip));
+       xfs_dqtrace_entry(dqp, "DQGET DONE");
+       *O_dqpp = dqp;
+       return (0);
+}
+
+
+/*
+ * Release a reference to the dquot (decrement ref-count)
+ * and unlock it. If there is a group quota attached to this
+ * dquot, carefully release that too without tripping over
+ * deadlocks'n'stuff.
+ */
+void
+xfs_qm_dqput(
+       xfs_dquot_t     *dqp)
+{
+       xfs_dquot_t     *gdqp;
+
+       ASSERT(dqp->q_nrefs > 0);
+       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+       xfs_dqtrace_entry(dqp, "DQPUT");
+
+       if (dqp->q_nrefs != 1) {
+               dqp->q_nrefs--;
+               xfs_dqunlock(dqp);
+               return;
+       }
+
+       /*
+        * drop the dqlock and acquire the freelist and dqlock
+        * in the right order; but try to get it out-of-order first
+        */
+       if (! xfs_qm_freelist_lock_nowait(xfs_Gqm)) {
+               xfs_dqtrace_entry(dqp, "DQPUT: FLLOCK-WAIT");
+               xfs_dqunlock(dqp);
+               xfs_qm_freelist_lock(xfs_Gqm);
+               xfs_dqlock(dqp);
+       }
+
+       while (1) {
+               gdqp = NULL;
+
+               /* We can't depend on nrefs being == 1 here */
+               if (--dqp->q_nrefs == 0) {
+                       xfs_dqtrace_entry(dqp, "DQPUT: ON FREELIST");
+                       /*
+                        * insert at end of the freelist.
+                        */
+                       XQM_FREELIST_INSERT(&(xfs_Gqm->qm_dqfreelist), dqp);
+
+                       /*
+                        * If we just added a udquot to the freelist, then
+                        * we want to release the gdquot reference that
+                        * it (probably) has. Otherwise it'll keep the
+                        * gdquot from getting reclaimed.
+                        */
+                       if ((gdqp = dqp->q_gdquot)) {
+                               /*
+                                * Avoid a recursive dqput call
+                                */
+                               xfs_dqlock(gdqp);
+                               dqp->q_gdquot = NULL;
+                       }
+
+                       /* xfs_qm_freelist_print(&(xfs_Gqm->qm_dqfreelist),
+                          "@@@@@++ Free list (after append) @@@@@+");
+                          */
+               }
+               xfs_dqunlock(dqp);
+
+               /*
+                * If we had a group quota inside the user quota as a hint,
+                * release it now.
+                */
+               if (! gdqp)
+                       break;
+               dqp = gdqp;
+       }
+       xfs_qm_freelist_unlock(xfs_Gqm);
+}
+
+/*
+ * Release a dquot. Flush it if dirty, then dqput() it.
+ * dquot must not be locked.
+ */
+void
+xfs_qm_dqrele(
+       xfs_dquot_t     *dqp)
+{
+       ASSERT(dqp);
+       xfs_dqtrace_entry(dqp, "DQRELE");
+
+       xfs_dqlock(dqp);
+       /*
+        * We don't care to flush it if the dquot is dirty here.
+        * That will create stutters that we want to avoid.
+        * Instead we do a delayed write when we try to reclaim
+        * a dirty dquot. Also xfs_sync will take part of the burden...
+        */
+       xfs_qm_dqput(dqp);
+}
+
+
+/*
+ * Write a modified dquot to disk.
+ * The dquot must be locked and the flush lock too taken by caller.
+ * The flush lock will not be unlocked until the dquot reaches the disk,
+ * but the dquot is free to be unlocked and modified by the caller
+ * in the interim. Dquot is still locked on return. This behavior is
+ * identical to that of inodes.
+ */
+int
+xfs_qm_dqflush(
+       xfs_dquot_t             *dqp,
+       uint                    flags)
+{
+       xfs_mount_t             *mp;
+       xfs_buf_t               *bp;
+       xfs_disk_dquot_t        *ddqp;
+       int                     error;
+       SPLDECL(s);
+
+       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+       ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp));
+       xfs_dqtrace_entry(dqp, "DQFLUSH");
+
+       /*
+        * If not dirty, nada.
+        */
+       if (!XFS_DQ_IS_DIRTY(dqp)) {
+               xfs_dqfunlock(dqp);
+               return (0);
+       }
+
+       /*
+        * Cant flush a pinned dquot. Wait for it.
+        */
+       xfs_qm_dqunpin_wait(dqp);
+
+       /*
+        * This may have been unpinned because the filesystem is shutting
+        * down forcibly. If that's the case we must not write this dquot
+        * to disk, because the log record didn't make it to disk!
+        */
+       if (XFS_FORCED_SHUTDOWN(dqp->q_mount)) {
+               dqp->dq_flags &= ~(XFS_DQ_DIRTY);
+               xfs_dqfunlock(dqp);
+               return XFS_ERROR(EIO);
+       }
+
+       /*
+        * Get the buffer containing the on-disk dquot
+        * We don't need a transaction envelope because we know that the
+        * the ondisk-dquot has already been allocated for.
+        */
+       if ((error = xfs_qm_dqtobp(NULL, dqp, &ddqp, &bp, XFS_QMOPT_DOWARN))) {
+               xfs_dqtrace_entry(dqp, "DQTOBP FAIL");
+               ASSERT(error != ENOENT);
+               /*
+                * Quotas could have gotten turned off (ESRCH)
+                */
+               xfs_dqfunlock(dqp);
+               return (error);
+       }
+
+       if (xfs_qm_dqcheck(&dqp->q_core, INT_GET(ddqp->d_id, ARCH_CONVERT), 0, XFS_QMOPT_DOWARN,
+                          "dqflush (incore copy)")) {
+               xfs_force_shutdown(dqp->q_mount, XFS_CORRUPT_INCORE);
+               return XFS_ERROR(EIO);
+       }
+
+       /* This is the only portion of data that needs to persist */
+       memcpy(ddqp, &(dqp->q_core), sizeof(xfs_disk_dquot_t));
+
+       /*
+        * Clear the dirty field and remember the flush lsn for later use.
+        */
+       dqp->dq_flags &= ~(XFS_DQ_DIRTY);
+       mp = dqp->q_mount;
+
+       /* lsn is 64 bits */
+       AIL_LOCK(mp, s);
+       dqp->q_logitem.qli_flush_lsn = dqp->q_logitem.qli_item.li_lsn;
+       AIL_UNLOCK(mp, s);
+
+       /*
+        * Attach an iodone routine so that we can remove this dquot from the
+        * AIL and release the flush lock once the dquot is synced to disk.
+        */
+       xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t *, xfs_log_item_t *))
+                             xfs_qm_dqflush_done, &(dqp->q_logitem.qli_item));
+       /*
+        * If the buffer is pinned then push on the log so we won't
+        * get stuck waiting in the write for too long.
+        */
+       if (XFS_BUF_ISPINNED(bp)) {
+               xfs_dqtrace_entry(dqp, "DQFLUSH LOG FORCE");
+               xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE);
+       }
+
+       if (flags & XFS_QMOPT_DELWRI) {
+               xfs_bdwrite(mp, bp);
+       } else if (flags & XFS_QMOPT_ASYNC) {
+               xfs_bawrite(mp, bp);
+       } else {
+               error = xfs_bwrite(mp, bp);
+       }
+       xfs_dqtrace_entry(dqp, "DQFLUSH END");
+       /*
+        * dqp is still locked, but caller is free to unlock it now.
+        */
+       return (error);
+
+}
+
+/*
+ * This is the dquot flushing I/O completion routine.  It is called
+ * from interrupt level when the buffer containing the dquot is
+ * flushed to disk.  It is responsible for removing the dquot logitem
+ * from the AIL if it has not been re-logged, and unlocking the dquot's
+ * flush lock. This behavior is very similar to that of inodes..
+ */
+/*ARGSUSED*/
+STATIC void
+xfs_qm_dqflush_done(
+       xfs_buf_t               *bp,
+       xfs_dq_logitem_t        *qip)
+{
+       xfs_dquot_t             *dqp;
+       SPLDECL(s);
+
+       dqp = qip->qli_dquot;
+
+       /*
+        * We only want to pull the item from the AIL if its
+        * location in the log has not changed since we started the flush.
+        * Thus, we only bother if the dquot's lsn has
+        * not changed. First we check the lsn outside the lock
+        * since it's cheaper, and then we recheck while
+        * holding the lock before removing the dquot from the AIL.
+        */
+       if ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
+           qip->qli_item.li_lsn == qip->qli_flush_lsn) {
+
+               AIL_LOCK(dqp->q_mount, s);
+               /*
+                * xfs_trans_delete_ail() drops the AIL lock.
+                */
+               if (qip->qli_item.li_lsn == qip->qli_flush_lsn)
+                       xfs_trans_delete_ail(dqp->q_mount,
+                                            (xfs_log_item_t*)qip, s);
+               else
+                       AIL_UNLOCK(dqp->q_mount, s);
+       }
+
+       /*
+        * Release the dq's flush lock since we're done with it.
+        */
+       xfs_dqfunlock(dqp);
+}
+
+
+int
+xfs_qm_dqflock_nowait(
+       xfs_dquot_t *dqp)
+{
+       int locked;
+
+       locked = cpsema(&((dqp)->q_flock));
+
+       /* XXX ifdef these out */
+       if (locked)
+               (dqp)->dq_flags |= XFS_DQ_FLOCKED;
+       return (locked);
+}
+
+
+int
+xfs_qm_dqlock_nowait(
+       xfs_dquot_t *dqp)
+{
+       return (mutex_trylock(&((dqp)->q_qlock)));
+}
+
+void
+xfs_dqlock(
+       xfs_dquot_t *dqp)
+{
+       mutex_lock(&(dqp->q_qlock), PINOD);
+}
+
+void
+xfs_dqunlock(
+       xfs_dquot_t *dqp)
+{
+       mutex_unlock(&(dqp->q_qlock));
+       if (dqp->q_logitem.qli_dquot == dqp) {
+               /* Once was dqp->q_mount, but might just have been cleared */
+               xfs_trans_unlocked_item(dqp->q_logitem.qli_item.li_mountp,
+                                       (xfs_log_item_t*)&(dqp->q_logitem));
+       }
+}
+
+
+void
+xfs_dqunlock_nonotify(
+       xfs_dquot_t *dqp)
+{
+       mutex_unlock(&(dqp->q_qlock));
+}
+
+void
+xfs_dqlock2(
+       xfs_dquot_t     *d1,
+       xfs_dquot_t     *d2)
+{
+       if (d1 && d2) {
+               ASSERT(d1 != d2);
+               if (INT_GET(d1->q_core.d_id, ARCH_CONVERT) > INT_GET(d2->q_core.d_id, ARCH_CONVERT)) {
+                       xfs_dqlock(d2);
+                       xfs_dqlock(d1);
+               } else {
+                       xfs_dqlock(d1);
+                       xfs_dqlock(d2);
+               }
+       } else {
+               if (d1) {
+                       xfs_dqlock(d1);
+               } else if (d2) {
+                       xfs_dqlock(d2);
+               }
+       }
+}
+
+
+/*
+ * Take a dquot out of the mount's dqlist as well as the hashlist.
+ * This is called via unmount as well as quotaoff, and the purge
+ * will always succeed unless there are soft (temp) references
+ * outstanding.
+ *
+ * This returns 0 if it was purged, 1 if it wasn't. It's not an error code
+ * that we're returning! XXXsup - not cool.
+ */
+/* ARGSUSED */
+int
+xfs_qm_dqpurge(
+       xfs_dquot_t     *dqp,
+       uint            flags)
+{
+       xfs_dqhash_t    *thishash;
+       xfs_mount_t     *mp;
+
+       mp = dqp->q_mount;
+
+       ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
+       ASSERT(XFS_DQ_IS_HASH_LOCKED(dqp->q_hash));
+
+       xfs_dqlock(dqp);
+       /*
+        * We really can't afford to purge a dquot that is
+        * referenced, because these are hard refs.
+        * It shouldn't happen in general because we went thru _all_ inodes in
+        * dqrele_all_inodes before calling this and didn't let the mountlock go.
+        * However it is possible that we have dquots with temporary
+        * references that are not attached to an inode. e.g. see xfs_setattr().
+        */
+       if (dqp->q_nrefs != 0) {
+               xfs_dqunlock(dqp);
+               XFS_DQ_HASH_UNLOCK(dqp->q_hash);
+               return (1);
+       }
+
+       ASSERT(XFS_DQ_IS_ON_FREELIST(dqp));
+
+       /*
+        * If we're turning off quotas, we have to make sure that, for
+        * example, we don't delete quota disk blocks while dquots are
+        * in the process of getting written to those disk blocks.
+        * This dquot might well be on AIL, and we can't leave it there
+        * if we're turning off quotas. Basically, we need this flush
+        * lock, and are willing to block on it.
+        */
+       if (! xfs_qm_dqflock_nowait(dqp)) {
+               /*
+                * Block on the flush lock after nudging dquot buffer,
+                * if it is incore.
+                */
+               xfs_qm_dqflock_pushbuf_wait(dqp);
+       }
+
+       /*
+        * XXXIf we're turning this type of quotas off, we don't care
+        * about the dirty metadata sitting in this dquot. OTOH, if
+        * we're unmounting, we do care, so we flush it and wait.
+        */
+       if (XFS_DQ_IS_DIRTY(dqp)) {
+               xfs_dqtrace_entry(dqp, "DQPURGE ->DQFLUSH: DQDIRTY");
+               /* dqflush unlocks dqflock */
+               /*
+                * Given that dqpurge is a very rare occurrence, it is OK
+                * that we're holding the hashlist and mplist locks
+                * across the disk write. But, ... XXXsup
+                *
+                * We don't care about getting disk errors here. We need
+                * to purge this dquot anyway, so we go ahead regardless.
+                */
+               (void) xfs_qm_dqflush(dqp, XFS_QMOPT_SYNC);
+               xfs_dqflock(dqp);
+       }
+       ASSERT(dqp->q_pincount == 0);
+       ASSERT(XFS_FORCED_SHUTDOWN(mp) ||
+              !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL));
+
+       thishash = dqp->q_hash;
+       XQM_HASHLIST_REMOVE(thishash, dqp);
+       XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(mp)), dqp);
+       /*
+        * XXX Move this to the front of the freelist, if we can get the
+        * freelist lock.
+        */
+       ASSERT(XFS_DQ_IS_ON_FREELIST(dqp));
+
+       dqp->q_mount = NULL;;
+       dqp->q_hash = NULL;
+       dqp->dq_flags = XFS_DQ_INACTIVE;
+       memset(&dqp->q_core, 0, sizeof(dqp->q_core));
+       xfs_dqfunlock(dqp);
+       xfs_dqunlock(dqp);
+       XFS_DQ_HASH_UNLOCK(thishash);
+       return (0);
+}
+
+
+#ifdef QUOTADEBUG
+void
+xfs_qm_dqprint(xfs_dquot_t *dqp)
+{
+       cmn_err(CE_DEBUG, "-----------KERNEL DQUOT----------------");
+       cmn_err(CE_DEBUG, "---- dquotID =  %d",
+               (int)INT_GET(dqp->q_core.d_id, ARCH_CONVERT));
+       cmn_err(CE_DEBUG, "---- type    =  %s",
+               XFS_QM_ISUDQ(dqp) ? "USR" : "GRP");
+       cmn_err(CE_DEBUG, "---- fs      =  0x%p", dqp->q_mount);
+       cmn_err(CE_DEBUG, "---- blkno   =  0x%x", (int) dqp->q_blkno);
+       cmn_err(CE_DEBUG, "---- boffset =  0x%x", (int) dqp->q_bufoffset);
+       cmn_err(CE_DEBUG, "---- blkhlimit =  %Lu (0x%x)",
+               INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT),
+               (int) INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT));
+       cmn_err(CE_DEBUG, "---- blkslimit =  %Lu (0x%x)",
+               INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT),
+               (int)INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT));
+       cmn_err(CE_DEBUG, "---- inohlimit =  %Lu (0x%x)",
+               INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT),
+               (int)INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT));
+       cmn_err(CE_DEBUG, "---- inoslimit =  %Lu (0x%x)",
+               INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT),
+               (int)INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT));
+       cmn_err(CE_DEBUG, "---- bcount  =  %Lu (0x%x)",
+               INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT),
+               (int)INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
+       cmn_err(CE_DEBUG, "---- icount  =  %Lu (0x%x)",
+               INT_GET(dqp->q_core.d_icount, ARCH_CONVERT),
+               (int)INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
+       cmn_err(CE_DEBUG, "---- btimer  =  %d",
+               (int)INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT));
+       cmn_err(CE_DEBUG, "---- itimer  =  %d",
+               (int)INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT));
+       cmn_err(CE_DEBUG, "---------------------------");
+}
+#endif
+
+/*
+ * Give the buffer a little push if it is incore and
+ * wait on the flush lock.
+ */
+void
+xfs_qm_dqflock_pushbuf_wait(
+       xfs_dquot_t     *dqp)
+{
+       xfs_buf_t       *bp;
+
+       /*
+        * Check to see if the dquot has been flushed delayed
+        * write.  If so, grab its buffer and send it
+        * out immediately.  We'll be able to acquire
+        * the flush lock when the I/O completes.
+        */
+       bp = xfs_incore(dqp->q_mount->m_ddev_targp, dqp->q_blkno,
+                   XFS_QI_DQCHUNKLEN(dqp->q_mount),
+                   XFS_INCORE_TRYLOCK);
+       if (bp != NULL) {
+               if (XFS_BUF_ISDELAYWRITE(bp)) {
+                       if (XFS_BUF_ISPINNED(bp)) {
+                               xfs_log_force(dqp->q_mount,
+                                             (xfs_lsn_t)0,
+                                             XFS_LOG_FORCE);
+                       }
+                       xfs_bawrite(dqp->q_mount, bp);
+               } else {
+                       xfs_buf_relse(bp);
+               }
+       }
+       xfs_dqflock(dqp);
+}
diff --git a/fs/xfs/quota/xfs_dquot.h b/fs/xfs/quota/xfs_dquot.h
new file mode 100644 (file)
index 0000000..9d68757
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.         Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_DQUOT_H__
+#define __XFS_DQUOT_H__
+
+/*
+ * Dquots are structures that hold quota information about a user or a group,
+ * much like inodes are for files. In fact, dquots share many characteristics
+ * with inodes. However, dquots can also be a centralized resource, relative
+ * to a collection of inodes. In this respect, dquots share some characteristics
+ * of the superblock.
+ * XFS dquots exploit both those in its algorithms. They make every attempt
+ * to not be a bottleneck when quotas are on and have minimal impact, if any,
+ * when quotas are off.
+ */
+
+/*
+ * The hash chain headers (hash buckets)
+ */
+typedef struct xfs_dqhash {
+       struct xfs_dquot *qh_next;
+       mutex_t           qh_lock;
+       uint              qh_version;   /* ever increasing version */
+       uint              qh_nelems;    /* number of dquots on the list */
+} xfs_dqhash_t;
+
+typedef struct xfs_dqlink {
+       struct xfs_dquot  *ql_next;     /* forward link */
+       struct xfs_dquot **ql_prevp;    /* pointer to prev ql_next */
+} xfs_dqlink_t;
+
+struct xfs_mount;
+struct xfs_trans;
+
+/*
+ * This is the marker which is designed to occupy the first few
+ * bytes of the xfs_dquot_t structure. Even inside this, the freelist pointers
+ * must come first.
+ * This serves as the marker ("sentinel") when we have to restart list
+ * iterations because of locking considerations.
+ */
+typedef struct xfs_dqmarker {
+       struct xfs_dquot*dqm_flnext;    /* link to freelist: must be first */
+       struct xfs_dquot*dqm_flprev;
+       xfs_dqlink_t     dqm_mplist;    /* link to mount's list of dquots */
+       xfs_dqlink_t     dqm_hashlist;  /* link to the hash chain */
+       uint             dqm_flags;     /* various flags (XFS_DQ_*) */
+} xfs_dqmarker_t;
+
+/*
+ * The incore dquot structure
+ */
+typedef struct xfs_dquot {
+       xfs_dqmarker_t   q_lists;       /* list ptrs, q_flags (marker) */
+       xfs_dqhash_t    *q_hash;        /* the hashchain header */
+       struct xfs_mount*q_mount;       /* filesystem this relates to */
+       struct xfs_trans*q_transp;      /* trans this belongs to currently */
+       uint             q_nrefs;       /* # active refs from inodes */
+       xfs_daddr_t      q_blkno;       /* blkno of dquot buffer */
+       int              q_bufoffset;   /* off of dq in buffer (# dquots) */
+       xfs_fileoff_t    q_fileoffset;  /* offset in quotas file */
+
+       struct xfs_dquot*q_gdquot;      /* group dquot, hint only */
+       xfs_disk_dquot_t q_core;        /* actual usage & quotas */
+       xfs_dq_logitem_t q_logitem;     /* dquot log item */
+       xfs_qcnt_t       q_res_bcount;  /* total regular nblks used+reserved */
+       xfs_qcnt_t       q_res_icount;  /* total inos allocd+reserved */
+       xfs_qcnt_t       q_res_rtbcount;/* total realtime blks used+reserved */
+       mutex_t          q_qlock;       /* quota lock */
+       sema_t           q_flock;       /* flush lock */
+       uint             q_pincount;    /* pin count for this dquot */
+       sv_t             q_pinwait;     /* sync var for pinning */
+#ifdef DQUOT_TRACING
+       struct ktrace   *q_trace;       /* trace header structure */
+#endif
+} xfs_dquot_t;
+
+
+#define dq_flnext      q_lists.dqm_flnext
+#define dq_flprev      q_lists.dqm_flprev
+#define dq_mplist      q_lists.dqm_mplist
+#define dq_hashlist    q_lists.dqm_hashlist
+#define dq_flags       q_lists.dqm_flags
+
+#define XFS_DQHOLD(dqp)                ((dqp)->q_nrefs++)
+
+/*
+ * Quota Accounting flags
+ */
+#define XFS_ALL_QUOTA_ACCT     (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT)
+#define XFS_ALL_QUOTA_ENFD     (XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD)
+#define XFS_ALL_QUOTA_CHKD     (XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD)
+#define XFS_ALL_QUOTA_ACTV     (XFS_UQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE)
+#define XFS_ALL_QUOTA_ACCT_ENFD (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
+                                XFS_GQUOTA_ACCT|XFS_GQUOTA_ENFD)
+
+#define XFS_IS_QUOTA_RUNNING(mp)  ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
+#define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT)
+#define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT)
+
+/*
+ * Quota Limit Enforcement flags
+ */
+#define XFS_IS_QUOTA_ENFORCED(mp)      ((mp)->m_qflags & XFS_ALL_QUOTA_ENFD)
+#define XFS_IS_UQUOTA_ENFORCED(mp)     ((mp)->m_qflags & XFS_UQUOTA_ENFD)
+#define XFS_IS_GQUOTA_ENFORCED(mp)     ((mp)->m_qflags & XFS_GQUOTA_ENFD)
+
+#ifdef DEBUG
+static inline int
+XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp)
+{
+       if (mutex_trylock(&dqp->q_qlock)) {
+               mutex_unlock(&dqp->q_qlock);
+               return 0;
+       }
+       return 1;
+}
+#endif
+
+
+/*
+ * The following three routines simply manage the q_flock
+ * semaphore embedded in the dquot.  This semaphore synchronizes
+ * processes attempting to flush the in-core dquot back to disk.
+ */
+#define xfs_dqflock(dqp)        { psema(&((dqp)->q_flock), PINOD | PRECALC);\
+                                  (dqp)->dq_flags |= XFS_DQ_FLOCKED; }
+#define xfs_dqfunlock(dqp)      { ASSERT(valusema(&((dqp)->q_flock)) <= 0); \
+                                  vsema(&((dqp)->q_flock)); \
+                                  (dqp)->dq_flags &= ~(XFS_DQ_FLOCKED); }
+
+#define XFS_DQ_PINLOCK(dqp)       mutex_spinlock( \
+                                    &(XFS_DQ_TO_QINF(dqp)->qi_pinlock))
+#define XFS_DQ_PINUNLOCK(dqp, s)   mutex_spinunlock( \
+                                    &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s)
+
+#define XFS_DQ_IS_FLUSH_LOCKED(dqp) (valusema(&((dqp)->q_flock)) <= 0)
+#define XFS_DQ_IS_ON_FREELIST(dqp)  ((dqp)->dq_flnext != (dqp))
+#define XFS_DQ_IS_DIRTY(dqp)   ((dqp)->dq_flags & XFS_DQ_DIRTY)
+#define XFS_QM_ISUDQ(dqp)      ((dqp)->dq_flags & XFS_DQ_USER)
+#define XFS_DQ_TO_QINF(dqp)    ((dqp)->q_mount->m_quotainfo)
+#define XFS_DQ_TO_QIP(dqp)     (XFS_QM_ISUDQ(dqp) ? \
+                                XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \
+                                XFS_DQ_TO_QINF(dqp)->qi_gquotaip)
+
+#define XFS_IS_THIS_QUOTA_OFF(d) (! (XFS_QM_ISUDQ(d) ? \
+                                    (XFS_IS_UQUOTA_ON((d)->q_mount)) : \
+                                    (XFS_IS_GQUOTA_ON((d)->q_mount))))
+#ifdef DQUOT_TRACING
+/*
+ * Dquot Tracing stuff.
+ */
+#define DQUOT_TRACE_SIZE       64
+#define DQUOT_KTRACE_ENTRY     1
+
+#define xfs_dqtrace_entry_ino(a,b,ip) \
+xfs_dqtrace_entry__((a), (b), (void*)__return_address, (ip))
+#define xfs_dqtrace_entry(a,b) \
+xfs_dqtrace_entry__((a), (b), (void*)__return_address, NULL)
+extern void            xfs_dqtrace_entry__(xfs_dquot_t *dqp, char *func,
+                                           void *, xfs_inode_t *);
+#else
+#define xfs_dqtrace_entry(a,b)
+#define xfs_dqtrace_entry_ino(a,b,ip)
+#endif
+#ifdef QUOTADEBUG
+extern void            xfs_qm_dqprint(xfs_dquot_t *);
+#else
+#define xfs_qm_dqprint(a)
+#endif
+
+extern void            xfs_qm_dqdestroy(xfs_dquot_t *);
+extern int             xfs_qm_dqflush(xfs_dquot_t *, uint);
+extern int             xfs_qm_dqpurge(xfs_dquot_t *, uint);
+extern void            xfs_qm_dqunpin_wait(xfs_dquot_t *);
+extern int             xfs_qm_dqlock_nowait(xfs_dquot_t *);
+extern int             xfs_qm_dqflock_nowait(xfs_dquot_t *);
+extern void            xfs_qm_dqflock_pushbuf_wait(xfs_dquot_t *dqp);
+extern void            xfs_qm_adjust_dqtimers(xfs_mount_t *,
+                                       xfs_disk_dquot_t *);
+extern int             xfs_qm_dqwarn(xfs_disk_dquot_t *, uint);
+extern int             xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *,
+                                       xfs_dqid_t, uint, uint, xfs_dquot_t **);
+extern void            xfs_qm_dqput(xfs_dquot_t *);
+extern void            xfs_qm_dqrele(xfs_dquot_t *);
+extern void            xfs_dqlock(xfs_dquot_t *);
+extern void            xfs_dqlock2(xfs_dquot_t *, xfs_dquot_t *);
+extern void            xfs_dqunlock(xfs_dquot_t *);
+extern void            xfs_dqunlock_nonotify(xfs_dquot_t *);
+
+#endif /* __XFS_DQUOT_H__ */
diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c
new file mode 100644 (file)
index 0000000..a056284
--- /dev/null
@@ -0,0 +1,680 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.         Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+#include "xfs_qm.h"
+
+
+/*
+ * returns the number of iovecs needed to log the given dquot item.
+ */
+/* ARGSUSED */
+STATIC uint
+xfs_qm_dquot_logitem_size(
+       xfs_dq_logitem_t        *logitem)
+{
+       /*
+        * we need only two iovecs, one for the format, one for the real thing
+        */
+       return (2);
+}
+
+/*
+ * fills in the vector of log iovecs for the given dquot log item.
+ */
+STATIC void
+xfs_qm_dquot_logitem_format(
+       xfs_dq_logitem_t        *logitem,
+       xfs_log_iovec_t         *logvec)
+{
+       ASSERT(logitem);
+       ASSERT(logitem->qli_dquot);
+
+       logvec->i_addr = (xfs_caddr_t)&logitem->qli_format;
+       logvec->i_len  = sizeof(xfs_dq_logformat_t);
+       logvec++;
+       logvec->i_addr = (xfs_caddr_t)&logitem->qli_dquot->q_core;
+       logvec->i_len  = sizeof(xfs_disk_dquot_t);
+
+       ASSERT(2 == logitem->qli_item.li_desc->lid_size);
+       logitem->qli_format.qlf_size = 2;
+
+}
+
+/*
+ * Increment the pin count of the given dquot.
+ * This value is protected by pinlock spinlock in the xQM structure.
+ */
+STATIC void
+xfs_qm_dquot_logitem_pin(
+       xfs_dq_logitem_t *logitem)
+{
+       unsigned long   s;
+       xfs_dquot_t *dqp;
+
+       dqp = logitem->qli_dquot;
+       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+       s = XFS_DQ_PINLOCK(dqp);
+       dqp->q_pincount++;
+       XFS_DQ_PINUNLOCK(dqp, s);
+}
+
+/*
+ * Decrement the pin count of the given dquot, and wake up
+ * anyone in xfs_dqwait_unpin() if the count goes to 0.         The
+ * dquot must have been previously pinned with a call to xfs_dqpin().
+ */
+/* ARGSUSED */
+STATIC void
+xfs_qm_dquot_logitem_unpin(
+       xfs_dq_logitem_t *logitem,
+       int               stale)
+{
+       unsigned long   s;
+       xfs_dquot_t *dqp;
+
+       dqp = logitem->qli_dquot;
+       ASSERT(dqp->q_pincount > 0);
+       s = XFS_DQ_PINLOCK(dqp);
+       dqp->q_pincount--;
+       if (dqp->q_pincount == 0) {
+               sv_broadcast(&dqp->q_pinwait);
+       }
+       XFS_DQ_PINUNLOCK(dqp, s);
+}
+
+/* ARGSUSED */
+STATIC void
+xfs_qm_dquot_logitem_unpin_remove(
+       xfs_dq_logitem_t *logitem,
+       xfs_trans_t      *tp)
+{
+       xfs_qm_dquot_logitem_unpin(logitem, 0);
+}
+
+/*
+ * Given the logitem, this writes the corresponding dquot entry to disk
+ * asynchronously. This is called with the dquot entry securely locked;
+ * we simply get xfs_qm_dqflush() to do the work, and unlock the dquot
+ * at the end.
+ */
+STATIC void
+xfs_qm_dquot_logitem_push(
+       xfs_dq_logitem_t        *logitem)
+{
+       xfs_dquot_t     *dqp;
+
+       dqp = logitem->qli_dquot;
+
+       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+       ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp));
+
+       /*
+        * Since we were able to lock the dquot's flush lock and
+        * we found it on the AIL, the dquot must be dirty.  This
+        * is because the dquot is removed from the AIL while still
+        * holding the flush lock in xfs_dqflush_done().  Thus, if
+        * we found it in the AIL and were able to obtain the flush
+        * lock without sleeping, then there must not have been
+        * anyone in the process of flushing the dquot.
+        */
+       xfs_qm_dqflush(dqp, XFS_B_DELWRI);
+       xfs_dqunlock(dqp);
+}
+
+/*ARGSUSED*/
+STATIC xfs_lsn_t
+xfs_qm_dquot_logitem_committed(
+       xfs_dq_logitem_t        *l,
+       xfs_lsn_t               lsn)
+{
+       /*
+        * We always re-log the entire dquot when it becomes dirty,
+        * so, the latest copy _is_ the only one that matters.
+        */
+       return (lsn);
+}
+
+
+/*
+ * This is called to wait for the given dquot to be unpinned.
+ * Most of these pin/unpin routines are plagiarized from inode code.
+ */
+void
+xfs_qm_dqunpin_wait(
+       xfs_dquot_t     *dqp)
+{
+       SPLDECL(s);
+
+       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+       if (dqp->q_pincount == 0) {
+               return;
+       }
+
+       /*
+        * Give the log a push so we don't wait here too long.
+        */
+       xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, XFS_LOG_FORCE);
+       s = XFS_DQ_PINLOCK(dqp);
+       if (dqp->q_pincount == 0) {
+               XFS_DQ_PINUNLOCK(dqp, s);
+               return;
+       }
+       sv_wait(&(dqp->q_pinwait), PINOD,
+               &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s);
+}
+
+/*
+ * This is called when IOP_TRYLOCK returns XFS_ITEM_PUSHBUF to indicate that
+ * the dquot is locked by us, but the flush lock isn't. So, here we are
+ * going to see if the relevant dquot buffer is incore, waiting on DELWRI.
+ * If so, we want to push it out to help us take this item off the AIL as soon
+ * as possible.
+ *
+ * We must not be holding the AIL_LOCK at this point. Calling incore() to
+ * search the buffercache can be a time consuming thing, and AIL_LOCK is a
+ * spinlock.
+ */
+STATIC void
+xfs_qm_dquot_logitem_pushbuf(
+       xfs_dq_logitem_t    *qip)
+{
+       xfs_dquot_t     *dqp;
+       xfs_mount_t     *mp;
+       xfs_buf_t       *bp;
+       uint            dopush;
+
+       dqp = qip->qli_dquot;
+       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+
+       /*
+        * The qli_pushbuf_flag keeps others from
+        * trying to duplicate our effort.
+        */
+       ASSERT(qip->qli_pushbuf_flag != 0);
+       ASSERT(qip->qli_push_owner == get_thread_id());
+
+       /*
+        * If flushlock isn't locked anymore, chances are that the
+        * inode flush completed and the inode was taken off the AIL.
+        * So, just get out.
+        */
+       if ((valusema(&(dqp->q_flock)) > 0)  ||
+           ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) {
+               qip->qli_pushbuf_flag = 0;
+               xfs_dqunlock(dqp);
+               return;
+       }
+       mp = dqp->q_mount;
+       bp = xfs_incore(mp->m_ddev_targp, qip->qli_format.qlf_blkno,
+                   XFS_QI_DQCHUNKLEN(mp),
+                   XFS_INCORE_TRYLOCK);
+       if (bp != NULL) {
+               if (XFS_BUF_ISDELAYWRITE(bp)) {
+                       dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
+                                 (valusema(&(dqp->q_flock)) <= 0));
+                       qip->qli_pushbuf_flag = 0;
+                       xfs_dqunlock(dqp);
+
+                       if (XFS_BUF_ISPINNED(bp)) {
+                               xfs_log_force(mp, (xfs_lsn_t)0,
+                                             XFS_LOG_FORCE);
+                       }
+                       if (dopush) {
+#ifdef XFSRACEDEBUG
+                               delay_for_intr();
+                               delay(300);
+#endif
+                               xfs_bawrite(mp, bp);
+                       } else {
+                               xfs_buf_relse(bp);
+                       }
+               } else {
+                       qip->qli_pushbuf_flag = 0;
+                       xfs_dqunlock(dqp);
+                       xfs_buf_relse(bp);
+               }
+               return;
+       }
+
+       qip->qli_pushbuf_flag = 0;
+       xfs_dqunlock(dqp);
+}
+
+/*
+ * This is called to attempt to lock the dquot associated with this
+ * dquot log item.  Don't sleep on the dquot lock or the flush lock.
+ * If the flush lock is already held, indicating that the dquot has
+ * been or is in the process of being flushed, then see if we can
+ * find the dquot's buffer in the buffer cache without sleeping.  If
+ * we can and it is marked delayed write, then we want to send it out.
+ * We delay doing so until the push routine, though, to avoid sleeping
+ * in any device strategy routines.
+ */
+STATIC uint
+xfs_qm_dquot_logitem_trylock(
+       xfs_dq_logitem_t        *qip)
+{
+       xfs_dquot_t             *dqp;
+       uint                    retval;
+
+       dqp = qip->qli_dquot;
+       if (dqp->q_pincount > 0)
+               return (XFS_ITEM_PINNED);
+
+       if (! xfs_qm_dqlock_nowait(dqp))
+               return (XFS_ITEM_LOCKED);
+
+       retval = XFS_ITEM_SUCCESS;
+       if (! xfs_qm_dqflock_nowait(dqp)) {
+               /*
+                * The dquot is already being flushed.  It may have been
+                * flushed delayed write, however, and we don't want to
+                * get stuck waiting for that to complete.  So, we want to check
+                * to see if we can lock the dquot's buffer without sleeping.
+                * If we can and it is marked for delayed write, then we
+                * hold it and send it out from the push routine.  We don't
+                * want to do that now since we might sleep in the device
+                * strategy routine.  We also don't want to grab the buffer lock
+                * here because we'd like not to call into the buffer cache
+                * while holding the AIL_LOCK.
+                * Make sure to only return PUSHBUF if we set pushbuf_flag
+                * ourselves.  If someone else is doing it then we don't
+                * want to go to the push routine and duplicate their efforts.
+                */
+               if (qip->qli_pushbuf_flag == 0) {
+                       qip->qli_pushbuf_flag = 1;
+                       ASSERT(qip->qli_format.qlf_blkno == dqp->q_blkno);
+#ifdef DEBUG
+                       qip->qli_push_owner = get_thread_id();
+#endif
+                       /*
+                        * The dquot is left locked.
+                        */
+                       retval = XFS_ITEM_PUSHBUF;
+               } else {
+                       retval = XFS_ITEM_FLUSHING;
+                       xfs_dqunlock_nonotify(dqp);
+               }
+       }
+
+       ASSERT(qip->qli_item.li_flags & XFS_LI_IN_AIL);
+       return (retval);
+}
+
+
+/*
+ * Unlock the dquot associated with the log item.
+ * Clear the fields of the dquot and dquot log item that
+ * are specific to the current transaction.  If the
+ * hold flags is set, do not unlock the dquot.
+ */
+STATIC void
+xfs_qm_dquot_logitem_unlock(
+       xfs_dq_logitem_t    *ql)
+{
+       xfs_dquot_t     *dqp;
+
+       ASSERT(ql != NULL);
+       dqp = ql->qli_dquot;
+       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+
+       /*
+        * Clear the transaction pointer in the dquot
+        */
+       dqp->q_transp = NULL;
+
+       /*
+        * dquots are never 'held' from getting unlocked at the end of
+        * a transaction.  Their locking and unlocking is hidden inside the
+        * transaction layer, within trans_commit. Hence, no LI_HOLD flag
+        * for the logitem.
+        */
+       xfs_dqunlock(dqp);
+}
+
+
+/*
+ * The transaction with the dquot locked has aborted.  The dquot
+ * must not be dirty within the transaction.  We simply unlock just
+ * as if the transaction had been cancelled.
+ */
+STATIC void
+xfs_qm_dquot_logitem_abort(
+       xfs_dq_logitem_t    *ql)
+{
+       xfs_qm_dquot_logitem_unlock(ql);
+}
+
+/*
+ * this needs to stamp an lsn into the dquot, I think.
+ * rpc's that look at user dquot's would then have to
+ * push on the dependency recorded in the dquot
+ */
+/* ARGSUSED */
+STATIC void
+xfs_qm_dquot_logitem_committing(
+       xfs_dq_logitem_t        *l,
+       xfs_lsn_t               lsn)
+{
+       return;
+}
+
+
+/*
+ * This is the ops vector for dquots
+ */
+struct xfs_item_ops xfs_dquot_item_ops = {
+       .iop_size       = (uint(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_size,
+       .iop_format     = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
+                                       xfs_qm_dquot_logitem_format,
+       .iop_pin        = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_pin,
+       .iop_unpin      = (void(*)(xfs_log_item_t*, int))
+                                       xfs_qm_dquot_logitem_unpin,
+       .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*))
+                                       xfs_qm_dquot_logitem_unpin_remove,
+       .iop_trylock    = (uint(*)(xfs_log_item_t*))
+                                       xfs_qm_dquot_logitem_trylock,
+       .iop_unlock     = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_unlock,
+       .iop_committed  = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
+                                       xfs_qm_dquot_logitem_committed,
+       .iop_push       = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_push,
+       .iop_abort      = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_abort,
+       .iop_pushbuf    = (void(*)(xfs_log_item_t*))
+                                       xfs_qm_dquot_logitem_pushbuf,
+       .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
+                                       xfs_qm_dquot_logitem_committing
+};
+
+/*
+ * Initialize the dquot log item for a newly allocated dquot.
+ * The dquot isn't locked at this point, but it isn't on any of the lists
+ * either, so we don't care.
+ */
+void
+xfs_qm_dquot_logitem_init(
+       struct xfs_dquot *dqp)
+{
+       xfs_dq_logitem_t  *lp;
+       lp = &dqp->q_logitem;
+
+       lp->qli_item.li_type = XFS_LI_DQUOT;
+       lp->qli_item.li_ops = &xfs_dquot_item_ops;
+       lp->qli_item.li_mountp = dqp->q_mount;
+       lp->qli_dquot = dqp;
+       lp->qli_format.qlf_type = XFS_LI_DQUOT;
+       lp->qli_format.qlf_id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT);
+       lp->qli_format.qlf_blkno = dqp->q_blkno;
+       lp->qli_format.qlf_len = 1;
+       /*
+        * This is just the offset of this dquot within its buffer
+        * (which is currently 1 FSB and probably won't change).
+        * Hence 32 bits for this offset should be just fine.
+        * Alternatively, we can store (bufoffset / sizeof(xfs_dqblk_t))
+        * here, and recompute it at recovery time.
+        */
+       lp->qli_format.qlf_boffset = (__uint32_t)dqp->q_bufoffset;
+}
+
+/*------------------  QUOTAOFF LOG ITEMS  -------------------*/
+
+/*
+ * This returns the number of iovecs needed to log the given quotaoff item.
+ * We only need 1 iovec for an quotaoff item.  It just logs the
+ * quotaoff_log_format structure.
+ */
+/*ARGSUSED*/
+STATIC uint
+xfs_qm_qoff_logitem_size(xfs_qoff_logitem_t *qf)
+{
+       return (1);
+}
+
+/*
+ * This is called to fill in the vector of log iovecs for the
+ * given quotaoff log item. We use only 1 iovec, and we point that
+ * at the quotaoff_log_format structure embedded in the quotaoff item.
+ * It is at this point that we assert that all of the extent
+ * slots in the quotaoff item have been filled.
+ */
+STATIC void
+xfs_qm_qoff_logitem_format(xfs_qoff_logitem_t  *qf,
+                          xfs_log_iovec_t      *log_vector)
+{
+       ASSERT(qf->qql_format.qf_type == XFS_LI_QUOTAOFF);
+
+       log_vector->i_addr = (xfs_caddr_t)&(qf->qql_format);
+       log_vector->i_len = sizeof(xfs_qoff_logitem_t);
+       qf->qql_format.qf_size = 1;
+}
+
+
+/*
+ * Pinning has no meaning for an quotaoff item, so just return.
+ */
+/*ARGSUSED*/
+STATIC void
+xfs_qm_qoff_logitem_pin(xfs_qoff_logitem_t *qf)
+{
+       return;
+}
+
+
+/*
+ * Since pinning has no meaning for an quotaoff item, unpinning does
+ * not either.
+ */
+/*ARGSUSED*/
+STATIC void
+xfs_qm_qoff_logitem_unpin(xfs_qoff_logitem_t *qf, int stale)
+{
+       return;
+}
+
+/*ARGSUSED*/
+STATIC void
+xfs_qm_qoff_logitem_unpin_remove(xfs_qoff_logitem_t *qf, xfs_trans_t *tp)
+{
+       return;
+}
+
+/*
+ * Quotaoff items have no locking, so just return success.
+ */
+/*ARGSUSED*/
+STATIC uint
+xfs_qm_qoff_logitem_trylock(xfs_qoff_logitem_t *qf)
+{
+       return XFS_ITEM_LOCKED;
+}
+
+/*
+ * Quotaoff items have no locking or pushing, so return failure
+ * so that the caller doesn't bother with us.
+ */
+/*ARGSUSED*/
+STATIC void
+xfs_qm_qoff_logitem_unlock(xfs_qoff_logitem_t *qf)
+{
+       return;
+}
+
+/*
+ * The quotaoff-start-item is logged only once and cannot be moved in the log,
+ * so simply return the lsn at which it's been logged.
+ */
+/*ARGSUSED*/
+STATIC xfs_lsn_t
+xfs_qm_qoff_logitem_committed(xfs_qoff_logitem_t *qf, xfs_lsn_t lsn)
+{
+       return (lsn);
+}
+
+/*
+ * The transaction of which this QUOTAOFF is a part has been aborted.
+ * Just clean up after ourselves.
+ * Shouldn't this never happen in the case of qoffend logitems? XXX
+ */
+STATIC void
+xfs_qm_qoff_logitem_abort(xfs_qoff_logitem_t *qf)
+{
+       kmem_free(qf, sizeof(xfs_qoff_logitem_t));
+}
+
+/*
+ * There isn't much you can do to push on an quotaoff item.  It is simply
+ * stuck waiting for the log to be flushed to disk.
+ */
+/*ARGSUSED*/
+STATIC void
+xfs_qm_qoff_logitem_push(xfs_qoff_logitem_t *qf)
+{
+       return;
+}
+
+
+/*ARGSUSED*/
+STATIC xfs_lsn_t
+xfs_qm_qoffend_logitem_committed(
+       xfs_qoff_logitem_t *qfe,
+       xfs_lsn_t lsn)
+{
+       xfs_qoff_logitem_t      *qfs;
+       SPLDECL(s);
+
+       qfs = qfe->qql_start_lip;
+       AIL_LOCK(qfs->qql_item.li_mountp,s);
+       /*
+        * Delete the qoff-start logitem from the AIL.
+        * xfs_trans_delete_ail() drops the AIL lock.
+        */
+       xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs, s);
+       kmem_free(qfs, sizeof(xfs_qoff_logitem_t));
+       kmem_free(qfe, sizeof(xfs_qoff_logitem_t));
+       return (xfs_lsn_t)-1;
+}
+
+/*
+ * XXX rcc - don't know quite what to do with this.  I think we can
+ * just ignore it.  The only time that isn't the case is if we allow
+ * the client to somehow see that quotas have been turned off in which
+ * we can't allow that to get back until the quotaoff hits the disk.
+ * So how would that happen?  Also, do we need different routines for
+ * quotaoff start and quotaoff end?  I suspect the answer is yes but
+ * to be sure, I need to look at the recovery code and see how quota off
+ * recovery is handled (do we roll forward or back or do something else).
+ * If we roll forwards or backwards, then we need two separate routines,
+ * one that does nothing and one that stamps in the lsn that matters
+ * (truly makes the quotaoff irrevocable).  If we do something else,
+ * then maybe we don't need two.
+ */
+/* ARGSUSED */
+STATIC void
+xfs_qm_qoff_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn)
+{
+       return;
+}
+
+/* ARGSUSED */
+STATIC void
+xfs_qm_qoffend_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn)
+{
+       return;
+}
+
+struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
+       .iop_size       = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
+       .iop_format     = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
+                                       xfs_qm_qoff_logitem_format,
+       .iop_pin        = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
+       .iop_unpin      = (void(*)(xfs_log_item_t* ,int))
+                                       xfs_qm_qoff_logitem_unpin,
+       .iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
+                                       xfs_qm_qoff_logitem_unpin_remove,
+       .iop_trylock    = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
+       .iop_unlock     = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock,
+       .iop_committed  = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
+                                       xfs_qm_qoffend_logitem_committed,
+       .iop_push       = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
+       .iop_abort      = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort,
+       .iop_pushbuf    = NULL,
+       .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
+                                       xfs_qm_qoffend_logitem_committing
+};
+
+/*
+ * This is the ops vector shared by all quotaoff-start log items.
+ */
+struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
+       .iop_size       = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
+       .iop_format     = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
+                                       xfs_qm_qoff_logitem_format,
+       .iop_pin        = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
+       .iop_unpin      = (void(*)(xfs_log_item_t*, int))
+                                       xfs_qm_qoff_logitem_unpin,
+       .iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
+                                       xfs_qm_qoff_logitem_unpin_remove,
+       .iop_trylock    = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
+       .iop_unlock     = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock,
+       .iop_committed  = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
+                                       xfs_qm_qoff_logitem_committed,
+       .iop_push       = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
+       .iop_abort      = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort,
+       .iop_pushbuf    = NULL,
+       .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
+                                       xfs_qm_qoff_logitem_committing
+};
+
+/*
+ * Allocate and initialize an quotaoff item of the correct quota type(s).
+ */
+xfs_qoff_logitem_t *
+xfs_qm_qoff_logitem_init(
+       struct xfs_mount *mp,
+       xfs_qoff_logitem_t *start,
+       uint flags)
+{
+       xfs_qoff_logitem_t      *qf;
+
+       qf = (xfs_qoff_logitem_t*) kmem_zalloc(sizeof(xfs_qoff_logitem_t), KM_SLEEP);
+
+       qf->qql_item.li_type = XFS_LI_QUOTAOFF;
+       if (start)
+               qf->qql_item.li_ops = &xfs_qm_qoffend_logitem_ops;
+       else
+               qf->qql_item.li_ops = &xfs_qm_qoff_logitem_ops;
+       qf->qql_item.li_mountp = mp;
+       qf->qql_format.qf_type = XFS_LI_QUOTAOFF;
+       qf->qql_format.qf_flags = flags;
+       qf->qql_start_lip = start;
+       return (qf);
+}
diff --git a/fs/xfs/quota/xfs_dquot_item.h b/fs/xfs/quota/xfs_dquot_item.h
new file mode 100644 (file)
index 0000000..9c6500d
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.         Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_DQUOT_ITEM_H__
+#define __XFS_DQUOT_ITEM_H__
+
+struct xfs_dquot;
+struct xfs_trans;
+struct xfs_mount;
+struct xfs_qoff_logitem;
+
+typedef struct xfs_dq_logitem {
+       xfs_log_item_t           qli_item;         /* common portion */
+       struct xfs_dquot        *qli_dquot;        /* dquot ptr */
+       xfs_lsn_t                qli_flush_lsn;    /* lsn at last flush */
+       unsigned short           qli_pushbuf_flag; /* 1 bit used in push_ail */
+#ifdef DEBUG
+       uint64_t                 qli_push_owner;
+#endif
+       xfs_dq_logformat_t       qli_format;       /* logged structure */
+} xfs_dq_logitem_t;
+
+typedef struct xfs_qoff_logitem {
+       xfs_log_item_t           qql_item;      /* common portion */
+       struct xfs_qoff_logitem *qql_start_lip; /* qoff-start logitem, if any */
+       xfs_qoff_logformat_t     qql_format;    /* logged structure */
+} xfs_qoff_logitem_t;
+
+
+extern void               xfs_qm_dquot_logitem_init(struct xfs_dquot *);
+extern xfs_qoff_logitem_t *xfs_qm_qoff_logitem_init(struct xfs_mount *,
+                                       struct xfs_qoff_logitem *, uint);
+extern xfs_qoff_logitem_t *xfs_trans_get_qoff_item(struct xfs_trans *,
+                                       struct xfs_qoff_logitem *, uint);
+extern void               xfs_trans_log_quotaoff_item(struct xfs_trans *,
+                                       struct xfs_qoff_logitem *);
+
+#endif /* __XFS_DQUOT_ITEM_H__ */
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
new file mode 100644 (file)
index 0000000..5b16a17
--- /dev/null
@@ -0,0 +1,2794 @@
+/*
+ * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.         Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+#include "xfs_qm.h"
+
+/*
+ * The global quota manager. There is only one of these for the entire
+ * system, _not_ one per file system. XQM keeps track of the overall
+ * quota functionality, including maintaining the freelist and hash
+ * tables of dquots.
+ */
+mutex_t xfs_Gqm_lock;
+struct xfs_qm  *xfs_Gqm;
+EXPORT_SYMBOL(xfs_Gqm);        /* used by xfsidbg */
+
+kmem_zone_t    *qm_dqzone;
+kmem_zone_t    *qm_dqtrxzone;
+
+STATIC void    xfs_qm_list_init(xfs_dqlist_t *, char *, int);
+STATIC void    xfs_qm_list_destroy(xfs_dqlist_t *);
+STATIC int     xfs_qm_quotacheck(xfs_mount_t *);
+
+STATIC int     xfs_qm_init_quotainos(xfs_mount_t *);
+STATIC void    xfs_qm_shake(void);
+
+#ifdef DEBUG
+extern mutex_t qcheck_lock;
+#endif
+
+#ifdef QUOTADEBUG
+#define XQM_LIST_PRINT(l, NXT, title) \
+{ \
+       xfs_dquot_t     *dqp; int i = 0; \
+       cmn_err(CE_DEBUG, "%s (#%d)", title, (int) (l)->qh_nelems); \
+       for (dqp = (l)->qh_next; dqp != NULL; dqp = dqp->NXT) { \
+               cmn_err(CE_DEBUG, "   %d.  \"%d (%s)\"   " \
+                                 "bcnt = %d, icnt = %d, refs = %d", \
+                       ++i, (int) INT_GET(dqp->q_core.d_id, ARCH_CONVERT), \
+                       DQFLAGTO_TYPESTR(dqp),       \
+                       (int) INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), \
+                       (int) INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), \
+                       (int) dqp->q_nrefs);  } \
+}
+#else
+#define XQM_LIST_PRINT(l, NXT, title) do { } while (0)
+#endif
+
+/*
+ * Initialize the XQM structure.
+ * Note that there is not one quota manager per file system.
+ */
+STATIC struct xfs_qm *
+xfs_Gqm_init(void)
+{
+       xfs_qm_t                *xqm;
+       int                     hsize, i;
+
+       xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP);
+       ASSERT(xqm);
+
+       /*
+        * Initialize the dquot hash tables.
+        */
+       hsize = (DQUOT_HASH_HEURISTIC < XFS_QM_NCSIZE_THRESHOLD) ?
+               XFS_QM_HASHSIZE_LOW : XFS_QM_HASHSIZE_HIGH;
+       xqm->qm_dqhashmask = hsize - 1;
+
+       xqm->qm_usr_dqhtable = (xfs_dqhash_t *)kmem_zalloc(hsize *
+                                                     sizeof(xfs_dqhash_t),
+                                                     KM_SLEEP);
+       xqm->qm_grp_dqhtable = (xfs_dqhash_t *)kmem_zalloc(hsize *
+                                                     sizeof(xfs_dqhash_t),
+                                                     KM_SLEEP);
+       ASSERT(xqm->qm_usr_dqhtable != NULL);
+       ASSERT(xqm->qm_grp_dqhtable != NULL);
+
+       for (i = 0; i < hsize; i++) {
+               xfs_qm_list_init(&(xqm->qm_usr_dqhtable[i]), "uxdqh", i);
+               xfs_qm_list_init(&(xqm->qm_grp_dqhtable[i]), "gxdqh", i);
+       }
+
+       /*
+        * Freelist of all dquots of all file systems
+        */
+       xfs_qm_freelist_init(&(xqm->qm_dqfreelist));
+
+       /*
+        * dquot zone. we register our own low-memory callback.
+        */
+       if (!qm_dqzone) {
+               xqm->qm_dqzone = kmem_zone_init(sizeof(xfs_dquot_t),
+                                               "xfs_dquots");
+               qm_dqzone = xqm->qm_dqzone;
+       } else
+               xqm->qm_dqzone = qm_dqzone;
+
+       kmem_shake_register(xfs_qm_shake);
+
+       /*
+        * The t_dqinfo portion of transactions.
+        */
+       if (!qm_dqtrxzone) {
+               xqm->qm_dqtrxzone = kmem_zone_init(sizeof(xfs_dquot_acct_t),
+                                                  "xfs_dqtrx");
+               qm_dqtrxzone = xqm->qm_dqtrxzone;
+       } else
+               xqm->qm_dqtrxzone = qm_dqtrxzone;
+
+       atomic_set(&xqm->qm_totaldquots, 0);
+       xqm->qm_dqfree_ratio = XFS_QM_DQFREE_RATIO;
+       xqm->qm_nrefs = 0;
+#ifdef DEBUG
+       mutex_init(&qcheck_lock, MUTEX_DEFAULT, "qchk");
+#endif
+       return xqm;
+}
+
+/*
+ * Destroy the global quota manager when its reference count goes to zero.
+ */
+void
+xfs_qm_destroy(
+       struct xfs_qm   *xqm)
+{
+       int             hsize, i;
+
+       ASSERT(xqm != NULL);
+       ASSERT(xqm->qm_nrefs == 0);
+       kmem_shake_deregister(xfs_qm_shake);
+       hsize = xqm->qm_dqhashmask + 1;
+       for (i = 0; i < hsize; i++) {
+               xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
+               xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i]));
+       }
+       kmem_free(xqm->qm_usr_dqhtable, hsize * sizeof(xfs_dqhash_t));
+       kmem_free(xqm->qm_grp_dqhtable, hsize * sizeof(xfs_dqhash_t));
+       xqm->qm_usr_dqhtable = NULL;
+       xqm->qm_grp_dqhtable = NULL;
+       xqm->qm_dqhashmask = 0;
+       xfs_qm_freelist_destroy(&(xqm->qm_dqfreelist));
+#ifdef DEBUG
+       mutex_destroy(&qcheck_lock);
+#endif
+       kmem_free(xqm, sizeof(xfs_qm_t));
+}
+
+/*
+ * Called at mount time to let XQM know that another file system is
+ * starting quotas. This isn't crucial information as the individual mount
+ * structures are pretty independent, but it helps the XQM keep a
+ * global view of what's going on.
+ */
+/* ARGSUSED */
+STATIC int
+xfs_qm_hold_quotafs_ref(
+       struct xfs_mount *mp)
+{
+       /*
+        * Need to lock the xfs_Gqm structure for things like this. For example,
+        * the structure could disappear between the entry to this routine and
+        * a HOLD operation if not locked.
+        */
+       XFS_QM_LOCK(xfs_Gqm);
+
+       if (xfs_Gqm == NULL) {
+               if ((xfs_Gqm = xfs_Gqm_init()) == NULL) {
+                       return (XFS_ERROR(EINVAL));
+               }
+       }
+       /*
+        * We can keep a list of all filesystems with quotas mounted for
+        * debugging and statistical purposes, but ...
+        * Just take a reference and get out.
+        */
+       XFS_QM_HOLD(xfs_Gqm);
+       XFS_QM_UNLOCK(xfs_Gqm);
+
+       return 0;
+}
+
+
+/*
+ * Release the reference that a filesystem took at mount time,
+ * so that we know when we need to destroy the entire quota manager.
+ */
+/* ARGSUSED */
+STATIC void
+xfs_qm_rele_quotafs_ref(
+       struct xfs_mount *mp)
+{
+       xfs_dquot_t     *dqp, *nextdqp;
+
+       ASSERT(xfs_Gqm);
+       ASSERT(xfs_Gqm->qm_nrefs > 0);
+
+       /*
+        * Go thru the freelist and destroy all inactive dquots.
+        */
+       xfs_qm_freelist_lock(xfs_Gqm);
+
+       for (dqp = xfs_Gqm->qm_dqfreelist.qh_next;
+            dqp != (xfs_dquot_t *)&(xfs_Gqm->qm_dqfreelist); ) {
+               xfs_dqlock(dqp);
+               nextdqp = dqp->dq_flnext;
+               if (dqp->dq_flags & XFS_DQ_INACTIVE) {
+                       ASSERT(dqp->q_mount == NULL);
+                       ASSERT(! XFS_DQ_IS_DIRTY(dqp));
+                       ASSERT(dqp->HL_PREVP == NULL);
+                       ASSERT(dqp->MPL_PREVP == NULL);
+                       XQM_FREELIST_REMOVE(dqp);
+                       xfs_dqunlock(dqp);
+                       xfs_qm_dqdestroy(dqp);
+               } else {
+                       xfs_dqunlock(dqp);
+               }
+               dqp = nextdqp;
+       }
+       xfs_qm_freelist_unlock(xfs_Gqm);
+
+       /*
+        * Destroy the entire XQM. If somebody mounts with quotaon, this'll
+        * be restarted.
+        */
+       XFS_QM_LOCK(xfs_Gqm);
+       XFS_QM_RELE(xfs_Gqm);
+       if (xfs_Gqm->qm_nrefs == 0) {
+               xfs_qm_destroy(xfs_Gqm);
+               xfs_Gqm = NULL;
+       }
+       XFS_QM_UNLOCK(xfs_Gqm);
+}
+
+/*
+ * This is called at mount time from xfs_mountfs to initialize the quotainfo
+ * structure and start the global quotamanager (xfs_Gqm) if it hasn't done
+ * so already. Note that the superblock has not been read in yet.
+ */
+void
+xfs_qm_mount_quotainit(
+       xfs_mount_t     *mp,
+       uint            flags)
+{
+       /*
+        * User or group quotas has to be on.
+        */
+       ASSERT(flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA));
+
+       /*
+        * Initialize the flags in the mount structure. From this point
+        * onwards we look at m_qflags to figure out if quotas's ON/OFF, etc.
+        * Note that we enforce nothing if accounting is off.
+        * ie.  XFSMNT_*QUOTA must be ON for XFSMNT_*QUOTAENF.
+        * It isn't necessary to take the quotaoff lock to do this; this is
+        * called from mount.
+        */
+       if (flags & XFSMNT_UQUOTA) {
+               mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE);
+               if (flags & XFSMNT_UQUOTAENF)
+                       mp->m_qflags |= XFS_UQUOTA_ENFD;
+       }
+       if (flags & XFSMNT_GQUOTA) {
+               mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
+               if (flags & XFSMNT_GQUOTAENF)
+                       mp->m_qflags |= XFS_GQUOTA_ENFD;
+       }
+}
+
+/*
+ * Just destroy the quotainfo structure.
+ */
+void
+xfs_qm_unmount_quotadestroy(
+       xfs_mount_t     *mp)
+{
+       if (mp->m_quotainfo)
+               xfs_qm_destroy_quotainfo(mp);
+}
+
+
+/*
+ * This is called from xfs_mountfs to start quotas and initialize all
+ * necessary data structures like quotainfo.  This is also responsible for
+ * running a quotacheck as necessary.  We are guaranteed that the superblock
+ * is consistently read in at this point.
+ */
+int
+xfs_qm_mount_quotas(
+       xfs_mount_t     *mp)
+{
+       unsigned long   s;
+       int             error = 0;
+       uint            sbf;
+
+       /*
+        * If a file system had quotas running earlier, but decided to
+        * mount without -o quota/uquota/gquota options, revoke the
+        * quotachecked license, and bail out.
+        */
+       if (! XFS_IS_QUOTA_ON(mp) &&
+           (mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT))) {
+               mp->m_qflags = 0;
+               goto write_changes;
+       }
+
+       /*
+        * If quotas on realtime volumes is not supported, we disable
+        * quotas immediately.
+        */
+       if (mp->m_sb.sb_rextents) {
+               cmn_err(CE_NOTE,
+                       "Cannot turn on quotas for realtime filesystem %s",
+                       mp->m_fsname);
+               mp->m_qflags = 0;
+               goto write_changes;
+       }
+
+#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
+       cmn_err(CE_NOTE, "Attempting to turn on disk quotas.");
+#endif
+
+       ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+       /*
+        * Allocate the quotainfo structure inside the mount struct, and
+        * create quotainode(s), and change/rev superblock if necessary.
+        */
+       if ((error = xfs_qm_init_quotainfo(mp))) {
+               /*
+                * We must turn off quotas.
+                */
+               ASSERT(mp->m_quotainfo == NULL);
+               mp->m_qflags = 0;
+               goto write_changes;
+       }
+       /*
+        * If any of the quotas are not consistent, do a quotacheck.
+        */
+       if (XFS_QM_NEED_QUOTACHECK(mp)) {
+#ifdef DEBUG
+               cmn_err(CE_NOTE, "Doing a quotacheck. Please wait.");
+#endif
+               if ((error = xfs_qm_quotacheck(mp))) {
+                       cmn_err(CE_WARN, "Quotacheck unsuccessful (Error %d): "
+                               "Disabling quotas.",
+                               error);
+                       /*
+                        * We must turn off quotas.
+                        */
+                       ASSERT(mp->m_quotainfo != NULL);
+                       ASSERT(xfs_Gqm != NULL);
+                       xfs_qm_destroy_quotainfo(mp);
+                       mp->m_qflags = 0;
+                       goto write_changes;
+               }
+#ifdef DEBUG
+               cmn_err(CE_NOTE, "Done quotacheck.");
+#endif
+       }
+ write_changes:
+       /*
+        * We actually don't have to acquire the SB_LOCK at all.
+        * This can only be called from mount, and that's single threaded. XXX
+        */
+       s = XFS_SB_LOCK(mp);
+       sbf = mp->m_sb.sb_qflags;
+       mp->m_sb.sb_qflags = mp->m_qflags & XFS_MOUNT_QUOTA_ALL;
+       XFS_SB_UNLOCK(mp, s);
+
+       if (sbf != (mp->m_qflags & XFS_MOUNT_QUOTA_ALL)) {
+               if (xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS)) {
+                       /*
+                        * We could only have been turning quotas off.
+                        * We aren't in very good shape actually because
+                        * the incore structures are convinced that quotas are
+                        * off, but the on disk superblock doesn't know that !
+                        */
+                       ASSERT(!(XFS_IS_QUOTA_RUNNING(mp)));
+                       xfs_fs_cmn_err(CE_ALERT, mp,
+                               "XFS mount_quotas: Superblock update failed!");
+               }
+       }
+
+       if (error) {
+               xfs_fs_cmn_err(CE_WARN, mp,
+                       "Failed to initialize disk quotas.");
+       }
+       return XFS_ERROR(error);
+}
+
+/*
+ * Called from the vfsops layer.
+ */
+int
+xfs_qm_unmount_quotas(
+       xfs_mount_t     *mp)
+{
+       xfs_inode_t     *uqp, *gqp;
+       int             error = 0;
+
+       /*
+        * Release the dquots that root inode, et al might be holding,
+        * before we flush quotas and blow away the quotainfo structure.
+        */
+       ASSERT(mp->m_rootip);
+       xfs_qm_dqdetach(mp->m_rootip);
+       if (mp->m_rbmip)
+               xfs_qm_dqdetach(mp->m_rbmip);
+       if (mp->m_rsumip)
+               xfs_qm_dqdetach(mp->m_rsumip);
+
+       /*
+        * Flush out the quota inodes.
+        */
+       uqp = gqp = NULL;
+       if (mp->m_quotainfo) {
+               if ((uqp = mp->m_quotainfo->qi_uquotaip) != NULL) {
+                       xfs_ilock(uqp, XFS_ILOCK_EXCL);
+                       xfs_iflock(uqp);
+                       error = xfs_iflush(uqp, XFS_IFLUSH_SYNC);
+                       xfs_iunlock(uqp, XFS_ILOCK_EXCL);
+                       if (unlikely(error == EFSCORRUPTED)) {
+                               XFS_ERROR_REPORT("xfs_qm_unmount_quotas(1)",
+                                                XFS_ERRLEVEL_LOW, mp);
+                               goto out;
+                       }
+               }
+               if ((gqp = mp->m_quotainfo->qi_gquotaip) != NULL) {
+                       xfs_ilock(gqp, XFS_ILOCK_EXCL);
+                       xfs_iflock(gqp);
+                       error = xfs_iflush(gqp, XFS_IFLUSH_SYNC);
+                       xfs_iunlock(gqp, XFS_ILOCK_EXCL);
+                       if (unlikely(error == EFSCORRUPTED)) {
+                               XFS_ERROR_REPORT("xfs_qm_unmount_quotas(2)",
+                                                XFS_ERRLEVEL_LOW, mp);
+                               goto out;
+                       }
+               }
+       }
+       if (uqp) {
+                XFS_PURGE_INODE(uqp);
+                mp->m_quotainfo->qi_uquotaip = NULL;
+       }
+       if (gqp) {
+               XFS_PURGE_INODE(gqp);
+               mp->m_quotainfo->qi_gquotaip = NULL;
+       }
+out:
+       return XFS_ERROR(error);
+}
+
+/*
+ * Flush all dquots of the given file system to disk. The dquots are
+ * _not_ purged from memory here, just their data written to disk.
+ */
+int
+xfs_qm_dqflush_all(
+       xfs_mount_t     *mp,
+       int             flags)
+{
+       int             recl;
+       xfs_dquot_t     *dqp;
+       int             niters;
+       int             error;
+
+       if (mp->m_quotainfo == NULL)
+               return (0);
+       niters = 0;
+again:
+       xfs_qm_mplist_lock(mp);
+       FOREACH_DQUOT_IN_MP(dqp, mp) {
+               xfs_dqlock(dqp);
+               if (! XFS_DQ_IS_DIRTY(dqp)) {
+                       xfs_dqunlock(dqp);
+                       continue;
+               }
+               xfs_dqtrace_entry(dqp, "FLUSHALL: DQDIRTY");
+               /* XXX a sentinel would be better */
+               recl = XFS_QI_MPLRECLAIMS(mp);
+               if (! xfs_qm_dqflock_nowait(dqp)) {
+                       /*
+                        * If we can't grab the flush lock then check
+                        * to see if the dquot has been flushed delayed
+                        * write.  If so, grab its buffer and send it
+                        * out immediately.  We'll be able to acquire
+                        * the flush lock when the I/O completes.
+                        */
+                       xfs_qm_dqflock_pushbuf_wait(dqp);
+               }
+               /*
+                * Let go of the mplist lock. We don't want to hold it
+                * across a disk write.
+                */
+               xfs_qm_mplist_unlock(mp);
+               error = xfs_qm_dqflush(dqp, flags);
+               xfs_dqunlock(dqp);
+               if (error)
+                       return (error);
+
+               xfs_qm_mplist_lock(mp);
+               if (recl != XFS_QI_MPLRECLAIMS(mp)) {
+                       xfs_qm_mplist_unlock(mp);
+                       /* XXX restart limit */
+                       goto again;
+               }
+       }
+
+       xfs_qm_mplist_unlock(mp);
+       /* return ! busy */
+       return (0);
+}
+/*
+ * Release the group dquot pointers the user dquots may be
+ * carrying around as a hint. mplist is locked on entry and exit.
+ */
+STATIC void
+xfs_qm_detach_gdquots(
+       xfs_mount_t     *mp)
+{
+       xfs_dquot_t     *dqp, *gdqp;
+       int             nrecl;
+
+ again:
+       ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
+       dqp = XFS_QI_MPLNEXT(mp);
+       while (dqp) {
+               xfs_dqlock(dqp);
+               if ((gdqp = dqp->q_gdquot)) {
+                       xfs_dqlock(gdqp);
+                       dqp->q_gdquot = NULL;
+               }
+               xfs_dqunlock(dqp);
+
+               if (gdqp) {
+                       /*
+                        * Can't hold the mplist lock across a dqput.
+                        * XXXmust convert to marker based iterations here.
+                        */
+                       nrecl = XFS_QI_MPLRECLAIMS(mp);
+                       xfs_qm_mplist_unlock(mp);
+                       xfs_qm_dqput(gdqp);
+
+                       xfs_qm_mplist_lock(mp);
+                       if (nrecl != XFS_QI_MPLRECLAIMS(mp))
+                               goto again;
+               }
+               dqp = dqp->MPL_NEXT;
+       }
+}
+
+/*
+ * Go through all the incore dquots of this file system and take them
+ * off the mplist and hashlist, if the dquot type matches the dqtype
+ * parameter. This is used when turning off quota accounting for
+ * users and/or groups, as well as when the filesystem is unmounting.
+ */
+STATIC int
+xfs_qm_dqpurge_int(
+       xfs_mount_t     *mp,
+       uint            flags) /* QUOTAOFF/UMOUNTING/UQUOTA/GQUOTA */
+{
+       xfs_dquot_t     *dqp;
+       uint            dqtype;
+       int             nrecl;
+       xfs_dquot_t     *nextdqp;
+       int             nmisses;
+
+       if (mp->m_quotainfo == NULL)
+               return (0);
+
+       dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0;
+       dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0;
+
+       xfs_qm_mplist_lock(mp);
+
+       /*
+        * In the first pass through all incore dquots of this filesystem,
+        * we release the group dquot pointers the user dquots may be
+        * carrying around as a hint. We need to do this irrespective of
+        * what's being turned off.
+        */
+       xfs_qm_detach_gdquots(mp);
+
+      again:
+       nmisses = 0;
+       ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
+       /*
+        * Try to get rid of all of the unwanted dquots. The idea is to
+        * get them off mplist and hashlist, but leave them on freelist.
+        */
+       dqp = XFS_QI_MPLNEXT(mp);
+       while (dqp) {
+               /*
+                * It's OK to look at the type without taking dqlock here.
+                * We're holding the mplist lock here, and that's needed for
+                * a dqreclaim.
+                */
+               if ((dqp->dq_flags & dqtype) == 0) {
+                       dqp = dqp->MPL_NEXT;
+                       continue;
+               }
+
+               if (! xfs_qm_dqhashlock_nowait(dqp)) {
+                       nrecl = XFS_QI_MPLRECLAIMS(mp);
+                       xfs_qm_mplist_unlock(mp);
+                       XFS_DQ_HASH_LOCK(dqp->q_hash);
+                       xfs_qm_mplist_lock(mp);
+
+                       /*
+                        * XXXTheoretically, we can get into a very long
+                        * ping pong game here.
+                        * No one can be adding dquots to the mplist at
+                        * this point, but somebody might be taking things off.
+                        */
+                       if (nrecl != XFS_QI_MPLRECLAIMS(mp)) {
+                               XFS_DQ_HASH_UNLOCK(dqp->q_hash);
+                               goto again;
+                       }
+               }
+
+               /*
+                * Take the dquot off the mplist and hashlist. It may remain on
+                * freelist in INACTIVE state.
+                */
+               nextdqp = dqp->MPL_NEXT;
+               nmisses += xfs_qm_dqpurge(dqp, flags);
+               dqp = nextdqp;
+       }
+       xfs_qm_mplist_unlock(mp);
+       return nmisses;
+}
+
+int
+xfs_qm_dqpurge_all(
+       xfs_mount_t     *mp,
+       uint            flags)
+{
+       int             ndquots;
+
+       /*
+        * Purge the dquot cache.
+        * None of the dquots should really be busy at this point.
+        */
+       if (mp->m_quotainfo) {
+               while ((ndquots = xfs_qm_dqpurge_int(mp, flags))) {
+                       delay(ndquots * 10);
+               }
+       }
+       return 0;
+}
+
+STATIC int
+xfs_qm_dqattach_one(
+       xfs_inode_t     *ip,
+       xfs_dqid_t      id,
+       uint            type,
+       uint            doalloc,
+       uint            dolock,
+       xfs_dquot_t     *udqhint, /* hint */
+       xfs_dquot_t     **IO_idqpp)
+{
+       xfs_dquot_t     *dqp;
+       int             error;
+
+       ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+       error = 0;
+       /*
+        * See if we already have it in the inode itself. IO_idqpp is
+        * &i_udquot or &i_gdquot. This made the code look weird, but
+        * made the logic a lot simpler.
+        */
+       if ((dqp = *IO_idqpp)) {
+               if (dolock)
+                       xfs_dqlock(dqp);
+               xfs_dqtrace_entry(dqp, "DQATTACH: found in ip");
+               goto done;
+       }
+
+       /*
+        * udqhint is the i_udquot field in inode, and is non-NULL only
+        * when the type arg is XFS_DQ_GROUP. Its purpose is to save a
+        * lookup by dqid (xfs_qm_dqget) by caching a group dquot inside
+        * the user dquot.
+        */
+       ASSERT(!udqhint || type == XFS_DQ_GROUP);
+       if (udqhint && !dolock)
+               xfs_dqlock(udqhint);
+
+       /*
+        * No need to take dqlock to look at the id.
+        * The ID can't change until it gets reclaimed, and it won't
+        * be reclaimed as long as we have a ref from inode and we hold
+        * the ilock.
+        */
+       if (udqhint &&
+           (dqp = udqhint->q_gdquot) &&
+           (INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id)) {
+               ASSERT(XFS_DQ_IS_LOCKED(udqhint));
+               xfs_dqlock(dqp);
+               XFS_DQHOLD(dqp);
+               ASSERT(*IO_idqpp == NULL);
+               *IO_idqpp = dqp;
+               if (!dolock) {
+                       xfs_dqunlock(dqp);
+                       xfs_dqunlock(udqhint);
+               }
+               goto done;
+       }
+       /*
+        * We can't hold a dquot lock when we call the dqget code.
+        * We'll deadlock in no time, because of (not conforming to)
+        * lock ordering - the inodelock comes before any dquot lock,
+        * and we may drop and reacquire the ilock in xfs_qm_dqget().
+        */
+       if (udqhint)
+               xfs_dqunlock(udqhint);
+       /*
+        * Find the dquot from somewhere. This bumps the
+        * reference count of dquot and returns it locked.
+        * This can return ENOENT if dquot didn't exist on
+        * disk and we didn't ask it to allocate;
+        * ESRCH if quotas got turned off suddenly.
+        */
+       if ((error = xfs_qm_dqget(ip->i_mount, ip, id, type,
+                                doalloc|XFS_QMOPT_DOWARN, &dqp))) {
+               if (udqhint && dolock)
+                       xfs_dqlock(udqhint);
+               goto done;
+       }
+
+       xfs_dqtrace_entry(dqp, "DQATTACH: found by dqget");
+       /*
+        * dqget may have dropped and re-acquired the ilock, but it guarantees
+        * that the dquot returned is the one that should go in the inode.
+        */
+       *IO_idqpp = dqp;
+       ASSERT(dqp);
+       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+       if (! dolock) {
+               xfs_dqunlock(dqp);
+               ASSERT(!udqhint || !XFS_DQ_IS_LOCKED(udqhint));
+               goto done;
+       }
+       if (! udqhint)
+               goto done;
+
+       ASSERT(udqhint);
+       ASSERT(dolock);
+       ASSERT(! XFS_DQ_IS_LOCKED(udqhint));
+       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+       if (! xfs_qm_dqlock_nowait(udqhint)) {
+               xfs_dqunlock(dqp);
+               xfs_dqlock(udqhint);
+               xfs_dqlock(dqp);
+       }
+      done:
+#ifdef QUOTADEBUG
+       if (udqhint) {
+               if (dolock)
+                       ASSERT(XFS_DQ_IS_LOCKED(udqhint));
+               else
+                       ASSERT(! XFS_DQ_IS_LOCKED(udqhint));
+       }
+       if (! error) {
+               if (dolock)
+                       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+               else
+                       ASSERT(! XFS_DQ_IS_LOCKED(dqp));
+       }
+#endif
+       return (error);
+}
+
+
+/*
+ * Given a udquot and gdquot, attach a ptr to the group dquot in the
+ * udquot as a hint for future lookups. The idea sounds simple, but the
+ * execution isn't, because the udquot might have a group dquot attached
+ * already and getting rid of that gets us into lock ordering contraints.
+ * The process is complicated more by the fact that the dquots may or may not
+ * be locked on entry.
+ */
+STATIC void
+xfs_qm_dqattach_grouphint(
+       xfs_dquot_t     *udq,
+       xfs_dquot_t     *gdq,
+       uint            locked)
+{
+       xfs_dquot_t     *tmp;
+
+#ifdef QUOTADEBUG
+       if (locked) {
+               ASSERT(XFS_DQ_IS_LOCKED(udq));
+               ASSERT(XFS_DQ_IS_LOCKED(gdq));
+       } else {
+               ASSERT(! XFS_DQ_IS_LOCKED(udq));
+               ASSERT(! XFS_DQ_IS_LOCKED(gdq));
+       }
+#endif
+       if (! locked)
+               xfs_dqlock(udq);
+
+       if ((tmp = udq->q_gdquot)) {
+               if (tmp == gdq) {
+                       if (! locked)
+                               xfs_dqunlock(udq);
+                       return;
+               }
+
+               udq->q_gdquot = NULL;
+               /*
+                * We can't keep any dqlocks when calling dqrele,
+                * because the freelist lock comes before dqlocks.
+                */
+               xfs_dqunlock(udq);
+               if (locked)
+                       xfs_dqunlock(gdq);
+               /*
+                * we took a hard reference once upon a time in dqget,
+                * so give it back when the udquot no longer points at it
+                * dqput() does the unlocking of the dquot.
+                */
+               xfs_qm_dqrele(tmp);
+
+               ASSERT(! XFS_DQ_IS_LOCKED(udq));
+               ASSERT(! XFS_DQ_IS_LOCKED(gdq));
+               xfs_dqlock(udq);
+               xfs_dqlock(gdq);
+
+       } else {
+               ASSERT(XFS_DQ_IS_LOCKED(udq));
+               if (! locked) {
+                       ASSERT(! XFS_DQ_IS_LOCKED(gdq));
+                       xfs_dqlock(gdq);
+               }
+       }
+
+       ASSERT(XFS_DQ_IS_LOCKED(udq));
+       ASSERT(XFS_DQ_IS_LOCKED(gdq));
+       /*
+        * Somebody could have attached a gdquot here,
+        * when we dropped the uqlock. If so, just do nothing.
+        */
+       if (udq->q_gdquot == NULL) {
+               XFS_DQHOLD(gdq);
+               udq->q_gdquot = gdq;
+       }
+       if (! locked) {
+               xfs_dqunlock(gdq);
+               xfs_dqunlock(udq);
+       }
+}
+
+
+/*
+ * Given a locked inode, attach dquot(s) to it, taking UQUOTAON / GQUOTAON
+ * in to account.
+ * If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed.
+ * If XFS_QMOPT_DQLOCK, the dquot(s) will be returned locked. This option pretty
+ * much made this code a complete mess, but it has been pretty useful.
+ * If XFS_QMOPT_ILOCKED, then inode sent is already locked EXCL.
+ * Inode may get unlocked and relocked in here, and the caller must deal with
+ * the consequences.
+ */
+int
+xfs_qm_dqattach(
+       xfs_inode_t     *ip,
+       uint            flags)
+{
+       xfs_mount_t     *mp = ip->i_mount;
+       uint            nquotas = 0;
+       int             error = 0;
+
+       if ((! XFS_IS_QUOTA_ON(mp)) ||
+           (! XFS_NOT_DQATTACHED(mp, ip)) ||
+           (ip->i_ino == mp->m_sb.sb_uquotino) ||
+           (ip->i_ino == mp->m_sb.sb_gquotino))
+               return (0);
+
+       ASSERT((flags & XFS_QMOPT_ILOCKED) == 0 ||
+              XFS_ISLOCKED_INODE_EXCL(ip));
+
+       if (! (flags & XFS_QMOPT_ILOCKED))
+               xfs_ilock(ip, XFS_ILOCK_EXCL);
+
+       if (XFS_IS_UQUOTA_ON(mp)) {
+               error = xfs_qm_dqattach_one(ip, ip->i_d.di_uid, XFS_DQ_USER,
+                                               flags & XFS_QMOPT_DQALLOC,
+                                               flags & XFS_QMOPT_DQLOCK,
+                                               NULL, &ip->i_udquot);
+               if (error)
+                       goto done;
+               nquotas++;
+       }
+       ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+       if (XFS_IS_GQUOTA_ON(mp)) {
+               error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
+                                               flags & XFS_QMOPT_DQALLOC,
+                                               flags & XFS_QMOPT_DQLOCK,
+                                               ip->i_udquot, &ip->i_gdquot);
+               /*
+                * Don't worry about the udquot that we may have
+                * attached above. It'll get detached, if not already.
+                */
+               if (error)
+                       goto done;
+               nquotas++;
+       }
+
+       /*
+        * Attach this group quota to the user quota as a hint.
+        * This WON'T, in general, result in a thrash.
+        */
+       if (nquotas == 2) {
+               ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+               ASSERT(ip->i_udquot);
+               ASSERT(ip->i_gdquot);
+
+               /*
+                * We may or may not have the i_udquot locked at this point,
+                * but this check is OK since we don't depend on the i_gdquot to
+                * be accurate 100% all the time. It is just a hint, and this
+                * will succeed in general.
+                */
+               if (ip->i_udquot->q_gdquot == ip->i_gdquot)
+                       goto done;
+               /*
+                * Attach i_gdquot to the gdquot hint inside the i_udquot.
+                */
+               xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot,
+                                        flags & XFS_QMOPT_DQLOCK);
+       }
+
+      done:
+
+#ifdef QUOTADEBUG
+       if (! error) {
+               if (ip->i_udquot) {
+                       if (flags & XFS_QMOPT_DQLOCK)
+                               ASSERT(XFS_DQ_IS_LOCKED(ip->i_udquot));
+                       else
+                               ASSERT(! XFS_DQ_IS_LOCKED(ip->i_udquot));
+               }
+               if (ip->i_gdquot) {
+                       if (flags & XFS_QMOPT_DQLOCK)
+                               ASSERT(XFS_DQ_IS_LOCKED(ip->i_gdquot));
+                       else
+                               ASSERT(! XFS_DQ_IS_LOCKED(ip->i_gdquot));
+               }
+               if (XFS_IS_UQUOTA_ON(mp))
+                       ASSERT(ip->i_udquot);
+               if (XFS_IS_GQUOTA_ON(mp))
+                       ASSERT(ip->i_gdquot);
+       }
+#endif
+
+       if (! (flags & XFS_QMOPT_ILOCKED))
+               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+
+#ifdef QUOTADEBUG
+       else
+               ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+#endif
+       return (error);
+}
+
+/*
+ * Release dquots (and their references) if any.
+ * The inode should be locked EXCL except when this's called by
+ * xfs_ireclaim.
+ */
+void
+xfs_qm_dqdetach(
+       xfs_inode_t     *ip)
+{
+       if (!(ip->i_udquot || ip->i_gdquot))
+               return;
+
+       ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino);
+       ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino);
+       if (ip->i_udquot)
+               xfs_dqtrace_entry_ino(ip->i_udquot, "DQDETTACH", ip);
+       if (ip->i_udquot) {
+               xfs_qm_dqrele(ip->i_udquot);
+               ip->i_udquot = NULL;
+       }
+       if (ip->i_gdquot) {
+               xfs_qm_dqrele(ip->i_gdquot);
+               ip->i_gdquot = NULL;
+       }
+}
+
+/*
+ * This is called by VFS_SYNC and flags arg determines the caller,
+ * and its motives, as done in xfs_sync.
+ *
+ * vfs_sync: SYNC_FSDATA|SYNC_ATTR|SYNC_BDFLUSH 0x31
+ * syscall sync: SYNC_FSDATA|SYNC_ATTR|SYNC_DELWRI 0x25
+ * umountroot : SYNC_WAIT | SYNC_CLOSE | SYNC_ATTR | SYNC_FSDATA
+ */
+
+int
+xfs_qm_sync(
+       xfs_mount_t     *mp,
+       short           flags)
+{
+       int             recl, restarts;
+       xfs_dquot_t     *dqp;
+       uint            flush_flags;
+       boolean_t       nowait;
+       int             error;
+
+       restarts = 0;
+       /*
+        * We won't block unless we are asked to.
+        */
+       nowait = (boolean_t)(flags & SYNC_BDFLUSH || (flags & SYNC_WAIT) == 0);
+
+  again:
+       xfs_qm_mplist_lock(mp);
+       /*
+        * dqpurge_all() also takes the mplist lock and iterate thru all dquots
+        * in quotaoff. However, if the QUOTA_ACTIVE bits are not cleared
+        * when we have the mplist lock, we know that dquots will be consistent
+        * as long as we have it locked.
+        */
+       if (! XFS_IS_QUOTA_ON(mp)) {
+               xfs_qm_mplist_unlock(mp);
+               return (0);
+       }
+       FOREACH_DQUOT_IN_MP(dqp, mp) {
+               /*
+                * If this is vfs_sync calling, then skip the dquots that
+                * don't 'seem' to be dirty. ie. don't acquire dqlock.
+                * This is very similar to what xfs_sync does with inodes.
+                */
+               if (flags & SYNC_BDFLUSH) {
+                       if (! XFS_DQ_IS_DIRTY(dqp))
+                               continue;
+               }
+
+               if (nowait) {
+                       /*
+                        * Try to acquire the dquot lock. We are NOT out of
+                        * lock order, but we just don't want to wait for this
+                        * lock, unless somebody wanted us to.
+                        */
+                       if (! xfs_qm_dqlock_nowait(dqp))
+                               continue;
+               } else {
+                       xfs_dqlock(dqp);
+               }
+
+               /*
+                * Now, find out for sure if this dquot is dirty or not.
+                */
+               if (! XFS_DQ_IS_DIRTY(dqp)) {
+                       xfs_dqunlock(dqp);
+                       continue;
+               }
+
+               /* XXX a sentinel would be better */
+               recl = XFS_QI_MPLRECLAIMS(mp);
+               if (! xfs_qm_dqflock_nowait(dqp)) {
+                       if (nowait) {
+                               xfs_dqunlock(dqp);
+                               continue;
+                       }
+                       /*
+                        * If we can't grab the flush lock then if the caller
+                        * really wanted us to give this our best shot,
+                        * see if we can give a push to the buffer before we wait
+                        * on the flush lock. At this point, we know that
+                        * eventhough the dquot is being flushed,
+                        * it has (new) dirty data.
+                        */
+                       xfs_qm_dqflock_pushbuf_wait(dqp);
+               }
+               /*
+                * Let go of the mplist lock. We don't want to hold it
+                * across a disk write
+                */
+               flush_flags = (nowait) ? XFS_QMOPT_DELWRI : XFS_QMOPT_SYNC;
+               xfs_qm_mplist_unlock(mp);
+               xfs_dqtrace_entry(dqp, "XQM_SYNC: DQFLUSH");
+               error = xfs_qm_dqflush(dqp, flush_flags);
+               xfs_dqunlock(dqp);
+               if (error && XFS_FORCED_SHUTDOWN(mp))
+                       return(0);      /* Need to prevent umount failure */
+               else if (error)
+                       return (error);
+
+               xfs_qm_mplist_lock(mp);
+               if (recl != XFS_QI_MPLRECLAIMS(mp)) {
+                       if (++restarts >= XFS_QM_SYNC_MAX_RESTARTS)
+                               break;
+
+                       xfs_qm_mplist_unlock(mp);
+                       goto again;
+               }
+       }
+
+       xfs_qm_mplist_unlock(mp);
+       return (0);
+}
+
+
+/*
+ * This initializes all the quota information that's kept in the
+ * mount structure
+ */
+int
+xfs_qm_init_quotainfo(
+       xfs_mount_t     *mp)
+{
+       xfs_quotainfo_t *qinf;
+       int             error;
+       xfs_dquot_t     *dqp;
+
+       ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+
+       /*
+        * Tell XQM that we exist as soon as possible.
+        */
+       if ((error = xfs_qm_hold_quotafs_ref(mp))) {
+               return (error);
+       }
+
+       qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), KM_SLEEP);
+
+       /*
+        * See if quotainodes are setup, and if not, allocate them,
+        * and change the superblock accordingly.
+        */
+       if ((error = xfs_qm_init_quotainos(mp))) {
+               kmem_free(qinf, sizeof(xfs_quotainfo_t));
+               mp->m_quotainfo = NULL;
+               return (error);
+       }
+
+       spinlock_init(&qinf->qi_pinlock, "xfs_qinf_pin");
+       xfs_qm_list_init(&qinf->qi_dqlist, "mpdqlist", 0);
+       qinf->qi_dqreclaims = 0;
+
+       /* mutex used to serialize quotaoffs */
+       mutex_init(&qinf->qi_quotaofflock, MUTEX_DEFAULT, "qoff");
+
+       /* Precalc some constants */
+       qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
+       ASSERT(qinf->qi_dqchunklen);
+       qinf->qi_dqperchunk = BBTOB(qinf->qi_dqchunklen);
+       do_div(qinf->qi_dqperchunk, sizeof(xfs_dqblk_t));
+
+       mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
+
+       /*
+        * We try to get the limits from the superuser's limits fields.
+        * This is quite hacky, but it is standard quota practice.
+        * We look at the USR dquot with id == 0 first, but if user quotas
+        * are not enabled we goto the GRP dquot with id == 0.
+        * We don't really care to keep separate default limits for user
+        * and group quotas, at least not at this point.
+        */
+       error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)0,
+                            (XFS_IS_UQUOTA_RUNNING(mp)) ?
+                            XFS_DQ_USER : XFS_DQ_GROUP,
+                            XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN,
+                            &dqp);
+       if (! error) {
+               /*
+                * The warnings and timers set the grace period given to
+                * a user or group before he or she can not perform any
+                * more writing. If it is zero, a default is used.
+                */
+               qinf->qi_btimelimit = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) ?
+                       INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) : XFS_QM_BTIMELIMIT;
+               qinf->qi_itimelimit = INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) ?
+                       INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) : XFS_QM_ITIMELIMIT;
+               qinf->qi_rtbtimelimit = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) ?
+                       INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) : XFS_QM_RTBTIMELIMIT;
+               qinf->qi_bwarnlimit = INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) ?
+                       INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) : XFS_QM_BWARNLIMIT;
+               qinf->qi_iwarnlimit = INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) ?
+                       INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) : XFS_QM_IWARNLIMIT;
+
+               /*
+                * We sent the XFS_QMOPT_DQSUSER flag to dqget because
+                * we don't want this dquot cached. We haven't done a
+                * quotacheck yet, and quotacheck doesn't like incore dquots.
+                */
+               xfs_qm_dqdestroy(dqp);
+       } else {
+               qinf->qi_btimelimit = XFS_QM_BTIMELIMIT;
+               qinf->qi_itimelimit = XFS_QM_ITIMELIMIT;
+               qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT;
+               qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT;
+               qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT;
+       }
+
+       return (0);
+}
+
+
+/*
+ * Gets called when unmounting a filesystem or when all quotas get
+ * turned off.
+ * This purges the quota inodes, destroys locks and frees itself.
+ */
+void
+xfs_qm_destroy_quotainfo(
+       xfs_mount_t     *mp)
+{
+       xfs_quotainfo_t *qi;
+
+       qi = mp->m_quotainfo;
+       ASSERT(qi != NULL);
+       ASSERT(xfs_Gqm != NULL);
+
+       /*
+        * Release the reference that XQM kept, so that we know
+        * when the XQM structure should be freed. We cannot assume
+        * that xfs_Gqm is non-null after this point.
+        */
+       xfs_qm_rele_quotafs_ref(mp);
+
+       spinlock_destroy(&qi->qi_pinlock);
+       xfs_qm_list_destroy(&qi->qi_dqlist);
+
+       if (qi->qi_uquotaip) {
+               XFS_PURGE_INODE(qi->qi_uquotaip);
+               qi->qi_uquotaip = NULL; /* paranoia */
+       }
+       if (qi->qi_gquotaip) {
+               XFS_PURGE_INODE(qi->qi_gquotaip);
+               qi->qi_gquotaip = NULL;
+       }
+       mutex_destroy(&qi->qi_quotaofflock);
+       kmem_free(qi, sizeof(xfs_quotainfo_t));
+       mp->m_quotainfo = NULL;
+}
+
+
+
+/* ------------------- PRIVATE STATIC FUNCTIONS ----------------------- */
+
+/* ARGSUSED */
+STATIC void
+xfs_qm_list_init(
+       xfs_dqlist_t    *list,
+       char            *str,
+       int             n)
+{
+       mutex_init(&list->qh_lock, MUTEX_DEFAULT, str);
+       list->qh_next = NULL;
+       list->qh_version = 0;
+       list->qh_nelems = 0;
+}
+
+STATIC void
+xfs_qm_list_destroy(
+       xfs_dqlist_t    *list)
+{
+       mutex_destroy(&(list->qh_lock));
+}
+
+
+/*
+ * Stripped down version of dqattach. This doesn't attach, or even look at the
+ * dquots attached to the inode. The rationale is that there won't be any
+ * attached at the time this is called from quotacheck.
+ */
+STATIC int
+xfs_qm_dqget_noattach(
+       xfs_inode_t     *ip,
+       xfs_dquot_t     **O_udqpp,
+       xfs_dquot_t     **O_gdqpp)
+{
+       int             error;
+       xfs_mount_t     *mp;
+       xfs_dquot_t     *udqp, *gdqp;
+
+       ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+       mp = ip->i_mount;
+       udqp = NULL;
+       gdqp = NULL;
+
+       if (XFS_IS_UQUOTA_ON(mp)) {
+               ASSERT(ip->i_udquot == NULL);
+               /*
+                * We want the dquot allocated if it doesn't exist.
+                */
+               if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_uid, XFS_DQ_USER,
+                                        XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN,
+                                        &udqp))) {
+                       /*
+                        * Shouldn't be able to turn off quotas here.
+                        */
+                       ASSERT(error != ESRCH);
+                       ASSERT(error != ENOENT);
+                       return (error);
+               }
+               ASSERT(udqp);
+       }
+
+       if (XFS_IS_GQUOTA_ON(mp)) {
+               ASSERT(ip->i_gdquot == NULL);
+               if (udqp)
+                       xfs_dqunlock(udqp);
+               if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_gid, XFS_DQ_GROUP,
+                                        XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN,
+                                        &gdqp))) {
+                       if (udqp)
+                               xfs_qm_dqrele(udqp);
+                       ASSERT(error != ESRCH);
+                       ASSERT(error != ENOENT);
+                       return (error);
+               }
+               ASSERT(gdqp);
+
+               /* Reacquire the locks in the right order */
+               if (udqp) {
+                       if (! xfs_qm_dqlock_nowait(udqp)) {
+                               xfs_dqunlock(gdqp);
+                               xfs_dqlock(udqp);
+                               xfs_dqlock(gdqp);
+                       }
+               }
+       }
+
+       *O_udqpp = udqp;
+       *O_gdqpp = gdqp;
+
+#ifdef QUOTADEBUG
+       if (udqp) ASSERT(XFS_DQ_IS_LOCKED(udqp));
+       if (gdqp) ASSERT(XFS_DQ_IS_LOCKED(gdqp));
+#endif
+       return (0);
+}
+
+/*
+ * Create an inode and return with a reference already taken, but unlocked
+ * This is how we create quota inodes
+ */
+STATIC int
+xfs_qm_qino_alloc(
+       xfs_mount_t     *mp,
+       xfs_inode_t     **ip,
+       __int64_t       sbfields,
+       uint            flags)
+{
+       xfs_trans_t     *tp;
+       int             error;
+       unsigned long s;
+       cred_t          zerocr;
+       int             committed;
+
+       tp = xfs_trans_alloc(mp,XFS_TRANS_QM_QINOCREATE);
+       if ((error = xfs_trans_reserve(tp,
+                                     XFS_QM_QINOCREATE_SPACE_RES(mp),
+                                     XFS_CREATE_LOG_RES(mp), 0,
+                                     XFS_TRANS_PERM_LOG_RES,
+                                     XFS_CREATE_LOG_COUNT))) {
+               xfs_trans_cancel(tp, 0);
+               return (error);
+       }
+       memset(&zerocr, 0, sizeof(zerocr));
+
+       if ((error = xfs_dir_ialloc(&tp, mp->m_rootip, IFREG, 1, 0,
+                                  &zerocr, 0, 1, ip, &committed))) {
+               xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
+                                XFS_TRANS_ABORT);
+               return (error);
+       }
+
+       /*
+        * Keep an extra reference to this quota inode. This inode is
+        * locked exclusively and joined to the transaction already.
+        */
+       ASSERT(XFS_ISLOCKED_INODE_EXCL(*ip));
+       VN_HOLD(XFS_ITOV((*ip)));
+
+       /*
+        * Make the changes in the superblock, and log those too.
+        * sbfields arg may contain fields other than *QUOTINO;
+        * VERSIONNUM for example.
+        */
+       s = XFS_SB_LOCK(mp);
+       if (flags & XFS_QMOPT_SBVERSION) {
+#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
+               unsigned oldv = mp->m_sb.sb_versionnum;
+#endif
+               ASSERT(!XFS_SB_VERSION_HASQUOTA(&mp->m_sb));
+               ASSERT((sbfields & (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
+                                  XFS_SB_GQUOTINO | XFS_SB_QFLAGS)) ==
+                      (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
+                       XFS_SB_GQUOTINO | XFS_SB_QFLAGS));
+
+               XFS_SB_VERSION_ADDQUOTA(&mp->m_sb);
+               mp->m_sb.sb_uquotino = NULLFSINO;
+               mp->m_sb.sb_gquotino = NULLFSINO;
+
+               /* qflags will get updated _after_ quotacheck */
+               mp->m_sb.sb_qflags = 0;
+#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
+               cmn_err(CE_NOTE,
+                       "Old superblock version %x, converting to %x.",
+                       oldv, mp->m_sb.sb_versionnum);
+#endif
+       }
+       if (flags & XFS_QMOPT_UQUOTA)
+               mp->m_sb.sb_uquotino = (*ip)->i_ino;
+       else
+               mp->m_sb.sb_gquotino = (*ip)->i_ino;
+       XFS_SB_UNLOCK(mp, s);
+       xfs_mod_sb(tp, sbfields);
+
+       if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
+                                    NULL))) {
+               xfs_fs_cmn_err(CE_ALERT, mp, "XFS qino_alloc failed!");
+               return (error);
+       }
+       return (0);
+}
+
+
+STATIC int
+xfs_qm_reset_dqcounts(
+       xfs_mount_t     *mp,
+       xfs_buf_t       *bp,
+       xfs_dqid_t      id,
+       uint            type)
+{
+       xfs_disk_dquot_t        *ddq;
+       int                     j;
+
+       xfs_buftrace("RESET DQUOTS", bp);
+       /*
+        * Reset all counters and timers. They'll be
+        * started afresh by xfs_qm_quotacheck.
+        */
+#ifdef DEBUG
+       j = XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
+       do_div(j, sizeof(xfs_dqblk_t));
+       ASSERT(XFS_QM_DQPERBLK(mp) == j);
+#endif
+       ddq = (xfs_disk_dquot_t *)XFS_BUF_PTR(bp);
+       for (j = 0; j < XFS_QM_DQPERBLK(mp); j++) {
+               /*
+                * Do a sanity check, and if needed, repair the dqblk. Don't
+                * output any warnings because it's perfectly possible to
+                * find unitialized dquot blks. See comment in xfs_qm_dqcheck.
+                */
+               (void) xfs_qm_dqcheck(ddq, id+j, type, XFS_QMOPT_DQREPAIR,
+                                     "xfs_quotacheck");
+               INT_SET(ddq->d_bcount, ARCH_CONVERT, 0ULL);
+               INT_SET(ddq->d_icount, ARCH_CONVERT, 0ULL);
+               INT_SET(ddq->d_rtbcount, ARCH_CONVERT, 0ULL);
+               INT_SET(ddq->d_btimer, ARCH_CONVERT, (time_t)0);
+               INT_SET(ddq->d_itimer, ARCH_CONVERT, (time_t)0);
+               INT_SET(ddq->d_bwarns, ARCH_CONVERT, 0UL);
+               INT_SET(ddq->d_iwarns, ARCH_CONVERT, 0UL);
+               ddq = (xfs_disk_dquot_t *) ((xfs_dqblk_t *)ddq + 1);
+       }
+
+       return (0);
+}
+
+STATIC int
+xfs_qm_dqiter_bufs(
+       xfs_mount_t     *mp,
+       xfs_dqid_t      firstid,
+       xfs_fsblock_t   bno,
+       xfs_filblks_t   blkcnt,
+       uint            flags)
+{
+       xfs_buf_t       *bp;
+       int             error;
+       int             notcommitted;
+       int             incr;
+
+       ASSERT(blkcnt > 0);
+       notcommitted = 0;
+       incr = (blkcnt > XFS_QM_MAX_DQCLUSTER_LOGSZ) ?
+               XFS_QM_MAX_DQCLUSTER_LOGSZ : blkcnt;
+       error = 0;
+
+       /*
+        * Blkcnt arg can be a very big number, and might even be
+        * larger than the log itself. So, we have to break it up into
+        * manageable-sized transactions.
+        * Note that we don't start a permanent transaction here; we might
+        * not be able to get a log reservation for the whole thing up front,
+        * and we don't really care to either, because we just discard
+        * everything if we were to crash in the middle of this loop.
+        */
+       while (blkcnt--) {
+               error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
+                             XFS_FSB_TO_DADDR(mp, bno),
+                             (int)XFS_QI_DQCHUNKLEN(mp), 0, &bp);
+               if (error)
+                       break;
+
+               (void) xfs_qm_reset_dqcounts(mp, bp, firstid,
+                                            flags & XFS_QMOPT_UQUOTA ?
+                                            XFS_DQ_USER : XFS_DQ_GROUP);
+               xfs_bdwrite(mp, bp);
+               /*
+                * goto the next block.
+                */
+               bno++;
+               firstid += XFS_QM_DQPERBLK(mp);
+       }
+       return (error);
+}
+
+/*
+ * Iterate over all allocated USR/GRP dquots in the system, calling a
+ * caller supplied function for every chunk of dquots that we find.
+ */
+STATIC int
+xfs_qm_dqiterate(
+       xfs_mount_t     *mp,
+       xfs_inode_t     *qip,
+       uint            flags)
+{
+       xfs_bmbt_irec_t         *map;
+       int                     i, nmaps;       /* number of map entries */
+       int                     error;          /* return value */
+       xfs_fileoff_t           lblkno;
+       xfs_filblks_t           maxlblkcnt;
+       xfs_dqid_t              firstid;
+       xfs_fsblock_t           rablkno;
+       xfs_filblks_t           rablkcnt;
+
+       error = 0;
+       /*
+        * This looks racey, but we can't keep an inode lock across a
+        * trans_reserve. But, this gets called during quotacheck, and that
+        * happens only at mount time which is single threaded.
+        */
+       if (qip->i_d.di_nblocks == 0)
+               return (0);
+
+       map = kmem_alloc(XFS_DQITER_MAP_SIZE * sizeof(*map), KM_SLEEP);
+
+       lblkno = 0;
+       maxlblkcnt = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAX_FILE_OFFSET);
+       do {
+               nmaps = XFS_DQITER_MAP_SIZE;
+               /*
+                * We aren't changing the inode itself. Just changing
+                * some of its data. No new blocks are added here, and
+                * the inode is never added to the transaction.
+                */
+               xfs_ilock(qip, XFS_ILOCK_SHARED);
+               error = xfs_bmapi(NULL, qip, lblkno,
+                                 maxlblkcnt - lblkno,
+                                 XFS_BMAPI_METADATA,
+                                 NULL,
+                                 0, map, &nmaps, NULL);
+               xfs_iunlock(qip, XFS_ILOCK_SHARED);
+               if (error)
+                       break;
+
+               ASSERT(nmaps <= XFS_DQITER_MAP_SIZE);
+               for (i = 0; i < nmaps; i++) {
+                       ASSERT(map[i].br_startblock != DELAYSTARTBLOCK);
+                       ASSERT(map[i].br_blockcount);
+
+
+                       lblkno += map[i].br_blockcount;
+
+                       if (map[i].br_startblock == HOLESTARTBLOCK)
+                               continue;
+
+                       firstid = (xfs_dqid_t) map[i].br_startoff *
+                               XFS_QM_DQPERBLK(mp);
+                       /*
+                        * Do a read-ahead on the next extent.
+                        */
+                       if ((i+1 < nmaps) &&
+                           (map[i+1].br_startblock != HOLESTARTBLOCK)) {
+                               rablkcnt =  map[i+1].br_blockcount;
+                               rablkno = map[i+1].br_startblock;
+                               while (rablkcnt--) {
+                                       xfs_baread(mp->m_ddev_targp,
+                                              XFS_FSB_TO_DADDR(mp, rablkno),
+                                              (int)XFS_QI_DQCHUNKLEN(mp));
+                                       rablkno++;
+                               }
+                       }
+                       /*
+                        * Iterate thru all the blks in the extent and
+                        * reset the counters of all the dquots inside them.
+                        */
+                       if ((error = xfs_qm_dqiter_bufs(mp,
+                                                      firstid,
+                                                      map[i].br_startblock,
+                                                      map[i].br_blockcount,
+                                                      flags))) {
+                               break;
+                       }
+               }
+
+               if (error)
+                       break;
+       } while (nmaps > 0);
+
+       kmem_free(map, XFS_DQITER_MAP_SIZE * sizeof(*map));
+
+       return (error);
+}
+
+/*
+ * Called by dqusage_adjust in doing a quotacheck.
+ * Given the inode, and a dquot (either USR or GRP, doesn't matter),
+ * this updates its incore copy as well as the buffer copy. This is
+ * so that once the quotacheck is done, we can just log all the buffers,
+ * as opposed to logging numerous updates to individual dquots.
+ */
+STATIC void
+xfs_qm_quotacheck_dqadjust(
+       xfs_dquot_t             *dqp,
+       xfs_qcnt_t              nblks,
+       xfs_qcnt_t              rtblks)
+{
+       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+       xfs_dqtrace_entry(dqp, "QCHECK DQADJUST");
+       /*
+        * Adjust the inode count and the block count to reflect this inode's
+        * resource usage.
+        */
+       INT_MOD(dqp->q_core.d_icount, ARCH_CONVERT, +1);
+       dqp->q_res_icount++;
+       if (nblks) {
+               INT_MOD(dqp->q_core.d_bcount, ARCH_CONVERT, nblks);
+               dqp->q_res_bcount += nblks;
+       }
+       if (rtblks) {
+               INT_MOD(dqp->q_core.d_rtbcount, ARCH_CONVERT, rtblks);
+               dqp->q_res_rtbcount += rtblks;
+       }
+
+       /*
+        * Adjust the timers since we just changed usages
+        */
+       if (! XFS_IS_SUSER_DQUOT(dqp))
+               xfs_qm_adjust_dqtimers(dqp->q_mount, &dqp->q_core);
+
+       dqp->dq_flags |= XFS_DQ_DIRTY;
+}
+
+STATIC int
+xfs_qm_get_rtblks(
+       xfs_inode_t     *ip,
+       xfs_qcnt_t      *O_rtblks)
+{
+       xfs_filblks_t   rtblks;                 /* total rt blks */
+       xfs_ifork_t     *ifp;                   /* inode fork pointer */
+       xfs_extnum_t    nextents;               /* number of extent entries */
+       xfs_bmbt_rec_t  *base;                  /* base of extent array */
+       xfs_bmbt_rec_t  *ep;                    /* pointer to an extent entry */
+       int             error;
+
+       ASSERT(XFS_IS_REALTIME_INODE(ip));
+       ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+       if (!(ifp->if_flags & XFS_IFEXTENTS)) {
+               if ((error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK)))
+                       return (error);
+       }
+       rtblks = 0;
+       nextents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t);
+       base = &ifp->if_u1.if_extents[0];
+       for (ep = base; ep < &base[nextents]; ep++)
+               rtblks += xfs_bmbt_get_blockcount(ep);
+       *O_rtblks = (xfs_qcnt_t)rtblks;
+       return (0);
+}
+
+/*
+ * callback routine supplied to bulkstat(). Given an inumber, find its
+ * dquots and update them to account for resources taken by that inode.
+ */
+/* ARGSUSED */
+STATIC int
+xfs_qm_dqusage_adjust(
+       xfs_mount_t     *mp,            /* mount point for filesystem */
+       xfs_trans_t     *tp,            /* transaction pointer - NULL */
+       xfs_ino_t       ino,            /* inode number to get data for */
+       void            *buffer,        /* not used */
+       xfs_daddr_t     bno,            /* starting block of inode cluster */
+       void            *dip,           /* on-disk inode pointer (not used) */
+       int             *res)           /* result code value */
+{
+       xfs_inode_t     *ip;
+       xfs_dquot_t     *udqp, *gdqp;
+       xfs_qcnt_t      nblks, rtblks;
+       int             error;
+
+       ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+
+       /*
+        * rootino must have its resources accounted for, not so with the quota
+        * inodes.
+        */
+       if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
+               *res = BULKSTAT_RV_NOTHING;
+               return XFS_ERROR(EINVAL);
+       }
+
+       /*
+        * We don't _need_ to take the ilock EXCL. However, the xfs_qm_dqget
+        * interface expects the inode to be exclusively locked because that's
+        * the case in all other instances. It's OK that we do this because
+        * quotacheck is done only at mount time.
+        */
+       if ((error = xfs_iget(mp, tp, ino, XFS_ILOCK_EXCL, &ip, bno))) {
+               *res = BULKSTAT_RV_NOTHING;
+               return (error);
+       }
+
+       if (ip->i_d.di_mode == 0) {
+               xfs_iput_new(ip, XFS_ILOCK_EXCL);
+               *res = BULKSTAT_RV_NOTHING;
+               return XFS_ERROR(ENOENT);
+       }
+
+       /*
+        * Obtain the locked dquots. In case of an error (eg. allocation
+        * fails for ENOSPC), we return the negative of the error number
+        * to bulkstat, so that it can get propagated to quotacheck() and
+        * making us disable quotas for the file system.
+        */
+       if ((error = xfs_qm_dqget_noattach(ip, &udqp, &gdqp))) {
+               xfs_iput(ip, XFS_ILOCK_EXCL);
+               *res = BULKSTAT_RV_GIVEUP;
+               return (error);
+       }
+
+       rtblks = 0;
+       if (! XFS_IS_REALTIME_INODE(ip)) {
+               nblks = (xfs_qcnt_t)ip->i_d.di_nblocks;
+       } else {
+               /*
+                * Walk thru the extent list and count the realtime blocks.
+                */
+               if ((error = xfs_qm_get_rtblks(ip, &rtblks))) {
+                       xfs_iput(ip, XFS_ILOCK_EXCL);
+                       if (udqp)
+                               xfs_qm_dqput(udqp);
+                       if (gdqp)
+                               xfs_qm_dqput(gdqp);
+                       *res = BULKSTAT_RV_GIVEUP;
+                       return (error);
+               }
+               nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks;
+       }
+       ASSERT(ip->i_delayed_blks == 0);
+
+       /*
+        * We can't release the inode while holding its dquot locks.
+        * The inode can go into inactive and might try to acquire the dquotlocks.
+        * So, just unlock here and do a vn_rele at the end.
+        */
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
+
+       /*
+        * Add the (disk blocks and inode) resources occupied by this
+        * inode to its dquots. We do this adjustment in the incore dquot,
+        * and also copy the changes to its buffer.
+        * We don't care about putting these changes in a transaction
+        * envelope because if we crash in the middle of a 'quotacheck'
+        * we have to start from the beginning anyway.
+        * Once we're done, we'll log all the dquot bufs.
+        *
+        * The *QUOTA_ON checks below may look pretty racey, but quotachecks
+        * and quotaoffs don't race. (Quotachecks happen at mount time only).
+        */
+       if (XFS_IS_UQUOTA_ON(mp)) {
+               ASSERT(udqp);
+               xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks);
+               xfs_qm_dqput(udqp);
+       }
+       if (XFS_IS_GQUOTA_ON(mp)) {
+               ASSERT(gdqp);
+               xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks);
+               xfs_qm_dqput(gdqp);
+       }
+       /*
+        * Now release the inode. This will send it to 'inactive', and
+        * possibly even free blocks.
+        */
+       VN_RELE(XFS_ITOV(ip));
+
+       /*
+        * Goto next inode.
+        */
+       *res = BULKSTAT_RV_DIDONE;
+       return (0);
+}
+
+/*
+ * Walk thru all the filesystem inodes and construct a consistent view
+ * of the disk quota world.
+ */
+STATIC int
+xfs_qm_quotacheck(
+       xfs_mount_t     *mp)
+{
+       int             done, count, error;
+       xfs_ino_t       lastino;
+       size_t          structsz;
+       xfs_inode_t     *uip, *gip;
+       uint            flags;
+
+       count = INT_MAX;
+       structsz = 1;
+       lastino = 0;
+       flags = 0;
+
+       ASSERT(XFS_QI_UQIP(mp) || XFS_QI_GQIP(mp));
+       ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+
+       /*
+        * There should be no cached dquots. The (simplistic) quotacheck
+        * algorithm doesn't like that.
+        */
+       ASSERT(XFS_QI_MPLNDQUOTS(mp) == 0);
+
+       cmn_err(CE_NOTE, "XFS quotacheck %s: Please wait.", mp->m_fsname);
+
+       /*
+        * First we go thru all the dquots on disk, USR and GRP, and reset
+        * their counters to zero. We need a clean slate.
+        * We don't log our changes till later.
+        */
+       if ((uip = XFS_QI_UQIP(mp))) {
+               if ((error = xfs_qm_dqiterate(mp, uip, XFS_QMOPT_UQUOTA)))
+                       goto error_return;
+               flags |= XFS_UQUOTA_CHKD;
+       }
+
+       if ((gip = XFS_QI_GQIP(mp))) {
+               if ((error = xfs_qm_dqiterate(mp, gip, XFS_QMOPT_GQUOTA)))
+                       goto error_return;
+               flags |= XFS_GQUOTA_CHKD;
+       }
+
+       do {
+               /*
+                * Iterate thru all the inodes in the file system,
+                * adjusting the corresponding dquot counters in core.
+                */
+               if ((error = xfs_bulkstat(mp, NULL, &lastino, &count,
+                                    xfs_qm_dqusage_adjust,
+                                    structsz, NULL,
+                                    BULKSTAT_FG_IGET|BULKSTAT_FG_VFSLOCKED,
+                                    &done)))
+                       break;
+
+       } while (! done);
+
+       /*
+        * We can get this error if we couldn't do a dquot allocation inside
+        * xfs_qm_dqusage_adjust (via bulkstat). We don't care about the
+        * dirty dquots that might be cached, we just want to get rid of them
+        * and turn quotaoff. The dquots won't be attached to any of the inodes
+        * at this point (because we intentionally didn't in dqget_noattach).
+        */
+       if (error) {
+               xfs_qm_dqpurge_all(mp,
+                                  XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA|
+                                  XFS_QMOPT_QUOTAOFF);
+               goto error_return;
+       }
+       /*
+        * We've made all the changes that we need to make incore.
+        * Now flush_them down to disk buffers.
+        */
+       xfs_qm_dqflush_all(mp, XFS_QMOPT_DELWRI);
+
+       /*
+        * We didn't log anything, because if we crashed, we'll have to
+        * start the quotacheck from scratch anyway. However, we must make
+        * sure that our dquot changes are secure before we put the
+        * quotacheck'd stamp on the superblock. So, here we do a synchronous
+        * flush.
+        */
+       XFS_bflush(mp->m_ddev_targp);
+
+       /*
+        * If one type of quotas is off, then it will lose its
+        * quotachecked status, since we won't be doing accounting for
+        * that type anymore.
+        */
+       mp->m_qflags &= ~(XFS_GQUOTA_CHKD | XFS_UQUOTA_CHKD);
+       mp->m_qflags |= flags;
+
+       XQM_LIST_PRINT(&(XFS_QI_MPL_LIST(mp)), MPL_NEXT, "++++ Mp list +++");
+
+ error_return:
+       cmn_err(CE_NOTE, "XFS quotacheck %s: Done.", mp->m_fsname);
+       return (error);
+}
+
+/*
+ * This is called after the superblock has been read in and we're ready to
+ * iget the quota inodes.
+ */
+STATIC int
+xfs_qm_init_quotainos(
+       xfs_mount_t     *mp)
+{
+       xfs_inode_t     *uip, *gip;
+       int             error;
+       __int64_t       sbflags;
+       uint            flags;
+
+       ASSERT(mp->m_quotainfo);
+       uip = gip = NULL;
+       sbflags = 0;
+       flags = 0;
+
+       /*
+        * Get the uquota and gquota inodes
+        */
+       if (XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) {
+               if (XFS_IS_UQUOTA_ON(mp) &&
+                   mp->m_sb.sb_uquotino != NULLFSINO) {
+                       ASSERT(mp->m_sb.sb_uquotino > 0);
+                       if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
+                                            0, &uip, 0)))
+                               return XFS_ERROR(error);
+               }
+               if (XFS_IS_GQUOTA_ON(mp) &&
+                   mp->m_sb.sb_gquotino != NULLFSINO) {
+                       ASSERT(mp->m_sb.sb_gquotino > 0);
+                       if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
+                                            0, &gip, 0))) {
+                               if (uip)
+                                       VN_RELE(XFS_ITOV(uip));
+                               return XFS_ERROR(error);
+                       }
+               }
+       } else {
+               flags |= XFS_QMOPT_SBVERSION;
+               sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
+                           XFS_SB_GQUOTINO | XFS_SB_QFLAGS);
+       }
+
+       /*
+        * Create the two inodes, if they don't exist already. The changes
+        * made above will get added to a transaction and logged in one of
+        * the qino_alloc calls below.  If the device is readonly,
+        * temporarily switch to read-write to do this.
+        */
+       if (XFS_IS_UQUOTA_ON(mp) && uip == NULL) {
+               if ((error = xfs_qm_qino_alloc(mp, &uip,
+                                             sbflags | XFS_SB_UQUOTINO,
+                                             flags | XFS_QMOPT_UQUOTA)))
+                       return XFS_ERROR(error);
+
+               flags &= ~XFS_QMOPT_SBVERSION;
+       }
+       if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) {
+               if ((error = xfs_qm_qino_alloc(mp, &gip,
+                                             sbflags | XFS_SB_GQUOTINO,
+                                             flags | XFS_QMOPT_GQUOTA))) {
+                       if (uip)
+                               VN_RELE(XFS_ITOV(uip));
+
+                       return XFS_ERROR(error);
+               }
+       }
+
+       XFS_QI_UQIP(mp) = uip;
+       XFS_QI_GQIP(mp) = gip;
+
+       return (0);
+}
+
+
+/*
+ * Traverse the freelist of dquots and attempt to reclaim a maximum of
+ * 'howmany' dquots. This operation races with dqlookup(), and attempts to
+ * favor the lookup function ...
+ * XXXsup merge this with qm_reclaim_one().
+ */
+STATIC int
+xfs_qm_shake_freelist(
+       int howmany)
+{
+       int             nreclaimed;
+       xfs_dqhash_t    *hash;
+       xfs_dquot_t     *dqp, *nextdqp;
+       int             restarts;
+       int             nflushes;
+
+       if (howmany <= 0)
+               return (0);
+
+       nreclaimed = 0;
+       restarts = 0;
+       nflushes = 0;
+
+#ifdef QUOTADEBUG
+       cmn_err(CE_DEBUG, "Shake free 0x%x", howmany);
+#endif
+       /* lock order is : hashchainlock, freelistlock, mplistlock */
+ tryagain:
+       xfs_qm_freelist_lock(xfs_Gqm);
+
+       for (dqp = xfs_Gqm->qm_dqfreelist.qh_next;
+            ((dqp != (xfs_dquot_t *) &xfs_Gqm->qm_dqfreelist) &&
+             nreclaimed < howmany); ) {
+               xfs_dqlock(dqp);
+
+               /*
+                * We are racing with dqlookup here. Naturally we don't
+                * want to reclaim a dquot that lookup wants.
+                */
+               if (dqp->dq_flags & XFS_DQ_WANT) {
+                       xfs_dqunlock(dqp);
+                       xfs_qm_freelist_unlock(xfs_Gqm);
+                       if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
+                               return (nreclaimed != howmany);
+                       XQM_STATS_INC(xqmstats.xs_qm_dqwants);
+                       goto tryagain;
+               }
+
+               /*
+                * If the dquot is inactive, we are assured that it is
+                * not on the mplist or the hashlist, and that makes our
+                * life easier.
+                */
+               if (dqp->dq_flags & XFS_DQ_INACTIVE) {
+                       ASSERT(dqp->q_mount == NULL);
+                       ASSERT(! XFS_DQ_IS_DIRTY(dqp));
+                       ASSERT(dqp->HL_PREVP == NULL);
+                       ASSERT(dqp->MPL_PREVP == NULL);
+                       XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);
+                       nextdqp = dqp->dq_flnext;
+                       goto off_freelist;
+               }
+
+               ASSERT(dqp->MPL_PREVP);
+               /*
+                * Try to grab the flush lock. If this dquot is in the process of
+                * getting flushed to disk, we don't want to reclaim it.
+                */
+               if (! xfs_qm_dqflock_nowait(dqp)) {
+                       xfs_dqunlock(dqp);
+                       dqp = dqp->dq_flnext;
+                       continue;
+               }
+
+               /*
+                * We have the flush lock so we know that this is not in the
+                * process of being flushed. So, if this is dirty, flush it
+                * DELWRI so that we don't get a freelist infested with
+                * dirty dquots.
+                */
+               if (XFS_DQ_IS_DIRTY(dqp)) {
+                       xfs_dqtrace_entry(dqp, "DQSHAKE: DQDIRTY");
+                       /*
+                        * We flush it delayed write, so don't bother
+                        * releasing the mplock.
+                        */
+                       (void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI);
+                       xfs_dqunlock(dqp); /* dqflush unlocks dqflock */
+                       dqp = dqp->dq_flnext;
+                       continue;
+               }
+               /*
+                * We're trying to get the hashlock out of order. This races
+                * with dqlookup; so, we giveup and goto the next dquot if
+                * we couldn't get the hashlock. This way, we won't starve
+                * a dqlookup process that holds the hashlock that is
+                * waiting for the freelist lock.
+                */
+               if (! xfs_qm_dqhashlock_nowait(dqp)) {
+                       xfs_dqfunlock(dqp);
+                       xfs_dqunlock(dqp);
+                       dqp = dqp->dq_flnext;
+                       continue;
+               }
+               /*
+                * This races with dquot allocation code as well as dqflush_all
+                * and reclaim code. So, if we failed to grab the mplist lock,
+                * giveup everything and start over.
+                */
+               hash = dqp->q_hash;
+               ASSERT(hash);
+               if (! xfs_qm_mplist_nowait(dqp->q_mount)) {
+                       /* XXX put a sentinel so that we can come back here */
+                       xfs_dqfunlock(dqp);
+                       xfs_dqunlock(dqp);
+                       XFS_DQ_HASH_UNLOCK(hash);
+                       xfs_qm_freelist_unlock(xfs_Gqm);
+                       if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
+                               return (nreclaimed != howmany);
+                       goto tryagain;
+               }
+               xfs_dqtrace_entry(dqp, "DQSHAKE: UNLINKING");
+#ifdef QUOTADEBUG
+               cmn_err(CE_DEBUG, "Shake 0x%p, ID 0x%x\n",
+                       dqp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT));
+#endif
+               ASSERT(dqp->q_nrefs == 0);
+               nextdqp = dqp->dq_flnext;
+               XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp);
+               XQM_HASHLIST_REMOVE(hash, dqp);
+               xfs_dqfunlock(dqp);
+               xfs_qm_mplist_unlock(dqp->q_mount);
+               XFS_DQ_HASH_UNLOCK(hash);
+
+ off_freelist:
+               XQM_FREELIST_REMOVE(dqp);
+               xfs_dqunlock(dqp);
+               nreclaimed++;
+               XQM_STATS_INC(xqmstats.xs_qm_dqshake_reclaims);
+               xfs_qm_dqdestroy(dqp);
+               dqp = nextdqp;
+       }
+       xfs_qm_freelist_unlock(xfs_Gqm);
+       return (nreclaimed != howmany);
+}
+
+
+/*
+ * The shake manager routine called by shaked() when memory is
+ * running low.
+ */
+/* ARGSUSED */
+STATIC void
+xfs_qm_shake(void)
+{
+       int     ndqused, nfree, n;
+
+       if (!xfs_Gqm)
+               return;
+
+       nfree = xfs_Gqm->qm_dqfreelist.qh_nelems; /* free dquots */
+       /* incore dquots in all f/s's */
+       ndqused = atomic_read(&xfs_Gqm->qm_totaldquots) - nfree;
+
+       ASSERT(ndqused >= 0);
+
+       if (nfree <= ndqused && nfree < ndquot)
+               return;
+
+       ndqused *= xfs_Gqm->qm_dqfree_ratio;    /* target # of free dquots */
+       n = nfree - ndqused - ndquot;           /* # over target */
+
+       (void) xfs_qm_shake_freelist(MAX(nfree, n));
+}
+
+
+/*
+ * Just pop the least recently used dquot off the freelist and
+ * recycle it. The returned dquot is locked.
+ */
+STATIC xfs_dquot_t *
+xfs_qm_dqreclaim_one(void)
+{
+       xfs_dquot_t     *dqpout;
+       xfs_dquot_t     *dqp;
+       int             restarts;
+       int             nflushes;
+
+       restarts = 0;
+       dqpout = NULL;
+       nflushes = 0;
+
+       /* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */
+ startagain:
+       xfs_qm_freelist_lock(xfs_Gqm);
+
+       FOREACH_DQUOT_IN_FREELIST(dqp, &(xfs_Gqm->qm_dqfreelist)) {
+               xfs_dqlock(dqp);
+
+               /*
+                * We are racing with dqlookup here. Naturally we don't
+                * want to reclaim a dquot that lookup wants. We release the
+                * freelist lock and start over, so that lookup will grab
+                * both the dquot and the freelistlock.
+                */
+               if (dqp->dq_flags & XFS_DQ_WANT) {
+                       ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE));
+                       xfs_dqtrace_entry(dqp, "DQRECLAIM: DQWANT");
+                       xfs_dqunlock(dqp);
+                       xfs_qm_freelist_unlock(xfs_Gqm);
+                       if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
+                               return (NULL);
+                       XQM_STATS_INC(xqmstats.xs_qm_dqwants);
+                       goto startagain;
+               }
+
+               /*
+                * If the dquot is inactive, we are assured that it is
+                * not on the mplist or the hashlist, and that makes our
+                * life easier.
+                */
+               if (dqp->dq_flags & XFS_DQ_INACTIVE) {
+                       ASSERT(dqp->q_mount == NULL);
+                       ASSERT(! XFS_DQ_IS_DIRTY(dqp));
+                       ASSERT(dqp->HL_PREVP == NULL);
+                       ASSERT(dqp->MPL_PREVP == NULL);
+                       XQM_FREELIST_REMOVE(dqp);
+                       xfs_dqunlock(dqp);
+                       dqpout = dqp;
+                       XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);
+                       break;
+               }
+
+               ASSERT(dqp->q_hash);
+               ASSERT(dqp->MPL_PREVP);
+
+               /*
+                * Try to grab the flush lock. If this dquot is in the process of
+                * getting flushed to disk, we don't want to reclaim it.
+                */
+               if (! xfs_qm_dqflock_nowait(dqp)) {
+                       xfs_dqunlock(dqp);
+                       continue;
+               }
+
+               /*
+                * We have the flush lock so we know that this is not in the
+                * process of being flushed. So, if this is dirty, flush it
+                * DELWRI so that we don't get a freelist infested with
+                * dirty dquots.
+                */
+               if (XFS_DQ_IS_DIRTY(dqp)) {
+                       xfs_dqtrace_entry(dqp, "DQRECLAIM: DQDIRTY");
+                       /*
+                        * We flush it delayed write, so don't bother
+                        * releasing the freelist lock.
+                        */
+                       (void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI);
+                       xfs_dqunlock(dqp); /* dqflush unlocks dqflock */
+                       continue;
+               }
+
+               if (! xfs_qm_mplist_nowait(dqp->q_mount)) {
+                       xfs_dqfunlock(dqp);
+                       xfs_dqunlock(dqp);
+                       continue;
+               }
+
+               if (! xfs_qm_dqhashlock_nowait(dqp))
+                       goto mplistunlock;
+
+               ASSERT(dqp->q_nrefs == 0);
+               xfs_dqtrace_entry(dqp, "DQRECLAIM: UNLINKING");
+               XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp);
+               XQM_HASHLIST_REMOVE(dqp->q_hash, dqp);
+               XQM_FREELIST_REMOVE(dqp);
+               dqpout = dqp;
+               XFS_DQ_HASH_UNLOCK(dqp->q_hash);
+ mplistunlock:
+               xfs_qm_mplist_unlock(dqp->q_mount);
+               xfs_dqfunlock(dqp);
+               xfs_dqunlock(dqp);
+               if (dqpout)
+                       break;
+       }
+
+       xfs_qm_freelist_unlock(xfs_Gqm);
+       return (dqpout);
+}
+
+
+/*------------------------------------------------------------------*/
+
+/*
+ * Return a new incore dquot. Depending on the number of
+ * dquots in the system, we either allocate a new one on the kernel heap,
+ * or reclaim a free one.
+ * Return value is B_TRUE if we allocated a new dquot, B_FALSE if we managed
+ * to reclaim an existing one from the freelist.
+ */
+boolean_t
+xfs_qm_dqalloc_incore(
+       xfs_dquot_t **O_dqpp)
+{
+       xfs_dquot_t     *dqp;
+
+       /*
+        * Check against high water mark to see if we want to pop
+        * a nincompoop dquot off the freelist.
+        */
+       if (atomic_read(&xfs_Gqm->qm_totaldquots) >= ndquot) {
+               /*
+                * Try to recycle a dquot from the freelist.
+                */
+               if ((dqp = xfs_qm_dqreclaim_one())) {
+                       XQM_STATS_INC(xqmstats.xs_qm_dqreclaims);
+                       /*
+                        * Just zero the core here. The rest will get
+                        * reinitialized by caller. XXX we shouldn't even
+                        * do this zero ...
+                        */
+                       memset(&dqp->q_core, 0, sizeof(dqp->q_core));
+                       *O_dqpp = dqp;
+                       return (B_FALSE);
+               }
+               XQM_STATS_INC(xqmstats.xs_qm_dqreclaim_misses);
+       }
+
+       /*
+        * Allocate a brand new dquot on the kernel heap and return it
+        * to the caller to initialize.
+        */
+       ASSERT(xfs_Gqm->qm_dqzone != NULL);
+       *O_dqpp = kmem_zone_zalloc(xfs_Gqm->qm_dqzone, KM_SLEEP);
+       atomic_inc(&xfs_Gqm->qm_totaldquots);
+
+       return (B_TRUE);
+}
+
+
+/*
+ * Start a transaction and write the incore superblock changes to
+ * disk. flags parameter indicates which fields have changed.
+ */
+int
+xfs_qm_write_sb_changes(
+       xfs_mount_t     *mp,
+       __int64_t       flags)
+{
+       xfs_trans_t     *tp;
+       int             error;
+
+#ifdef QUOTADEBUG
+       cmn_err(CE_NOTE, "Writing superblock quota changes :%s", mp->m_fsname);
+#endif
+       tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
+       if ((error = xfs_trans_reserve(tp, 0,
+                                     mp->m_sb.sb_sectsize + 128, 0,
+                                     0,
+                                     XFS_DEFAULT_LOG_COUNT))) {
+               xfs_trans_cancel(tp, 0);
+               return (error);
+       }
+
+       xfs_mod_sb(tp, flags);
+       (void) xfs_trans_commit(tp, 0, NULL);
+
+       return (0);
+}
+
+
+/* --------------- utility functions for vnodeops ---------------- */
+
+
+/*
+ * Given an inode, a uid and gid (from cred_t) make sure that we have
+ * allocated relevant dquot(s) on disk, and that we won't exceed inode
+ * quotas by creating this file.
+ * This also attaches dquot(s) to the given inode after locking it,
+ * and returns the dquots corresponding to the uid and/or gid.
+ *
+ * in  : inode (unlocked)
+ * out : udquot, gdquot with references taken and unlocked
+ */
+int
+xfs_qm_vop_dqalloc(
+       xfs_mount_t     *mp,
+       xfs_inode_t     *ip,
+       uid_t           uid,
+       gid_t           gid,
+       uint            flags,
+       xfs_dquot_t     **O_udqpp,
+       xfs_dquot_t     **O_gdqpp)
+{
+       int             error;
+       xfs_dquot_t     *uq, *gq;
+       uint            lockflags;
+
+       if (!XFS_IS_QUOTA_ON(mp))
+               return 0;
+
+       lockflags = XFS_ILOCK_EXCL;
+       xfs_ilock(ip, lockflags);
+
+       if ((flags & XFS_QMOPT_INHERIT) &&
+           XFS_INHERIT_GID(ip, XFS_MTOVFS(mp)))
+               gid = ip->i_d.di_gid;
+
+       /*
+        * Attach the dquot(s) to this inode, doing a dquot allocation
+        * if necessary. The dquot(s) will not be locked.
+        */
+       if (XFS_NOT_DQATTACHED(mp, ip)) {
+               if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_DQALLOC |
+                                           XFS_QMOPT_ILOCKED))) {
+                       xfs_iunlock(ip, lockflags);
+                       return (error);
+               }
+       }
+
+       uq = gq = NULL;
+       if ((flags & XFS_QMOPT_UQUOTA) &&
+           XFS_IS_UQUOTA_ON(mp)) {
+               if (ip->i_d.di_uid != uid) {
+                       /*
+                        * What we need is the dquot that has this uid, and
+                        * if we send the inode to dqget, the uid of the inode
+                        * takes priority over what's sent in the uid argument.
+                        * We must unlock inode here before calling dqget if
+                        * we're not sending the inode, because otherwise
+                        * we'll deadlock by doing trans_reserve while
+                        * holding ilock.
+                        */
+                       xfs_iunlock(ip, lockflags);
+                       if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t) uid,
+                                                XFS_DQ_USER,
+                                                XFS_QMOPT_DQALLOC |
+                                                XFS_QMOPT_DOWARN,
+                                                &uq))) {
+                               ASSERT(error != ENOENT);
+                               return (error);
+                       }
+                       /*
+                        * Get the ilock in the right order.
+                        */
+                       xfs_dqunlock(uq);
+                       lockflags = XFS_ILOCK_SHARED;
+                       xfs_ilock(ip, lockflags);
+               } else {
+                       /*
+                        * Take an extra reference, because we'll return
+                        * this to caller
+                        */
+                       ASSERT(ip->i_udquot);
+                       uq = ip->i_udquot;
+                       xfs_dqlock(uq);
+                       XFS_DQHOLD(uq);
+                       xfs_dqunlock(uq);
+               }
+       }
+       if ((flags & XFS_QMOPT_GQUOTA) &&
+           XFS_IS_GQUOTA_ON(mp)) {
+               if (ip->i_d.di_gid != gid) {
+                       xfs_iunlock(ip, lockflags);
+                       if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid,
+                                                XFS_DQ_GROUP,
+                                                XFS_QMOPT_DQALLOC |
+                                                XFS_QMOPT_DOWARN,
+                                                &gq))) {
+                               if (uq)
+                                       xfs_qm_dqrele(uq);
+                               ASSERT(error != ENOENT);
+                               return (error);
+                       }
+                       xfs_dqunlock(gq);
+                       lockflags = XFS_ILOCK_SHARED;
+                       xfs_ilock(ip, lockflags);
+               } else {
+                       ASSERT(ip->i_gdquot);
+                       gq = ip->i_gdquot;
+                       xfs_dqlock(gq);
+                       XFS_DQHOLD(gq);
+                       xfs_dqunlock(gq);
+               }
+       }
+       if (uq)
+               xfs_dqtrace_entry_ino(uq, "DQALLOC", ip);
+
+       xfs_iunlock(ip, lockflags);
+       if (O_udqpp)
+               *O_udqpp = uq;
+       else if (uq)
+               xfs_qm_dqrele(uq);
+       if (O_gdqpp)
+               *O_gdqpp = gq;
+       else if (gq)
+               xfs_qm_dqrele(gq);
+       return (0);
+}
+
+/*
+ * Actually transfer ownership, and do dquot modifications.
+ * These were already reserved.
+ */
+xfs_dquot_t *
+xfs_qm_vop_chown(
+       xfs_trans_t     *tp,
+       xfs_inode_t     *ip,
+       xfs_dquot_t     **IO_olddq,
+       xfs_dquot_t     *newdq)
+{
+       xfs_dquot_t     *prevdq;
+       ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+       ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
+
+       /* old dquot */
+       prevdq = *IO_olddq;
+       ASSERT(prevdq);
+       ASSERT(prevdq != newdq);
+
+       xfs_trans_mod_dquot(tp, prevdq,
+                           XFS_TRANS_DQ_BCOUNT,
+                           -(ip->i_d.di_nblocks));
+       xfs_trans_mod_dquot(tp, prevdq,
+                           XFS_TRANS_DQ_ICOUNT,
+                           -1);
+
+       /* the sparkling new dquot */
+       xfs_trans_mod_dquot(tp, newdq,
+                           XFS_TRANS_DQ_BCOUNT,
+                           ip->i_d.di_nblocks);
+       xfs_trans_mod_dquot(tp, newdq,
+                           XFS_TRANS_DQ_ICOUNT,
+                           1);
+
+       /*
+        * Take an extra reference, because the inode
+        * is going to keep this dquot pointer even
+        * after the trans_commit.
+        */
+       xfs_dqlock(newdq);
+       XFS_DQHOLD(newdq);
+       xfs_dqunlock(newdq);
+       *IO_olddq = newdq;
+
+       return (prevdq);
+}
+
+/*
+ * Quota reservations for setattr(AT_UID|AT_GID).
+ */
+int
+xfs_qm_vop_chown_reserve(
+       xfs_trans_t     *tp,
+       xfs_inode_t     *ip,
+       xfs_dquot_t     *udqp,
+       xfs_dquot_t     *gdqp,
+       uint            flags)
+{
+       int             error;
+       xfs_mount_t     *mp;
+       uint            delblks;
+       xfs_dquot_t     *unresudq, *unresgdq, *delblksudq, *delblksgdq;
+
+       ASSERT(XFS_ISLOCKED_INODE(ip));
+       mp = ip->i_mount;
+       ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+
+       delblks = ip->i_delayed_blks;
+       delblksudq = delblksgdq = unresudq = unresgdq = NULL;
+
+       if (XFS_IS_UQUOTA_ON(mp) && udqp &&
+           ip->i_d.di_uid != (uid_t)INT_GET(udqp->q_core.d_id, ARCH_CONVERT)) {
+               delblksudq = udqp;
+               /*
+                * If there are delayed allocation blocks, then we have to
+                * unreserve those from the old dquot, and add them to the
+                * new dquot.
+                */
+               if (delblks) {
+                       ASSERT(ip->i_udquot);
+                       unresudq = ip->i_udquot;
+               }
+       }
+       if (XFS_IS_GQUOTA_ON(ip->i_mount) && gdqp &&
+           ip->i_d.di_gid != INT_GET(gdqp->q_core.d_id, ARCH_CONVERT)) {
+               delblksgdq = gdqp;
+               if (delblks) {
+                       ASSERT(ip->i_gdquot);
+                       unresgdq = ip->i_gdquot;
+               }
+       }
+
+       if ((error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
+                               delblksudq, delblksgdq, ip->i_d.di_nblocks, 1,
+                               flags | XFS_QMOPT_RES_REGBLKS)))
+               return (error);
+
+       /*
+        * Do the delayed blks reservations/unreservations now. Since, these
+        * are done without the help of a transaction, if a reservation fails
+        * its previous reservations won't be automatically undone by trans
+        * code. So, we have to do it manually here.
+        */
+       if (delblks) {
+               /*
+                * Do the reservations first. Unreservation can't fail.
+                */
+               ASSERT(delblksudq || delblksgdq);
+               ASSERT(unresudq || unresgdq);
+               if ((error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
+                               delblksudq, delblksgdq, (xfs_qcnt_t)delblks, 0,
+                               flags | XFS_QMOPT_RES_REGBLKS)))
+                       return (error);
+               xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
+                               unresudq, unresgdq, -((xfs_qcnt_t)delblks), 0,
+                               XFS_QMOPT_RES_REGBLKS);
+       }
+
+       return (0);
+}
+
+int
+xfs_qm_vop_rename_dqattach(
+       xfs_inode_t     **i_tab)
+{
+       xfs_inode_t     *ip;
+       int             i;
+       int             error;
+
+       ip = i_tab[0];
+
+       if (! XFS_IS_QUOTA_ON(ip->i_mount))
+               return (0);
+
+       if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
+               error = xfs_qm_dqattach(ip, 0);
+               if (error)
+                       return (error);
+       }
+       for (i = 1; (i < 4 && i_tab[i]); i++) {
+               /*
+                * Watch out for duplicate entries in the table.
+                */
+               if ((ip = i_tab[i]) != i_tab[i-1]) {
+                       if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
+                               error = xfs_qm_dqattach(ip, 0);
+                               if (error)
+                                       return (error);
+                       }
+               }
+       }
+       return (0);
+}
+
+void
+xfs_qm_vop_dqattach_and_dqmod_newinode(
+       xfs_trans_t     *tp,
+       xfs_inode_t     *ip,
+       xfs_dquot_t     *udqp,
+       xfs_dquot_t     *gdqp)
+{
+       if (!XFS_IS_QUOTA_ON(tp->t_mountp))
+               return;
+
+       ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+       ASSERT(XFS_IS_QUOTA_RUNNING(tp->t_mountp));
+
+       if (udqp) {
+               xfs_dqlock(udqp);
+               XFS_DQHOLD(udqp);
+               xfs_dqunlock(udqp);
+               ASSERT(ip->i_udquot == NULL);
+               ip->i_udquot = udqp;
+               ASSERT(ip->i_d.di_uid == INT_GET(udqp->q_core.d_id, ARCH_CONVERT));
+               xfs_trans_mod_dquot(tp, udqp, XFS_TRANS_DQ_ICOUNT, 1);
+       }
+       if (gdqp) {
+               xfs_dqlock(gdqp);
+               XFS_DQHOLD(gdqp);
+               xfs_dqunlock(gdqp);
+               ASSERT(ip->i_gdquot == NULL);
+               ip->i_gdquot = gdqp;
+               ASSERT(ip->i_d.di_gid == INT_GET(gdqp->q_core.d_id, ARCH_CONVERT));
+               xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1);
+       }
+}
+
+/* ------------- list stuff -----------------*/
+void
+xfs_qm_freelist_init(xfs_frlist_t *ql)
+{
+       ql->qh_next = ql->qh_prev = (xfs_dquot_t *) ql;
+       mutex_init(&ql->qh_lock, MUTEX_DEFAULT, "dqf");
+       ql->qh_version = 0;
+       ql->qh_nelems = 0;
+}
+
+void
+xfs_qm_freelist_destroy(xfs_frlist_t *ql)
+{
+       xfs_dquot_t     *dqp, *nextdqp;
+
+       mutex_lock(&ql->qh_lock, PINOD);
+       for (dqp = ql->qh_next;
+            dqp != (xfs_dquot_t *)ql; ) {
+               xfs_dqlock(dqp);
+               nextdqp = dqp->dq_flnext;
+#ifdef QUOTADEBUG
+               cmn_err(CE_DEBUG, "FREELIST destroy 0x%p", dqp);
+#endif
+               XQM_FREELIST_REMOVE(dqp);
+               xfs_dqunlock(dqp);
+               xfs_qm_dqdestroy(dqp);
+               dqp = nextdqp;
+       }
+       /*
+        * Don't bother about unlocking.
+        */
+       mutex_destroy(&ql->qh_lock);
+
+       ASSERT(ql->qh_nelems == 0);
+}
+
+void
+xfs_qm_freelist_insert(xfs_frlist_t *ql, xfs_dquot_t *dq)
+{
+       dq->dq_flnext = ql->qh_next;
+       dq->dq_flprev = (xfs_dquot_t *)ql;
+       ql->qh_next = dq;
+       dq->dq_flnext->dq_flprev = dq;
+       xfs_Gqm->qm_dqfreelist.qh_nelems++;
+       xfs_Gqm->qm_dqfreelist.qh_version++;
+}
+
+void
+xfs_qm_freelist_unlink(xfs_dquot_t *dq)
+{
+       xfs_dquot_t *next = dq->dq_flnext;
+       xfs_dquot_t *prev = dq->dq_flprev;
+
+       next->dq_flprev = prev;
+       prev->dq_flnext = next;
+       dq->dq_flnext = dq->dq_flprev = dq;
+       xfs_Gqm->qm_dqfreelist.qh_nelems--;
+       xfs_Gqm->qm_dqfreelist.qh_version++;
+}
+
+void
+xfs_qm_freelist_append(xfs_frlist_t *ql, xfs_dquot_t *dq)
+{
+       xfs_qm_freelist_insert((xfs_frlist_t *)ql->qh_prev, dq);
+}
+
+int
+xfs_qm_dqhashlock_nowait(
+       xfs_dquot_t *dqp)
+{
+       int locked;
+
+       locked = mutex_trylock(&((dqp)->q_hash->qh_lock));
+       return (locked);
+}
+
+int
+xfs_qm_freelist_lock_nowait(
+       xfs_qm_t *xqm)
+{
+       int locked;
+
+       locked = mutex_trylock(&(xqm->qm_dqfreelist.qh_lock));
+       return (locked);
+}
+
+int
+xfs_qm_mplist_nowait(
+       xfs_mount_t     *mp)
+{
+       int locked;
+
+       ASSERT(mp->m_quotainfo);
+       locked = mutex_trylock(&(XFS_QI_MPLLOCK(mp)));
+       return (locked);
+}
diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/quota/xfs_qm.h
new file mode 100644 (file)
index 0000000..c4bc3ab
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.         Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_QM_H__
+#define __XFS_QM_H__
+
+#include "xfs_dquot_item.h"
+#include "xfs_dquot.h"
+#include "xfs_quota_priv.h"
+#include "xfs_qm_stats.h"
+
+struct xfs_qm;
+struct xfs_inode;
+
+extern mutex_t         xfs_Gqm_lock;
+extern struct xfs_qm   *xfs_Gqm;
+extern kmem_zone_t     *qm_dqzone;
+extern kmem_zone_t     *qm_dqtrxzone;
+
+/*
+ * Used in xfs_qm_sync called by xfs_sync to count the max times that it can
+ * iterate over the mountpt's dquot list in one call.
+ */
+#define XFS_QM_SYNC_MAX_RESTARTS       7
+
+/*
+ * Ditto, for xfs_qm_dqreclaim_one.
+ */
+#define XFS_QM_RECLAIM_MAX_RESTARTS    4
+
+/*
+ * Ideal ratio of free to in use dquots. Quota manager makes an attempt
+ * to keep this balance.
+ */
+#define XFS_QM_DQFREE_RATIO            2
+
+/*
+ * Dquot hashtable constants/threshold values.
+ */
+#define XFS_QM_NCSIZE_THRESHOLD                5000
+#define XFS_QM_HASHSIZE_LOW            32
+#define XFS_QM_HASHSIZE_HIGH           64
+
+/*
+ * We output a cmn_err when quotachecking a quota file with more than
+ * this many fsbs.
+ */
+#define XFS_QM_BIG_QCHECK_NBLKS                500
+
+/*
+ * This defines the unit of allocation of dquots.
+ * Currently, it is just one file system block, and a 4K blk contains 30
+ * (136 * 30 = 4080) dquots. It's probably not worth trying to make
+ * this more dynamic.
+ * XXXsup However, if this number is changed, we have to make sure that we don't
+ * implicitly assume that we do allocations in chunks of a single filesystem
+ * block in the dquot/xqm code.
+ */
+#define XFS_DQUOT_CLUSTER_SIZE_FSB     (xfs_filblks_t)1
+/*
+ * When doing a quotacheck, we log dquot clusters of this many FSBs at most
+ * in a single transaction. We don't want to ask for too huge a log reservation.
+ */
+#define XFS_QM_MAX_DQCLUSTER_LOGSZ     3
+
+typedef xfs_dqhash_t   xfs_dqlist_t;
+/*
+ * The freelist head. The first two fields match the first two in the
+ * xfs_dquot_t structure (in xfs_dqmarker_t)
+ */
+typedef struct xfs_frlist {
+       struct xfs_dquot *qh_next;
+       struct xfs_dquot *qh_prev;
+       mutex_t          qh_lock;
+       uint             qh_version;
+       uint             qh_nelems;
+} xfs_frlist_t;
+
+/*
+ * Quota Manager (global) structure. Lives only in core.
+ */
+typedef struct xfs_qm {
+       xfs_dqlist_t    *qm_usr_dqhtable;/* udquot hash table */
+       xfs_dqlist_t    *qm_grp_dqhtable;/* gdquot hash table */
+       uint             qm_dqhashmask;  /* # buckets in dq hashtab - 1 */
+       xfs_frlist_t     qm_dqfreelist;  /* freelist of dquots */
+       atomic_t         qm_totaldquots; /* total incore dquots */
+       uint             qm_nrefs;       /* file systems with quota on */
+       int              qm_dqfree_ratio;/* ratio of free to inuse dquots */
+       kmem_zone_t     *qm_dqzone;      /* dquot mem-alloc zone */
+       kmem_zone_t     *qm_dqtrxzone;   /* t_dqinfo of transactions */
+} xfs_qm_t;
+
+/*
+ * Various quota information for individual filesystems.
+ * The mount structure keeps a pointer to this.
+ */
+typedef struct xfs_quotainfo {
+       xfs_inode_t     *qi_uquotaip;    /* user quota inode */
+       xfs_inode_t     *qi_gquotaip;    /* group quota inode */
+       lock_t           qi_pinlock;     /* dquot pinning mutex */
+       xfs_dqlist_t     qi_dqlist;      /* all dquots in filesys */
+       int              qi_dqreclaims;  /* a change here indicates
+                                           a removal in the dqlist */
+       time_t           qi_btimelimit;  /* limit for blks timer */
+       time_t           qi_itimelimit;  /* limit for inodes timer */
+       time_t           qi_rtbtimelimit;/* limit for rt blks timer */
+       xfs_qwarncnt_t   qi_bwarnlimit;  /* limit for num warnings */
+       xfs_qwarncnt_t   qi_iwarnlimit;  /* limit for num warnings */
+       mutex_t          qi_quotaofflock;/* to serialize quotaoff */
+       /* Some useful precalculated constants */
+       xfs_filblks_t    qi_dqchunklen;  /* # BBs in a chunk of dqs */
+       uint             qi_dqperchunk;  /* # ondisk dqs in above chunk */
+} xfs_quotainfo_t;
+
+
+extern xfs_dqtrxops_t  xfs_trans_dquot_ops;
+
+extern void    xfs_trans_mod_dquot(xfs_trans_t *, xfs_dquot_t *, uint, long);
+extern int     xfs_trans_reserve_quota_bydquots(xfs_trans_t *, xfs_mount_t *,
+                       xfs_dquot_t *, xfs_dquot_t *, long, long, uint);
+extern void    xfs_trans_dqjoin(xfs_trans_t *, xfs_dquot_t *);
+extern void    xfs_trans_log_dquot(xfs_trans_t *, xfs_dquot_t *);
+
+/*
+ * We keep the usr and grp dquots separately so that locking will be easier
+ * to do at commit time. All transactions that we know of at this point
+ * affect no more than two dquots of one type. Hence, the TRANS_MAXDQS value.
+ */
+#define XFS_QM_TRANS_MAXDQS            2
+typedef struct xfs_dquot_acct {
+       xfs_dqtrx_t     dqa_usrdquots[XFS_QM_TRANS_MAXDQS];
+       xfs_dqtrx_t     dqa_grpdquots[XFS_QM_TRANS_MAXDQS];
+} xfs_dquot_acct_t;
+
+/*
+ * Users are allowed to have a usage exceeding their softlimit for
+ * a period this long.
+ */
+#define XFS_QM_BTIMELIMIT      DQ_BTIMELIMIT
+#define XFS_QM_RTBTIMELIMIT    DQ_BTIMELIMIT
+#define XFS_QM_ITIMELIMIT      DQ_FTIMELIMIT
+
+#define XFS_QM_BWARNLIMIT      5
+#define XFS_QM_IWARNLIMIT      5
+
+#define XFS_QM_LOCK(xqm)       (mutex_lock(&xqm##_lock, PINOD))
+#define XFS_QM_UNLOCK(xqm)     (mutex_unlock(&xqm##_lock))
+#define XFS_QM_HOLD(xqm)       ((xqm)->qm_nrefs++)
+#define XFS_QM_RELE(xqm)       ((xqm)->qm_nrefs--)
+
+extern int             xfs_qm_init_quotainfo(xfs_mount_t *);
+extern void            xfs_qm_destroy_quotainfo(xfs_mount_t *);
+extern int             xfs_qm_mount_quotas(xfs_mount_t *);
+extern void            xfs_qm_mount_quotainit(xfs_mount_t *, uint);
+extern void            xfs_qm_unmount_quotadestroy(xfs_mount_t *);
+extern int             xfs_qm_unmount_quotas(xfs_mount_t *);
+extern int             xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t);
+extern int             xfs_qm_sync(xfs_mount_t *, short);
+
+/* dquot stuff */
+extern void            xfs_qm_dqunlink(xfs_dquot_t *);
+extern boolean_t       xfs_qm_dqalloc_incore(xfs_dquot_t **);
+extern int             xfs_qm_dqattach(xfs_inode_t *, uint);
+extern void            xfs_qm_dqdetach(xfs_inode_t *);
+extern int             xfs_qm_dqpurge_all(xfs_mount_t *, uint);
+extern void            xfs_qm_dqrele_all_inodes(xfs_mount_t *, uint);
+
+/* vop stuff */
+extern int             xfs_qm_vop_dqalloc(xfs_mount_t *, xfs_inode_t *,
+                                       uid_t, gid_t, uint,
+                                       xfs_dquot_t **, xfs_dquot_t **);
+extern void            xfs_qm_vop_dqattach_and_dqmod_newinode(
+                                       xfs_trans_t *, xfs_inode_t *,
+                                       xfs_dquot_t *, xfs_dquot_t *);
+extern int             xfs_qm_vop_rename_dqattach(xfs_inode_t **);
+extern xfs_dquot_t *   xfs_qm_vop_chown(xfs_trans_t *, xfs_inode_t *,
+                                       xfs_dquot_t **, xfs_dquot_t *);
+extern int             xfs_qm_vop_chown_reserve(xfs_trans_t *, xfs_inode_t *,
+                                       xfs_dquot_t *, xfs_dquot_t *, uint);
+
+/* list stuff */
+extern void            xfs_qm_freelist_init(xfs_frlist_t *);
+extern void            xfs_qm_freelist_destroy(xfs_frlist_t *);
+extern void            xfs_qm_freelist_insert(xfs_frlist_t *, xfs_dquot_t *);
+extern void            xfs_qm_freelist_append(xfs_frlist_t *, xfs_dquot_t *);
+extern void            xfs_qm_freelist_unlink(xfs_dquot_t *);
+extern int             xfs_qm_freelist_lock_nowait(xfs_qm_t *);
+extern int             xfs_qm_mplist_nowait(xfs_mount_t *);
+extern int             xfs_qm_dqhashlock_nowait(xfs_dquot_t *);
+
+/* system call interface */
+extern int             xfs_qm_quotactl(bhv_desc_t *, int, int, xfs_caddr_t);
+
+#ifdef DEBUG
+extern int             xfs_qm_internalqcheck(xfs_mount_t *);
+#else
+#define xfs_qm_internalqcheck(mp)      (0)
+#endif
+
+#endif /* __XFS_QM_H__ */
diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/quota/xfs_qm_bhv.c
new file mode 100644 (file)
index 0000000..665de8b
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.         Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+#include <linux/init.h>
+#include "xfs_qm.h"
+
+#define MNTOPT_QUOTA   "quota"         /* disk quotas (user) */
+#define MNTOPT_NOQUOTA "noquota"       /* no quotas */
+#define MNTOPT_USRQUOTA        "usrquota"      /* user quota enabled */
+#define MNTOPT_GRPQUOTA        "grpquota"      /* group quota enabled */
+#define MNTOPT_UQUOTA  "uquota"        /* user quota (IRIX variant) */
+#define MNTOPT_GQUOTA  "gquota"        /* group quota (IRIX variant) */
+#define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */
+#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
+#define MNTOPT_QUOTANOENF  "qnoenforce"        /* same as uqnoenforce */
+
+STATIC int
+xfs_qm_parseargs(
+       struct bhv_desc         *bhv,
+       char                    *options,
+       struct xfs_mount_args   *args,
+       int                     update)
+{
+       size_t                  length;
+       char                    *local_options = options;
+       char                    *this_char;
+       int                     error;
+       int                     referenced = update;
+
+       while ((this_char = strsep(&local_options, ",")) != NULL) {
+               length = strlen(this_char);
+               if (local_options)
+                       length++;
+
+               if (!strcmp(this_char, MNTOPT_NOQUOTA)) {
+                       args->flags &= ~(XFSMNT_UQUOTAENF|XFSMNT_UQUOTA);
+                       args->flags &= ~(XFSMNT_GQUOTAENF|XFSMNT_GQUOTA);
+                       referenced = update;
+               } else if (!strcmp(this_char, MNTOPT_QUOTA) ||
+                          !strcmp(this_char, MNTOPT_UQUOTA) ||
+                          !strcmp(this_char, MNTOPT_USRQUOTA)) {
+                       args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF;
+                       referenced = 1;
+               } else if (!strcmp(this_char, MNTOPT_QUOTANOENF) ||
+                          !strcmp(this_char, MNTOPT_UQUOTANOENF)) {
+                       args->flags |= XFSMNT_UQUOTA;
+                       args->flags &= ~XFSMNT_UQUOTAENF;
+                       referenced = 1;
+               } else if (!strcmp(this_char, MNTOPT_GQUOTA) ||
+                          !strcmp(this_char, MNTOPT_GRPQUOTA)) {
+                       args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF;
+                       referenced = 1;
+               } else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
+                       args->flags |= XFSMNT_GQUOTA;
+                       args->flags &= ~XFSMNT_GQUOTAENF;
+                       referenced = 1;
+               } else {
+                       if (local_options)
+                               *(local_options-1) = ',';
+                       continue;
+               }
+
+               while (length--)
+                       *this_char++ = ',';
+       }
+
+       PVFS_PARSEARGS(BHV_NEXT(bhv), options, args, update, error);
+       if (!error && !referenced)
+               bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_QM);
+       return error;
+}
+
+STATIC int
+xfs_qm_showargs(
+       struct bhv_desc         *bhv,
+       struct seq_file         *m)
+{
+       struct vfs              *vfsp = bhvtovfs(bhv);
+       struct xfs_mount        *mp = XFS_VFSTOM(vfsp);
+       int                     error;
+
+       if (mp->m_qflags & XFS_UQUOTA_ACCT) {
+               (mp->m_qflags & XFS_UQUOTA_ENFD) ?
+                       seq_puts(m, "," MNTOPT_USRQUOTA) :
+                       seq_puts(m, "," MNTOPT_UQUOTANOENF);
+       }
+
+       if (mp->m_qflags & XFS_GQUOTA_ACCT) {
+               (mp->m_qflags & XFS_GQUOTA_ENFD) ?
+                       seq_puts(m, "," MNTOPT_GRPQUOTA) :
+                       seq_puts(m, "," MNTOPT_GQUOTANOENF);
+       }
+
+       if (!(mp->m_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT)))
+               seq_puts(m, "," MNTOPT_NOQUOTA);
+
+       PVFS_SHOWARGS(BHV_NEXT(bhv), m, error);
+       return error;
+}
+
+STATIC int
+xfs_qm_mount(
+       struct bhv_desc         *bhv,
+       struct xfs_mount_args   *args,
+       struct cred             *cr)
+{
+       struct vfs              *vfsp = bhvtovfs(bhv);
+       struct xfs_mount        *mp = XFS_VFSTOM(vfsp);
+       int                     error;
+
+       if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA))
+               xfs_qm_mount_quotainit(mp, args->flags);
+       PVFS_MOUNT(BHV_NEXT(bhv), args, cr, error);
+       return error;
+}
+
+STATIC int
+xfs_qm_syncall(
+       struct bhv_desc         *bhv,
+       int                     flags,
+       cred_t                  *credp)
+{
+       struct vfs              *vfsp = bhvtovfs(bhv);
+       struct xfs_mount        *mp = XFS_VFSTOM(vfsp);
+       int                     error;
+
+       /*
+        * Get the Quota Manager to flush the dquots.
+        */
+       if (XFS_IS_QUOTA_ON(mp)) {
+               if ((error = xfs_qm_sync(mp, flags))) {
+                       /*
+                        * If we got an IO error, we will be shutting down.
+                        * So, there's nothing more for us to do here.
+                        */
+                       ASSERT(error != EIO || XFS_FORCED_SHUTDOWN(mp));
+                       if (XFS_FORCED_SHUTDOWN(mp)) {
+                               return XFS_ERROR(error);
+                       }
+               }
+       }
+       PVFS_SYNC(BHV_NEXT(bhv), flags, credp, error);
+       return error;
+}
+
+/*
+ * When xfsquotas isn't installed and the superblock had quotas, we need to
+ * clear the quotaflags from superblock.
+ */
+STATIC void
+xfs_mount_reset_sbqflags(
+       xfs_mount_t             *mp)
+{
+       xfs_trans_t             *tp;
+       unsigned long           s;
+
+       mp->m_qflags = 0;
+       /*
+        * It is OK to look at sb_qflags here in mount path,
+        * without SB_LOCK.
+        */
+       if (mp->m_sb.sb_qflags == 0)
+               return;
+       s = XFS_SB_LOCK(mp);
+       mp->m_sb.sb_qflags = 0;
+       XFS_SB_UNLOCK(mp, s);
+
+       /*
+        * if the fs is readonly, let the incore superblock run
+        * with quotas off but don't flush the update out to disk
+        */
+       if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY)
+               return;
+#ifdef QUOTADEBUG
+       xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes");
+#endif
+       tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
+       if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
+                                     XFS_DEFAULT_LOG_COUNT)) {
+               xfs_trans_cancel(tp, 0);
+               return;
+       }
+       xfs_mod_sb(tp, XFS_SB_QFLAGS);
+       xfs_trans_commit(tp, 0, NULL);
+}
+
+STATIC int
+xfs_qm_newmount(
+       xfs_mount_t     *mp,
+       uint            *needquotamount,
+       uint            *quotaflags)
+{
+       uint            quotaondisk;
+       uint            uquotaondisk = 0, gquotaondisk = 0;
+
+       *quotaflags = 0;
+       *needquotamount = B_FALSE;
+
+       quotaondisk = XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
+               mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT);
+
+       if (quotaondisk) {
+               uquotaondisk = mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT;
+               gquotaondisk = mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT;
+       }
+
+       /*
+        * If the device itself is read-only, we can't allow
+        * the user to change the state of quota on the mount -
+        * this would generate a transaction on the ro device,
+        * which would lead to an I/O error and shutdown
+        */
+
+       if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) ||
+           (!uquotaondisk &&  XFS_IS_UQUOTA_ON(mp)) ||
+            (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
+           (!gquotaondisk &&  XFS_IS_GQUOTA_ON(mp)))  &&
+           xfs_dev_is_read_only(mp, "changing quota state")) {
+               cmn_err(CE_WARN,
+                       "XFS: please mount with%s%s%s.",
+                       (!quotaondisk ? "out quota" : ""),
+                       (uquotaondisk ? " usrquota" : ""),
+                       (gquotaondisk ? " grpquota" : ""));
+               return XFS_ERROR(EPERM);
+       }
+
+       if (XFS_IS_QUOTA_ON(mp) || quotaondisk) {
+               /*
+                * Call mount_quotas at this point only if we won't have to do
+                * a quotacheck.
+                */
+               if (quotaondisk && !XFS_QM_NEED_QUOTACHECK(mp)) {
+                       /*
+                        * If the xfs quota code isn't installed,
+                        * we have to reset the quotachk'd bit.
+                        * If an error occured, qm_mount_quotas code
+                        * has already disabled quotas. So, just finish
+                        * mounting, and get on with the boring life
+                        * without disk quotas.
+                        */
+                       if (xfs_qm_mount_quotas(mp))
+                               xfs_mount_reset_sbqflags(mp);
+               } else {
+                       /*
+                        * Clear the quota flags, but remember them. This
+                        * is so that the quota code doesn't get invoked
+                        * before we're ready. This can happen when an
+                        * inode goes inactive and wants to free blocks,
+                        * or via xfs_log_mount_finish.
+                        */
+                       *needquotamount = B_TRUE;
+                       *quotaflags = mp->m_qflags;
+                       mp->m_qflags = 0;
+               }
+       }
+
+       return 0;
+}
+
+STATIC int
+xfs_qm_endmount(
+       xfs_mount_t     *mp,
+       uint            needquotamount,
+       uint            quotaflags)
+{
+       if (needquotamount) {
+               ASSERT(mp->m_qflags == 0);
+               mp->m_qflags = quotaflags;
+               if (xfs_qm_mount_quotas(mp))
+                       xfs_mount_reset_sbqflags(mp);
+       }
+
+#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
+       if (! (XFS_IS_QUOTA_ON(mp)))
+               xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas not turned on");
+       else
+               xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas turned on");
+#endif
+
+#ifdef QUOTADEBUG
+       if (XFS_IS_QUOTA_ON(mp) && xfs_qm_internalqcheck(mp))
+               cmn_err(CE_WARN, "XFS: mount internalqcheck failed");
+#endif
+
+       return 0;
+}
+
+STATIC void
+xfs_qm_dqrele_null(
+       xfs_dquot_t     *dq)
+{
+       /*
+        * Called from XFS, where we always check first for a NULL dquot.
+        */
+       if (!dq)
+               return;
+       xfs_qm_dqrele(dq);
+}
+
+
+struct xfs_qmops xfs_qmcore_xfs = {
+       .xfs_qminit             = xfs_qm_newmount,
+       .xfs_qmdone             = xfs_qm_unmount_quotadestroy,
+       .xfs_qmmount            = xfs_qm_endmount,
+       .xfs_qmunmount          = xfs_qm_unmount_quotas,
+       .xfs_dqrele             = xfs_qm_dqrele_null,
+       .xfs_dqattach           = xfs_qm_dqattach,
+       .xfs_dqdetach           = xfs_qm_dqdetach,
+       .xfs_dqpurgeall         = xfs_qm_dqpurge_all,
+       .xfs_dqvopalloc         = xfs_qm_vop_dqalloc,
+       .xfs_dqvopcreate        = xfs_qm_vop_dqattach_and_dqmod_newinode,
+       .xfs_dqvoprename        = xfs_qm_vop_rename_dqattach,
+       .xfs_dqvopchown         = xfs_qm_vop_chown,
+       .xfs_dqvopchownresv     = xfs_qm_vop_chown_reserve,
+       .xfs_dqtrxops           = &xfs_trans_dquot_ops,
+};
+
+struct bhv_vfsops xfs_qmops = { {
+       BHV_IDENTITY_INIT(VFS_BHV_QM, VFS_POSITION_QM),
+       .vfs_parseargs          = xfs_qm_parseargs,
+       .vfs_showargs           = xfs_qm_showargs,
+       .vfs_mount              = xfs_qm_mount,
+       .vfs_sync               = xfs_qm_syncall,
+       .vfs_quotactl           = xfs_qm_quotactl, },
+};
+
+
+void __init
+xfs_qm_init(void)
+{
+       static char     message[] __initdata =
+               KERN_INFO "SGI XFS Quota Management subsystem\n";
+
+       printk(message);
+       mutex_init(&xfs_Gqm_lock, MUTEX_DEFAULT, "xfs_qmlock");
+       vfs_bhv_set_custom(&xfs_qmops, &xfs_qmcore_xfs);
+       xfs_qm_init_procfs();
+}
+
+void __exit
+xfs_qm_exit(void)
+{
+       vfs_bhv_clr_custom(&xfs_qmops);
+       xfs_qm_cleanup_procfs();
+       if (qm_dqzone)
+               kmem_cache_destroy(qm_dqzone);
+       if (qm_dqtrxzone)
+               kmem_cache_destroy(qm_dqtrxzone);
+}
diff --git a/fs/xfs/quota/xfs_qm_stats.c b/fs/xfs/quota/xfs_qm_stats.c
new file mode 100644 (file)
index 0000000..af0ee82
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.         Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+#include <linux/proc_fs.h>
+#include "xfs_qm.h"
+
+struct xqmstats xqmstats;
+
+STATIC int
+xfs_qm_read_xfsquota(
+       char            *buffer,
+       char            **start,
+       off_t           offset,
+       int             count,
+       int             *eof,
+       void            *data)
+{
+       int             len;
+
+       /* maximum; incore; ratio free to inuse; freelist */
+       len = sprintf(buffer, "%d\t%d\t%d\t%u\n",
+                       ndquot,
+                       xfs_Gqm? atomic_read(&xfs_Gqm->qm_totaldquots) : 0,
+                       xfs_Gqm? xfs_Gqm->qm_dqfree_ratio : 0,
+                       xfs_Gqm? xfs_Gqm->qm_dqfreelist.qh_nelems : 0);
+
+       if (offset >= len) {
+               *start = buffer;
+               *eof = 1;
+               return 0;
+       }
+       *start = buffer + offset;
+       if ((len -= offset) > count)
+               return count;
+       *eof = 1;
+
+       return len;
+}
+
+STATIC int
+xfs_qm_read_stats(
+       char            *buffer,
+       char            **start,
+       off_t           offset,
+       int             count,
+       int             *eof,
+       void            *data)
+{
+       int             len;
+
+       /* quota performance statistics */
+       len = sprintf(buffer, "qm %u %u %u %u %u %u %u %u\n",
+                       xqmstats.xs_qm_dqreclaims,
+                       xqmstats.xs_qm_dqreclaim_misses,
+                       xqmstats.xs_qm_dquot_dups,
+                       xqmstats.xs_qm_dqcachemisses,
+                       xqmstats.xs_qm_dqcachehits,
+                       xqmstats.xs_qm_dqwants,
+                       xqmstats.xs_qm_dqshake_reclaims,
+                       xqmstats.xs_qm_dqinact_reclaims);
+
+       if (offset >= len) {
+               *start = buffer;
+               *eof = 1;
+               return 0;
+       }
+       *start = buffer + offset;
+       if ((len -= offset) > count)
+               return count;
+       *eof = 1;
+
+       return len;
+}
+
+void
+xfs_qm_init_procfs(void)
+{
+       create_proc_read_entry("fs/xfs/xqmstat", 0, 0, xfs_qm_read_stats, NULL);
+       create_proc_read_entry("fs/xfs/xqm", 0, 0, xfs_qm_read_xfsquota, NULL);
+}
+
+void
+xfs_qm_cleanup_procfs(void)
+{
+       remove_proc_entry("fs/xfs/xqm", NULL);
+       remove_proc_entry("fs/xfs/xqmstat", NULL);
+}
diff --git a/fs/xfs/quota/xfs_qm_stats.h b/fs/xfs/quota/xfs_qm_stats.h
new file mode 100644 (file)
index 0000000..8093c5c
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.         Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_QM_STATS_H__
+#define __XFS_QM_STATS_H__
+
+
+#if defined(CONFIG_PROC_FS) && !defined(XFS_STATS_OFF)
+
+/*
+ * XQM global statistics
+ */
+struct xqmstats {
+       __uint32_t              xs_qm_dqreclaims;
+       __uint32_t              xs_qm_dqreclaim_misses;
+       __uint32_t              xs_qm_dquot_dups;
+       __uint32_t              xs_qm_dqcachemisses;
+       __uint32_t              xs_qm_dqcachehits;
+       __uint32_t              xs_qm_dqwants;
+       __uint32_t              xs_qm_dqshake_reclaims;
+       __uint32_t              xs_qm_dqinact_reclaims;
+};
+
+extern struct xqmstats xqmstats;
+
+# define XQM_STATS_INC(count)  ( (count)++ )
+
+extern void xfs_qm_init_procfs(void);
+extern void xfs_qm_cleanup_procfs(void);
+
+#else
+
+# define XQM_STATS_INC(count)  do { } while (0)
+
+static __inline void xfs_qm_init_procfs(void) { };
+static __inline void xfs_qm_cleanup_procfs(void) { };
+
+#endif
+
+#endif /* __XFS_QM_STATS_H__ */
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c
new file mode 100644 (file)
index 0000000..c5d4939
--- /dev/null
@@ -0,0 +1,1410 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.         Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+#include "xfs_qm.h"
+
+#ifdef DEBUG
+# define qdprintk(s, args...)  cmn_err(CE_DEBUG, s, ## args)
+#else
+# define qdprintk(s, args...)  do { } while (0)
+#endif
+
+STATIC int     xfs_qm_scall_trunc_qfiles(xfs_mount_t *, uint);
+STATIC int     xfs_qm_scall_getquota(xfs_mount_t *, xfs_dqid_t, uint,
+                                       fs_disk_quota_t *);
+STATIC int     xfs_qm_scall_getqstat(xfs_mount_t *, fs_quota_stat_t *);
+STATIC int     xfs_qm_scall_setqlim(xfs_mount_t *, xfs_dqid_t, uint,
+                                       fs_disk_quota_t *);
+STATIC int     xfs_qm_scall_quotaon(xfs_mount_t *, uint);
+STATIC int     xfs_qm_scall_quotaoff(xfs_mount_t *, uint, boolean_t);
+STATIC int     xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint);
+STATIC int     xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
+                                       uint);
+STATIC uint    xfs_qm_import_flags(uint);
+STATIC uint    xfs_qm_export_flags(uint);
+STATIC uint    xfs_qm_import_qtype_flags(uint);
+STATIC uint    xfs_qm_export_qtype_flags(uint);
+STATIC void    xfs_qm_export_dquot(xfs_mount_t *, xfs_disk_dquot_t *,
+                                       fs_disk_quota_t *);
+
+
+/*
+ * The main distribution switch of all XFS quotactl system calls.
+ */
+int
+xfs_qm_quotactl(
+       struct bhv_desc *bdp,
+       int             cmd,
+       int             id,
+       xfs_caddr_t     addr)
+{
+       xfs_mount_t     *mp;
+       int             error;
+       struct vfs      *vfsp;
+
+       vfsp = bhvtovfs(bdp);
+        mp = XFS_VFSTOM(vfsp);
+
+       if (addr == NULL && cmd != Q_SYNC)
+               return XFS_ERROR(EINVAL);
+       if (id < 0 && cmd != Q_SYNC)
+               return XFS_ERROR(EINVAL);
+
+       /*
+        * The following commands are valid even when quotaoff.
+        */
+       switch (cmd) {
+               /* 
+                * truncate quota files. quota must be off.
+                */
+             case Q_XQUOTARM:
+               if (XFS_IS_QUOTA_ON(mp) || addr == NULL)
+                       return XFS_ERROR(EINVAL);
+               if (vfsp->vfs_flag & VFS_RDONLY)
+                       return XFS_ERROR(EROFS);
+               return (xfs_qm_scall_trunc_qfiles(mp, 
+                              xfs_qm_import_qtype_flags(*(uint *)addr)));
+               /*
+                * Get quota status information.
+                */
+             case Q_XGETQSTAT:
+               return (xfs_qm_scall_getqstat(mp, (fs_quota_stat_t *)addr));
+
+               /*
+                * QUOTAON for root f/s and quota enforcement on others..
+                * Quota accounting for non-root f/s's must be turned on
+                * at mount time.
+                */
+             case Q_XQUOTAON:
+               if (addr == NULL)
+                       return XFS_ERROR(EINVAL);
+               if (vfsp->vfs_flag & VFS_RDONLY)
+                       return XFS_ERROR(EROFS);
+               return (xfs_qm_scall_quotaon(mp,
+                                         xfs_qm_import_flags(*(uint *)addr)));
+             case Q_XQUOTAOFF:
+               if (vfsp->vfs_flag & VFS_RDONLY)
+                       return XFS_ERROR(EROFS);
+               break;
+               
+             default:
+               break;
+       }
+
+       if (! XFS_IS_QUOTA_ON(mp))
+               return XFS_ERROR(ESRCH);
+
+       switch (cmd) {
+             case Q_XQUOTAOFF:
+               if (vfsp->vfs_flag & VFS_RDONLY)
+                       return XFS_ERROR(EROFS);
+               error = xfs_qm_scall_quotaoff(mp,
+                                           xfs_qm_import_flags(*(uint *)addr),
+                                           B_FALSE);
+               break;
+
+               /* 
+                * Defaults to XFS_GETUQUOTA. 
+                */
+             case Q_XGETQUOTA:
+               error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_USER, 
+                                       (fs_disk_quota_t *)addr);
+               break;
+               /*
+                * Set limits, both hard and soft. Defaults to Q_SETUQLIM.
+                */
+             case Q_XSETQLIM:
+               if (vfsp->vfs_flag & VFS_RDONLY)
+                       return XFS_ERROR(EROFS);
+               error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_USER,
+                                            (fs_disk_quota_t *)addr);
+               break;
+
+              case Q_XSETGQLIM:
+               if (vfsp->vfs_flag & VFS_RDONLY)
+                       return XFS_ERROR(EROFS);
+               error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_GROUP,
+                                            (fs_disk_quota_t *)addr);
+               break;
+
+                       
+             case Q_XGETGQUOTA:
+               error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_GROUP, 
+                                       (fs_disk_quota_t *)addr);
+               break;
+
+               /*
+                * Quotas are entirely undefined after quotaoff in XFS quotas.
+                * For instance, there's no way to set limits when quotaoff.
+                */
+
+             default:
+               error = XFS_ERROR(EINVAL);
+               break;
+       }
+
+       return (error);
+}
+
+/*
+ * Turn off quota accounting and/or enforcement for all udquots and/or
+ * gdquots. Called only at unmount time.
+ *
+ * This assumes that there are no dquots of this file system cached
+ * incore, and modifies the ondisk dquot directly. Therefore, for example,
+ * it is an error to call this twice, without purging the cache.
+ */
+STATIC int
+xfs_qm_scall_quotaoff(
+       xfs_mount_t             *mp,
+       uint                    flags,
+       boolean_t               force)
+{
+       uint                    dqtype;
+       unsigned long   s;
+       int                     error;
+       uint                    inactivate_flags;
+       xfs_qoff_logitem_t      *qoffstart;
+       int                     nculprits;
+
+       if (!force && !capable(CAP_SYS_ADMIN))
+               return XFS_ERROR(EPERM);
+       /*
+        * No file system can have quotas enabled on disk but not in core.
+        * Note that quota utilities (like quotaoff) _expect_
+        * errno == EEXIST here.
+        */
+       if ((mp->m_qflags & flags) == 0)
+               return XFS_ERROR(EEXIST);
+       error = 0;
+
+       flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
+
+       /*
+        * We don't want to deal with two quotaoffs messing up each other,
+        * so we're going to serialize it. quotaoff isn't exactly a performance
+        * critical thing.
+        * If quotaoff, then we must be dealing with the root filesystem.
+        */
+       ASSERT(mp->m_quotainfo);
+       if (mp->m_quotainfo)
+               mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD);
+
+       ASSERT(mp->m_quotainfo);
+
+       /*
+        * If we're just turning off quota enforcement, change mp and go.
+        */
+       if ((flags & XFS_ALL_QUOTA_ACCT) == 0) {
+               mp->m_qflags &= ~(flags);
+
+               s = XFS_SB_LOCK(mp);
+               mp->m_sb.sb_qflags = mp->m_qflags;
+               XFS_SB_UNLOCK(mp, s);
+               mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
+
+               /* XXX what to do if error ? Revert back to old vals incore ? */
+               error = xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS);
+               return (error);
+       }
+
+       dqtype = 0;
+       inactivate_flags = 0;
+       /*
+        * If accounting is off, we must turn enforcement off, clear the
+        * quota 'CHKD' certificate to make it known that we have to
+        * do a quotacheck the next time this quota is turned on.
+        */
+       if (flags & XFS_UQUOTA_ACCT) {
+               dqtype |= XFS_QMOPT_UQUOTA;
+               flags |= (XFS_UQUOTA_CHKD | XFS_UQUOTA_ENFD);
+               inactivate_flags |= XFS_UQUOTA_ACTIVE;
+       }
+       if (flags & XFS_GQUOTA_ACCT) {
+               dqtype |= XFS_QMOPT_GQUOTA;
+               flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD);
+               inactivate_flags |= XFS_GQUOTA_ACTIVE;
+       }
+
+       /*
+        * Nothing to do?  Don't complain. This happens when we're just
+        * turning off quota enforcement.
+        */
+       if ((mp->m_qflags & flags) == 0) {
+               mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
+               return (0);
+       }
+
+       /*
+        * Write the LI_QUOTAOFF log record, and do SB changes atomically,
+        * and synchronously.
+        */
+       xfs_qm_log_quotaoff(mp, &qoffstart, flags);
+
+       /*
+        * Next we clear the XFS_MOUNT_*DQ_ACTIVE bit(s) in the mount struct
+        * to take care of the race between dqget and quotaoff. We don't take
+        * any special locks to reset these bits. All processes need to check
+        * these bits *after* taking inode lock(s) to see if the particular
+        * quota type is in the process of being turned off. If *ACTIVE, it is
+        * guaranteed that all dquot structures and all quotainode ptrs will all
+        * stay valid as long as that inode is kept locked.
+        *
+        * There is no turning back after this.
+        */
+       mp->m_qflags &= ~inactivate_flags;
+
+       /*
+        * Give back all the dquot reference(s) held by inodes.
+        * Here we go thru every single incore inode in this file system, and
+        * do a dqrele on the i_udquot/i_gdquot that it may have.
+        * Essentially, as long as somebody has an inode locked, this guarantees
+        * that quotas will not be turned off. This is handy because in a
+        * transaction once we lock the inode(s) and check for quotaon, we can
+        * depend on the quota inodes (and other things) being valid as long as
+        * we keep the lock(s).
+        */
+       xfs_qm_dqrele_all_inodes(mp, flags);
+
+       /*
+        * Next we make the changes in the quota flag in the mount struct.
+        * This isn't protected by a particular lock directly, because we
+        * don't want to take a mrlock everytime we depend on quotas being on.
+        */
+       mp->m_qflags &= ~(flags);
+
+       /*
+        * Go through all the dquots of this file system and purge them,
+        * according to what was turned off. We may not be able to get rid
+        * of all dquots, because dquots can have temporary references that
+        * are not attached to inodes. eg. xfs_setattr, xfs_create.
+        * So, if we couldn't purge all the dquots from the filesystem,
+        * we can't get rid of the incore data structures.
+        */
+       while ((nculprits = xfs_qm_dqpurge_all(mp, dqtype|XFS_QMOPT_QUOTAOFF)))
+               delay(10 * nculprits);
+
+       /*
+        * Transactions that had started before ACTIVE state bit was cleared
+        * could have logged many dquots, so they'd have higher LSNs than
+        * the first QUOTAOFF log record does. If we happen to crash when
+        * the tail of the log has gone past the QUOTAOFF record, but
+        * before the last dquot modification, those dquots __will__
+        * recover, and that's not good.
+        *
+        * So, we have QUOTAOFF start and end logitems; the start
+        * logitem won't get overwritten until the end logitem appears...
+        */
+       xfs_qm_log_quotaoff_end(mp, qoffstart, flags);
+
+       /*
+        * If quotas is completely disabled, close shop.
+        */
+       if ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_ALL) {
+               mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
+               xfs_qm_destroy_quotainfo(mp);
+               return (0);
+       }
+
+       /*
+        * Release our quotainode references, and vn_purge them,
+        * if we don't need them anymore.
+        */
+       if ((dqtype & XFS_QMOPT_UQUOTA) && XFS_QI_UQIP(mp)) {
+               XFS_PURGE_INODE(XFS_QI_UQIP(mp));
+               XFS_QI_UQIP(mp) = NULL;
+       }
+       if ((dqtype & XFS_QMOPT_GQUOTA) && XFS_QI_GQIP(mp)) {
+               XFS_PURGE_INODE(XFS_QI_GQIP(mp));
+               XFS_QI_GQIP(mp) = NULL;
+       }
+       mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
+
+       return (error);
+}
+
+STATIC int
+xfs_qm_scall_trunc_qfiles(
+       xfs_mount_t     *mp,
+       uint            flags)
+{
+       int             error;
+       xfs_inode_t     *qip;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return XFS_ERROR(EPERM);
+       error = 0;
+       if (!XFS_SB_VERSION_HASQUOTA(&mp->m_sb) || flags == 0) {
+               qdprintk("qtrunc flags=%x m_qflags=%x\n", flags, mp->m_qflags);
+               return XFS_ERROR(EINVAL);
+       }
+
+       if ((flags & XFS_DQ_USER) && mp->m_sb.sb_uquotino != NULLFSINO) {
+               error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &qip, 0);
+               if (! error) {
+                       (void) xfs_truncate_file(mp, qip);
+                       VN_RELE(XFS_ITOV(qip));
+               }
+       }
+
+       if ((flags & XFS_DQ_GROUP) && mp->m_sb.sb_gquotino != NULLFSINO) {
+               error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &qip, 0);
+               if (! error) {
+                       (void) xfs_truncate_file(mp, qip);
+                       VN_RELE(XFS_ITOV(qip));
+               }
+       }
+
+       return (error);
+}
+
+
+/*
+ * Switch on (a given) quota enforcement for a filesystem.  This takes
+ * effect immediately.
+ * (Switching on quota accounting must be done at mount time.)
+ */
+STATIC int
+xfs_qm_scall_quotaon(
+       xfs_mount_t     *mp,
+       uint            flags)
+{
+       int             error;
+       unsigned long s;
+       uint            qf;
+       uint            accflags;
+       __int64_t       sbflags;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return XFS_ERROR(EPERM);
+
+       flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
+       /*
+        * Switching on quota accounting must be done at mount time.
+        */
+       accflags = flags & XFS_ALL_QUOTA_ACCT;
+       flags &= ~(XFS_ALL_QUOTA_ACCT);
+
+       sbflags = 0;
+
+       if (flags == 0) {
+               qdprintk("quotaon: zero flags, m_qflags=%x\n", mp->m_qflags);
+               return XFS_ERROR(EINVAL);
+       }
+
+       /* No fs can turn on quotas with a delayed effect */
+       ASSERT((flags & XFS_ALL_QUOTA_ACCT) == 0);
+
+       /*
+        * Can't enforce without accounting. We check the superblock
+        * qflags here instead of m_qflags because rootfs can have
+        * quota acct on ondisk without m_qflags' knowing.
+        */
+       if (((flags & XFS_UQUOTA_ACCT) == 0 &&
+           (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
+           (flags & XFS_UQUOTA_ENFD))
+           ||
+           ((flags & XFS_GQUOTA_ACCT) == 0 &&
+           (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
+           (flags & XFS_GQUOTA_ENFD))) {
+               qdprintk("Can't enforce without acct, flags=%x sbflags=%x\n",
+                       flags, mp->m_sb.sb_qflags);
+               return XFS_ERROR(EINVAL);
+       }
+       /*
+        * If everything's upto-date incore, then don't waste time.
+        */
+       if ((mp->m_qflags & flags) == flags)
+               return XFS_ERROR(EEXIST);
+
+       /*
+        * Change sb_qflags on disk but not incore mp->qflags
+        * if this is the root filesystem.
+        */
+       s = XFS_SB_LOCK(mp);
+       qf = mp->m_sb.sb_qflags;
+       mp->m_sb.sb_qflags = qf | flags;
+       XFS_SB_UNLOCK(mp, s);
+
+       /*
+        * There's nothing to change if it's the same.
+        */
+       if ((qf & flags) == flags && sbflags == 0)
+               return XFS_ERROR(EEXIST);
+       sbflags |= XFS_SB_QFLAGS;
+
+       if ((error = xfs_qm_write_sb_changes(mp, sbflags)))
+               return (error);
+       /*
+        * If we aren't trying to switch on quota enforcement, we are done.
+        */
+       if  (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) !=
+            (mp->m_qflags & XFS_UQUOTA_ACCT)) ||
+           (flags & XFS_ALL_QUOTA_ENFD) == 0)
+               return (0);
+
+       if (! XFS_IS_QUOTA_RUNNING(mp))
+               return XFS_ERROR(ESRCH);
+
+       /*
+        * Switch on quota enforcement in core.
+        */
+       mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD);
+       mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD);
+       mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
+
+       return (0);
+}
+
+
+
+/*
+ * Return quota status information, such as uquota-off, enforcements, etc.
+ */
+STATIC int
+xfs_qm_scall_getqstat(
+       xfs_mount_t     *mp,
+       fs_quota_stat_t *out)
+{
+       xfs_inode_t     *uip, *gip;
+       boolean_t       tempuqip, tempgqip;
+
+       uip = gip = NULL;
+       tempuqip = tempgqip = B_FALSE;
+       memset(out, 0, sizeof(fs_quota_stat_t));
+
+       out->qs_version = FS_QSTAT_VERSION;
+       if (! XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) {
+               out->qs_uquota.qfs_ino = NULLFSINO;
+               out->qs_gquota.qfs_ino = NULLFSINO;
+               return (0);
+       }
+       out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
+                                                       (XFS_ALL_QUOTA_ACCT|
+                                                        XFS_ALL_QUOTA_ENFD));
+       out->qs_pad = 0;
+       out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
+       out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
+
+       if (mp->m_quotainfo) {
+               uip = mp->m_quotainfo->qi_uquotaip;
+               gip = mp->m_quotainfo->qi_gquotaip;
+       }
+       if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
+               if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &uip, 0) == 0)
+                       tempuqip = B_TRUE;
+       }
+       if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) {
+               if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &gip, 0) == 0)
+                       tempgqip = B_TRUE;
+       }
+       if (uip) {
+               out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
+               out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
+               if (tempuqip)
+                       VN_RELE(XFS_ITOV(uip));
+       }
+       if (gip) {
+               out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
+               out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
+               if (tempgqip)
+                       VN_RELE(XFS_ITOV(gip));
+       }
+       if (mp->m_quotainfo) {
+               out->qs_incoredqs = XFS_QI_MPLNDQUOTS(mp);
+               out->qs_btimelimit = XFS_QI_BTIMELIMIT(mp);
+               out->qs_itimelimit = XFS_QI_ITIMELIMIT(mp);
+               out->qs_rtbtimelimit = XFS_QI_RTBTIMELIMIT(mp);
+               out->qs_bwarnlimit = XFS_QI_BWARNLIMIT(mp);
+               out->qs_iwarnlimit = XFS_QI_IWARNLIMIT(mp);
+       }
+       return (0);
+}
+
+/*
+ * Adjust quota limits, and start/stop timers accordingly.
+ */
+STATIC int
+xfs_qm_scall_setqlim(
+       xfs_mount_t             *mp,
+       xfs_dqid_t              id,
+       uint                    type,
+       fs_disk_quota_t         *newlim)
+{
+       xfs_disk_dquot_t        *ddq;
+       xfs_dquot_t             *dqp;
+       xfs_trans_t             *tp;
+       int                     error;
+       xfs_qcnt_t              hard, soft;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return XFS_ERROR(EPERM);
+
+       if ((newlim->d_fieldmask & (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK)) == 0)
+               return (0);
+
+       tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM);
+       if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_disk_dquot_t) + 128,
+                                     0, 0, XFS_DEFAULT_LOG_COUNT))) {
+               xfs_trans_cancel(tp, 0);
+               return (error);
+       }
+
+       /*
+        * We don't want to race with a quotaoff so take the quotaoff lock.
+        * (We don't hold an inode lock, so there's nothing else to stop
+        * a quotaoff from happening). (XXXThis doesn't currently happen
+        * because we take the vfslock before calling xfs_qm_sysent).
+        */
+       mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD);
+
+       /*
+        * Get the dquot (locked), and join it to the transaction.
+        * Allocate the dquot if this doesn't exist.
+        */
+       if ((error = xfs_qm_dqget(mp, NULL, id, type, XFS_QMOPT_DQALLOC, &dqp))) {
+               xfs_trans_cancel(tp, XFS_TRANS_ABORT);
+               mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
+               ASSERT(error != ENOENT);
+               return (error);
+       }
+       xfs_dqtrace_entry(dqp, "Q_SETQLIM: AFT DQGET");
+       xfs_trans_dqjoin(tp, dqp);
+       ddq = &dqp->q_core;
+
+       /*
+        * Make sure that hardlimits are >= soft limits before changing.
+        */
+       hard = (newlim->d_fieldmask & FS_DQ_BHARD) ?
+               (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_hardlimit) :
+                       INT_GET(ddq->d_blk_hardlimit, ARCH_CONVERT);
+       soft = (newlim->d_fieldmask & FS_DQ_BSOFT) ?
+               (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_softlimit) :
+                       INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT);
+       if (hard == 0 || hard >= soft) {
+               INT_SET(ddq->d_blk_hardlimit, ARCH_CONVERT, hard);
+               INT_SET(ddq->d_blk_softlimit, ARCH_CONVERT, soft);
+       }
+       else {
+               qdprintk("blkhard %Ld < blksoft %Ld\n", hard, soft);
+       }
+       hard = (newlim->d_fieldmask & FS_DQ_RTBHARD) ?
+               (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_hardlimit) :
+                       INT_GET(ddq->d_rtb_hardlimit, ARCH_CONVERT);
+       soft = (newlim->d_fieldmask & FS_DQ_RTBSOFT) ?
+               (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_softlimit) :
+                       INT_GET(ddq->d_rtb_softlimit, ARCH_CONVERT);
+       if (hard == 0 || hard >= soft) {
+               INT_SET(ddq->d_rtb_hardlimit, ARCH_CONVERT, hard);
+               INT_SET(ddq->d_rtb_softlimit, ARCH_CONVERT, soft);
+       }
+       else
+               qdprintk("rtbhard %Ld < rtbsoft %Ld\n", hard, soft);
+
+       hard = (newlim->d_fieldmask & FS_DQ_IHARD) ?
+               (xfs_qcnt_t) newlim->d_ino_hardlimit :
+               INT_GET(ddq->d_ino_hardlimit, ARCH_CONVERT);
+       soft = (newlim->d_fieldmask & FS_DQ_ISOFT) ?
+               (xfs_qcnt_t) newlim->d_ino_softlimit :
+               INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT);
+       if (hard == 0 || hard >= soft) {
+               INT_SET(ddq->d_ino_hardlimit, ARCH_CONVERT, hard);
+               INT_SET(ddq->d_ino_softlimit, ARCH_CONVERT, soft);
+       }
+       else
+               qdprintk("ihard %Ld < isoft %Ld\n", hard, soft);
+
+       if (id == 0) {
+               /*
+                * Timelimits for the super user set the relative time
+                * the other users can be over quota for this file system.
+                * If it is zero a default is used.
+                */
+               if (newlim->d_fieldmask & FS_DQ_BTIMER) {
+                       mp->m_quotainfo->qi_btimelimit = newlim->d_btimer;
+                       INT_SET(dqp->q_core.d_btimer, ARCH_CONVERT, newlim->d_btimer);
+               }
+               if (newlim->d_fieldmask & FS_DQ_ITIMER) {
+                       mp->m_quotainfo->qi_itimelimit = newlim->d_itimer;
+                       INT_SET(dqp->q_core.d_itimer, ARCH_CONVERT, newlim->d_itimer);
+               }
+               if (newlim->d_fieldmask & FS_DQ_RTBTIMER) {
+                       mp->m_quotainfo->qi_rtbtimelimit = newlim->d_rtbtimer;
+                       INT_SET(dqp->q_core.d_rtbtimer, ARCH_CONVERT, newlim->d_rtbtimer);
+               }
+       } else /* if (XFS_IS_QUOTA_ENFORCED(mp)) */ {
+               /*
+                * If the user is now over quota, start the timelimit.
+                * The user will not be 'warned'.
+                * Note that we keep the timers ticking, whether enforcement
+                * is on or off. We don't really want to bother with iterating
+                * over all ondisk dquots and turning the timers on/off.
+                */
+               xfs_qm_adjust_dqtimers(mp, ddq);
+       }
+       dqp->dq_flags |= XFS_DQ_DIRTY;
+       xfs_trans_log_dquot(tp, dqp);
+
+       xfs_dqtrace_entry(dqp, "Q_SETQLIM: COMMIT");
+       xfs_trans_commit(tp, 0, NULL);
+       xfs_qm_dqprint(dqp);
+       xfs_qm_dqrele(dqp);
+       mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
+
+       return (0);
+}
+
+STATIC int
+xfs_qm_scall_getquota(
+       xfs_mount_t     *mp,
+       xfs_dqid_t      id,
+       uint            type,
+       fs_disk_quota_t *out)
+{
+       xfs_dquot_t     *dqp;
+       int             error;
+
+       /*
+        * Try to get the dquot. We don't want it allocated on disk, so
+        * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't
+        * exist, we'll get ENOENT back.
+        */
+       if ((error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp))) {
+               return (error);
+       }
+
+       xfs_dqtrace_entry(dqp, "Q_GETQUOTA SUCCESS");
+       /*
+        * If everything's NULL, this dquot doesn't quite exist as far as
+        * our utility programs are concerned.
+        */
+       if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
+               xfs_qm_dqput(dqp);
+               return XFS_ERROR(ENOENT);
+       }
+       /* xfs_qm_dqprint(dqp); */
+       /*
+        * Convert the disk dquot to the exportable format
+        */
+       xfs_qm_export_dquot(mp, &dqp->q_core, out);
+       xfs_qm_dqput(dqp);
+       return (error ? XFS_ERROR(EFAULT) : 0);
+}
+
+
+STATIC int
+xfs_qm_log_quotaoff_end(
+       xfs_mount_t             *mp,
+       xfs_qoff_logitem_t      *startqoff,
+       uint                    flags)
+{
+       xfs_trans_t            *tp;
+       int                     error;
+       xfs_qoff_logitem_t     *qoffi;
+
+       tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END);
+
+       if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_qoff_logitem_t) * 2,
+                                     0, 0, XFS_DEFAULT_LOG_COUNT))) {
+               xfs_trans_cancel(tp, 0);
+               return (error);
+       }
+
+       qoffi = xfs_trans_get_qoff_item(tp, startqoff,
+                                       flags & XFS_ALL_QUOTA_ACCT);
+       xfs_trans_log_quotaoff_item(tp, qoffi);
+
+       /*
+        * We have to make sure that the transaction is secure on disk before we
+        * return and actually stop quota accounting. So, make it synchronous.
+        * We don't care about quotoff's performance.
+        */
+       xfs_trans_set_sync(tp);
+       error = xfs_trans_commit(tp, 0, NULL);
+       return (error);
+}
+
+
+STATIC int
+xfs_qm_log_quotaoff(
+       xfs_mount_t            *mp,
+       xfs_qoff_logitem_t     **qoffstartp,
+       uint                   flags)
+{
+       xfs_trans_t            *tp;
+       int                     error;
+       unsigned long   s;
+       xfs_qoff_logitem_t     *qoffi=NULL;
+       uint                    oldsbqflag=0;
+
+       tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF);
+       if ((error = xfs_trans_reserve(tp, 0,
+                                     sizeof(xfs_qoff_logitem_t) * 2 +
+                                     mp->m_sb.sb_sectsize + 128,
+                                     0,
+                                     0,
+                                     XFS_DEFAULT_LOG_COUNT))) {
+               goto error0;
+       }
+
+       qoffi = xfs_trans_get_qoff_item(tp, NULL, flags & XFS_ALL_QUOTA_ACCT);
+       xfs_trans_log_quotaoff_item(tp, qoffi);
+
+       s = XFS_SB_LOCK(mp);
+       oldsbqflag = mp->m_sb.sb_qflags;
+       mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL;
+       XFS_SB_UNLOCK(mp, s);
+
+       xfs_mod_sb(tp, XFS_SB_QFLAGS);
+
+       /*
+        * We have to make sure that the transaction is secure on disk before we
+        * return and actually stop quota accounting. So, make it synchronous.
+        * We don't care about quotoff's performance.
+        */
+       xfs_trans_set_sync(tp);
+       error = xfs_trans_commit(tp, 0, NULL);
+
+error0:
+       if (error) {
+               xfs_trans_cancel(tp, 0);
+               /*
+                * No one else is modifying sb_qflags, so this is OK.
+                * We still hold the quotaofflock.
+                */
+               s = XFS_SB_LOCK(mp);
+               mp->m_sb.sb_qflags = oldsbqflag;
+               XFS_SB_UNLOCK(mp, s);
+       }
+       *qoffstartp = qoffi;
+       return (error);
+}
+
+
+/*
+ * Translate an internal style on-disk-dquot to the exportable format.
+ * The main differences are that the counters/limits are all in Basic
+ * Blocks (BBs) instead of the internal FSBs, and all on-disk data has
+ * to be converted to the native endianness.
+ */
+STATIC void
+xfs_qm_export_dquot(
+       xfs_mount_t             *mp,
+       xfs_disk_dquot_t        *src,
+       struct fs_disk_quota    *dst)
+{
+       memset(dst, 0, sizeof(*dst));
+       dst->d_version = FS_DQUOT_VERSION;  /* different from src->d_version */
+       dst->d_flags =
+               xfs_qm_export_qtype_flags(INT_GET(src->d_flags, ARCH_CONVERT));
+       dst->d_id = INT_GET(src->d_id, ARCH_CONVERT);
+       dst->d_blk_hardlimit = (__uint64_t)
+               XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_hardlimit, ARCH_CONVERT));
+       dst->d_blk_softlimit = (__uint64_t)
+               XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_softlimit, ARCH_CONVERT));
+       dst->d_ino_hardlimit = (__uint64_t)
+               INT_GET(src->d_ino_hardlimit, ARCH_CONVERT);
+       dst->d_ino_softlimit = (__uint64_t)
+               INT_GET(src->d_ino_softlimit, ARCH_CONVERT);
+       dst->d_bcount = (__uint64_t)
+               XFS_FSB_TO_BB(mp, INT_GET(src->d_bcount, ARCH_CONVERT));
+       dst->d_icount = (__uint64_t) INT_GET(src->d_icount, ARCH_CONVERT);
+       dst->d_btimer = (__uint32_t) INT_GET(src->d_btimer, ARCH_CONVERT);
+       dst->d_itimer = (__uint32_t) INT_GET(src->d_itimer, ARCH_CONVERT);
+       dst->d_iwarns = INT_GET(src->d_iwarns, ARCH_CONVERT);
+       dst->d_bwarns = INT_GET(src->d_bwarns, ARCH_CONVERT);
+
+       dst->d_rtb_hardlimit = (__uint64_t)
+               XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_hardlimit, ARCH_CONVERT));
+       dst->d_rtb_softlimit = (__uint64_t)
+               XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_softlimit, ARCH_CONVERT));
+       dst->d_rtbcount = (__uint64_t)
+               XFS_FSB_TO_BB(mp, INT_GET(src->d_rtbcount, ARCH_CONVERT));
+       dst->d_rtbtimer = (__uint32_t) INT_GET(src->d_rtbtimer, ARCH_CONVERT);
+       dst->d_rtbwarns = INT_GET(src->d_rtbwarns, ARCH_CONVERT);
+
+       /*
+        * Internally, we don't reset all the timers when quota enforcement
+        * gets turned off. No need to confuse the userlevel code,
+        * so return zeroes in that case.
+        */
+       if (! XFS_IS_QUOTA_ENFORCED(mp)) {
+               dst->d_btimer = 0;
+               dst->d_itimer = 0;
+               dst->d_rtbtimer = 0;
+       }
+
+#ifdef DEBUG
+       if (XFS_IS_QUOTA_ENFORCED(mp) && dst->d_id != 0) {
+               if (((int) dst->d_bcount >= (int) dst->d_blk_softlimit) &&
+                   (dst->d_blk_softlimit > 0)) {
+                       ASSERT(dst->d_btimer != 0);
+               }
+               if (((int) dst->d_icount >= (int) dst->d_ino_softlimit) &&
+                   (dst->d_ino_softlimit > 0)) {
+                       ASSERT(dst->d_itimer != 0);
+               }
+       }
+#endif
+}
+
+STATIC uint
+xfs_qm_import_qtype_flags(
+       uint uflags)
+{
+       /*
+        * Can't be both at the same time.
+        */
+       if (((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) ==
+            (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) ||
+           ((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == 0))
+               return (0);
+
+       return (uflags & XFS_USER_QUOTA) ?
+               XFS_DQ_USER : XFS_DQ_GROUP;
+}
+
+STATIC uint
+xfs_qm_export_qtype_flags(
+       uint flags)
+{
+       /*
+        * Can't be both at the same time.
+        */
+       ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) !=
+               (XFS_GROUP_QUOTA | XFS_USER_QUOTA));
+       ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) != 0);
+
+       return (flags & XFS_DQ_USER) ?
+               XFS_USER_QUOTA : XFS_GROUP_QUOTA;
+}
+
+STATIC uint
+xfs_qm_import_flags(
+       uint uflags)
+{
+       uint flags = 0;
+
+       if (uflags & XFS_QUOTA_UDQ_ACCT)
+               flags |= XFS_UQUOTA_ACCT;
+       if (uflags & XFS_QUOTA_GDQ_ACCT)
+               flags |= XFS_GQUOTA_ACCT;
+       if (uflags & XFS_QUOTA_UDQ_ENFD)
+               flags |= XFS_UQUOTA_ENFD;
+       if (uflags & XFS_QUOTA_GDQ_ENFD)
+               flags |= XFS_GQUOTA_ENFD;
+       return (flags);
+}
+
+
+STATIC uint
+xfs_qm_export_flags(
+       uint flags)
+{
+       uint uflags;
+
+       uflags = 0;
+       if (flags & XFS_UQUOTA_ACCT)
+               uflags |= XFS_QUOTA_UDQ_ACCT;
+       if (flags & XFS_GQUOTA_ACCT)
+               uflags |= XFS_QUOTA_GDQ_ACCT;
+       if (flags & XFS_UQUOTA_ENFD)
+               uflags |= XFS_QUOTA_UDQ_ENFD;
+       if (flags & XFS_GQUOTA_ENFD)
+               uflags |= XFS_QUOTA_GDQ_ENFD;
+       return (uflags);
+}
+
+
+/*
+ * Go thru all the inodes in the file system, releasing their dquots.
+ * Note that the mount structure gets modified to indicate that quotas are off
+ * AFTER this, in the case of quotaoff. This also gets called from
+ * xfs_rootumount.
+ */
+void
+xfs_qm_dqrele_all_inodes(
+       struct xfs_mount *mp,
+       uint             flags)
+{
+       vmap_t          vmap;
+       xfs_inode_t     *ip, *topino;
+       uint            ireclaims;
+       vnode_t         *vp;
+       boolean_t       vnode_refd;
+
+       ASSERT(mp->m_quotainfo);
+
+again:
+       XFS_MOUNT_ILOCK(mp);
+       ip = mp->m_inodes;
+       if (ip == NULL) {
+               XFS_MOUNT_IUNLOCK(mp);
+               return;
+       }
+       do {
+               /* Skip markers inserted by xfs_sync */
+               if (ip->i_mount == NULL) {
+                       ip = ip->i_mnext;
+                       continue;
+               }
+               /* Root inode, rbmip and rsumip have associated blocks */
+               if (ip == XFS_QI_UQIP(mp) || ip == XFS_QI_GQIP(mp)) {
+                       ASSERT(ip->i_udquot == NULL);
+                       ASSERT(ip->i_gdquot == NULL);
+                       ip = ip->i_mnext;
+                       continue;
+               }
+               vp = XFS_ITOV_NULL(ip);
+               if (!vp) {
+                       ASSERT(ip->i_udquot == NULL);
+                       ASSERT(ip->i_gdquot == NULL);
+                       ip = ip->i_mnext;
+                       continue;
+               }
+               vnode_refd = B_FALSE;
+               if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) {
+                       /*
+                        * Sample vp mapping while holding the mplock, lest
+                        * we come across a non-existent vnode.
+                        */
+                       VMAP(vp, vmap);
+                       ireclaims = mp->m_ireclaims;
+                       topino = mp->m_inodes;
+                       XFS_MOUNT_IUNLOCK(mp);
+
+                       /* XXX restart limit ? */
+                       if ( ! (vp = vn_get(vp, &vmap)))
+                               goto again;
+                       xfs_ilock(ip, XFS_ILOCK_EXCL);
+                       vnode_refd = B_TRUE;
+               } else {
+                       ireclaims = mp->m_ireclaims;
+                       topino = mp->m_inodes;
+                       XFS_MOUNT_IUNLOCK(mp);
+               }
+
+               /*
+                * We don't keep the mountlock across the dqrele() call,
+                * since it can take a while..
+                */
+               if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) {
+                       xfs_qm_dqrele(ip->i_udquot);
+                       ip->i_udquot = NULL;
+               }
+               if ((flags & XFS_GQUOTA_ACCT) && ip->i_gdquot) {
+                       xfs_qm_dqrele(ip->i_gdquot);
+                       ip->i_gdquot = NULL;
+               }
+               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+               /*
+                * Wait until we've dropped the ilock and mountlock to
+                * do the vn_rele. Or be condemned to an eternity in the
+                * inactive code in hell.
+                */
+               if (vnode_refd)
+                       VN_RELE(vp);
+               XFS_MOUNT_ILOCK(mp);
+               /*
+                * If an inode was inserted or removed, we gotta
+                * start over again.
+                */
+               if (topino != mp->m_inodes || mp->m_ireclaims != ireclaims) {
+                       /* XXX use a sentinel */
+                       XFS_MOUNT_IUNLOCK(mp);
+                       goto again;
+               }
+               ip = ip->i_mnext;
+       } while (ip != mp->m_inodes);
+
+       XFS_MOUNT_IUNLOCK(mp);
+}
+
+/*------------------------------------------------------------------------*/
+#ifdef DEBUG
+/*
+ * This contains all the test functions for XFS disk quotas.
+ * Currently it does a quota accounting check. ie. it walks through
+ * all inodes in the file system, calculating the dquot accounting fields,
+ * and prints out any inconsistencies.
+ */
+xfs_dqhash_t *qmtest_udqtab;
+xfs_dqhash_t *qmtest_gdqtab;
+int          qmtest_hashmask;
+int          qmtest_nfails;
+mutex_t              qcheck_lock;
+
+#define DQTEST_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \
+                                (__psunsigned_t)(id)) & \
+                               (qmtest_hashmask - 1))
+
+#define DQTEST_HASH(mp, id, type)   ((type & XFS_DQ_USER) ? \
+                                    (qmtest_udqtab + \
+                                     DQTEST_HASHVAL(mp, id)) : \
+                                    (qmtest_gdqtab + \
+                                     DQTEST_HASHVAL(mp, id)))
+
+#define DQTEST_LIST_PRINT(l, NXT, title) \
+{ \
+         xfs_dqtest_t  *dqp; int i = 0;\
+         cmn_err(CE_DEBUG, "%s (#%d)", title, (int) (l)->qh_nelems); \
+         for (dqp = (xfs_dqtest_t *)(l)->qh_next; dqp != NULL; \
+              dqp = (xfs_dqtest_t *)dqp->NXT) { \
+               cmn_err(CE_DEBUG, "  %d\. \"%d (%s)\"  bcnt = %d, icnt = %d", \
+                        ++i, dqp->d_id, DQFLAGTO_TYPESTR(dqp),      \
+                        dqp->d_bcount, dqp->d_icount); } \
+}
+
+typedef struct dqtest {
+       xfs_dqmarker_t  q_lists;
+       xfs_dqhash_t    *q_hash;        /* the hashchain header */
+       xfs_mount_t     *q_mount;       /* filesystem this relates to */
+       xfs_dqid_t      d_id;           /* user id or group id */
+       xfs_qcnt_t      d_bcount;       /* # disk blocks owned by the user */
+       xfs_qcnt_t      d_icount;       /* # inodes owned by the user */
+} xfs_dqtest_t;
+
+STATIC void
+xfs_qm_hashinsert(xfs_dqhash_t *h, xfs_dqtest_t *dqp)
+{
+       xfs_dquot_t *d;
+       if (((d) = (h)->qh_next))
+               (d)->HL_PREVP = &((dqp)->HL_NEXT);
+       (dqp)->HL_NEXT = d;
+       (dqp)->HL_PREVP = &((h)->qh_next);
+       (h)->qh_next = (xfs_dquot_t *)dqp;
+       (h)->qh_version++;
+       (h)->qh_nelems++;
+}
+STATIC void
+xfs_qm_dqtest_print(
+       xfs_dqtest_t    *d)
+{
+       cmn_err(CE_DEBUG, "-----------DQTEST DQUOT----------------");
+       cmn_err(CE_DEBUG, "---- dquot ID = %d", d->d_id);
+       cmn_err(CE_DEBUG, "---- type     = %s", XFS_QM_ISUDQ(d)? "USR" : "GRP");
+       cmn_err(CE_DEBUG, "---- fs       = 0x%p", d->q_mount);
+       cmn_err(CE_DEBUG, "---- bcount   = %Lu (0x%x)",
+               d->d_bcount, (int)d->d_bcount);
+       cmn_err(CE_DEBUG, "---- icount   = %Lu (0x%x)",
+               d->d_icount, (int)d->d_icount);
+       cmn_err(CE_DEBUG, "---------------------------");
+}
+
+STATIC void
+xfs_qm_dqtest_failed(
+       xfs_dqtest_t    *d,
+       xfs_dquot_t     *dqp,
+       char            *reason,
+       xfs_qcnt_t      a,
+       xfs_qcnt_t      b,
+       int             error)
+{
+       qmtest_nfails++;
+       if (error)
+               cmn_err(CE_DEBUG, "quotacheck failed id=%d, err=%d\nreason: %s",
+                      INT_GET(d->d_id, ARCH_CONVERT), error, reason);
+       else
+               cmn_err(CE_DEBUG, "quotacheck failed id=%d (%s) [%d != %d]",
+                      INT_GET(d->d_id, ARCH_CONVERT), reason, (int)a, (int)b);
+       xfs_qm_dqtest_print(d);
+       if (dqp)
+               xfs_qm_dqprint(dqp);
+}
+
+STATIC int
+xfs_dqtest_cmp2(
+       xfs_dqtest_t    *d,
+       xfs_dquot_t     *dqp)
+{
+       int err = 0;
+       if (INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) != d->d_icount) {
+               xfs_qm_dqtest_failed(d, dqp, "icount mismatch",
+                       INT_GET(dqp->q_core.d_icount, ARCH_CONVERT),
+                       d->d_icount, 0);
+               err++;
+       }
+       if (INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) != d->d_bcount) {
+               xfs_qm_dqtest_failed(d, dqp, "bcount mismatch",
+                       INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT),
+                       d->d_bcount, 0);
+               err++;
+       }
+       if (INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT) &&
+           INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) >=
+           INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT)) {
+               if (INT_ISZERO(dqp->q_core.d_btimer, ARCH_CONVERT) &&
+                   !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT)) {
+                       cmn_err(CE_DEBUG,
+                               "%d [%s] [0x%p] BLK TIMER NOT STARTED",
+                               d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
+                       err++;
+               }
+       }
+       if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) &&
+           INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >=
+           INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) {
+               if (INT_ISZERO(dqp->q_core.d_itimer, ARCH_CONVERT) &&
+                   !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT)) {
+                       cmn_err(CE_DEBUG,
+                               "%d [%s] [0x%p] INO TIMER NOT STARTED",
+                               d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
+                       err++;
+               }
+       }
+#ifdef QUOTADEBUG
+       if (!err) {
+               cmn_err(CE_DEBUG, "%d [%s] [0x%p] qchecked",
+                       d->d_id, XFS_QM_ISUDQ(d) ? "USR" : "GRP", d->q_mount);
+       }
+#endif
+       return (err);
+}
+
+STATIC void
+xfs_dqtest_cmp(
+       xfs_dqtest_t    *d)
+{
+       xfs_dquot_t     *dqp;
+       int             error;
+
+       /* xfs_qm_dqtest_print(d); */
+       if ((error = xfs_qm_dqget(d->q_mount, NULL, d->d_id, d->dq_flags, 0,
+                                &dqp))) {
+               xfs_qm_dqtest_failed(d, NULL, "dqget failed", 0, 0, error);
+               return;
+       }
+       xfs_dqtest_cmp2(d, dqp);
+       xfs_qm_dqput(dqp);
+}
+
+STATIC int
+xfs_qm_internalqcheck_dqget(
+       xfs_mount_t     *mp,
+       xfs_dqid_t      id,
+       uint            type,
+       xfs_dqtest_t    **O_dq)
+{
+       xfs_dqtest_t    *d;
+       xfs_dqhash_t    *h;
+
+       h = DQTEST_HASH(mp, id, type);
+       for (d = (xfs_dqtest_t *) h->qh_next; d != NULL;
+            d = (xfs_dqtest_t *) d->HL_NEXT) {
+               /* DQTEST_LIST_PRINT(h, HL_NEXT, "@@@@@ dqtestlist @@@@@"); */
+               if (d->d_id == id && mp == d->q_mount) {
+                       *O_dq = d;
+                       return (0);
+               }
+       }
+       d = kmem_zalloc(sizeof(xfs_dqtest_t), KM_SLEEP);
+       d->dq_flags = type;
+       d->d_id = id;
+       d->q_mount = mp;
+       d->q_hash = h;
+       xfs_qm_hashinsert(h, d);
+       *O_dq = d;
+       return (0);
+}
+
+STATIC void
+xfs_qm_internalqcheck_get_dquots(
+       xfs_mount_t     *mp,
+       xfs_dqid_t      uid,
+       xfs_dqid_t      gid,
+       xfs_dqtest_t    **ud,
+       xfs_dqtest_t    **gd)
+{
+       if (XFS_IS_UQUOTA_ON(mp))
+               xfs_qm_internalqcheck_dqget(mp, uid, XFS_DQ_USER, ud);
+       if (XFS_IS_GQUOTA_ON(mp))
+               xfs_qm_internalqcheck_dqget(mp, gid, XFS_DQ_GROUP, gd);
+}
+
+
+STATIC void
+xfs_qm_internalqcheck_dqadjust(
+       xfs_inode_t             *ip,
+       xfs_dqtest_t            *d)
+{
+       d->d_icount++;
+       d->d_bcount += (xfs_qcnt_t)ip->i_d.di_nblocks;
+}
+
+STATIC int
+xfs_qm_internalqcheck_adjust(
+       xfs_mount_t     *mp,            /* mount point for filesystem */
+       xfs_trans_t     *tp,            /* transaction pointer */
+       xfs_ino_t       ino,            /* inode number to get data for */
+       void            *buffer,        /* not used */
+       xfs_daddr_t     bno,            /* starting block of inode cluster */
+       void            *dip,           /* not used */
+       int             *res)           /* bulkstat result code */
+{
+       xfs_inode_t             *ip;
+       xfs_dqtest_t            *ud, *gd;
+       uint                    lock_flags;
+       boolean_t               ipreleased;
+       int                     error;
+
+       ASSERT(XFS_IS_QUOTA_RUNNING(mp));
+
+       if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
+               *res = BULKSTAT_RV_NOTHING;
+               qdprintk("internalqcheck: ino=%llu, uqino=%llu, gqino=%llu\n",
+                       (unsigned long long) ino,
+                       (unsigned long long) mp->m_sb.sb_uquotino,
+                       (unsigned long long) mp->m_sb.sb_gquotino);
+               return XFS_ERROR(EINVAL);
+       }
+       ipreleased = B_FALSE;
+ again:
+       lock_flags = XFS_ILOCK_SHARED;
+       if ((error = xfs_iget(mp, tp, ino, lock_flags, &ip, bno))) {
+               *res = BULKSTAT_RV_NOTHING;
+               return (error);
+       }
+
+       if (ip->i_d.di_mode == 0) {
+               xfs_iput_new(ip, lock_flags);
+               *res = BULKSTAT_RV_NOTHING;
+               return XFS_ERROR(ENOENT);
+       }
+
+       /*
+        * This inode can have blocks after eof which can get released
+        * when we send it to inactive. Since we don't check the dquot
+        * until the after all our calculations are done, we must get rid
+        * of those now.
+        */
+       if (! ipreleased) {
+               xfs_iput(ip, lock_flags);
+               ipreleased = B_TRUE;
+               goto again;
+       }
+       xfs_qm_internalqcheck_get_dquots(mp,
+                                       (xfs_dqid_t) ip->i_d.di_uid,
+                                       (xfs_dqid_t) ip->i_d.di_gid,
+                                       &ud, &gd);
+       if (XFS_IS_UQUOTA_ON(mp)) {
+               ASSERT(ud);
+               xfs_qm_internalqcheck_dqadjust(ip, ud);
+       }
+       if (XFS_IS_GQUOTA_ON(mp)) {
+               ASSERT(gd);
+               xfs_qm_internalqcheck_dqadjust(ip, gd);
+       }
+       xfs_iput(ip, lock_flags);
+       *res = BULKSTAT_RV_DIDONE;
+       return (0);
+}
+
+
+/* PRIVATE, debugging */
+int
+xfs_qm_internalqcheck(
+       xfs_mount_t     *mp)
+{
+       xfs_ino_t       lastino;
+       int             done, count;
+       int             i;
+       xfs_dqtest_t    *d, *e;
+       xfs_dqhash_t    *h1;
+       int             error;
+
+       lastino = 0;
+       qmtest_hashmask = 32;
+       count = 5;
+       done = 0;
+       qmtest_nfails = 0;
+
+       if (! XFS_IS_QUOTA_ON(mp))
+               return XFS_ERROR(ESRCH);
+
+       xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
+       XFS_bflush(mp->m_ddev_targp);
+       xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
+       XFS_bflush(mp->m_ddev_targp);
+
+       mutex_lock(&qcheck_lock, PINOD);
+       /* There should be absolutely no quota activity while this
+          is going on. */
+       qmtest_udqtab = kmem_zalloc(qmtest_hashmask *
+                                   sizeof(xfs_dqhash_t), KM_SLEEP);
+       qmtest_gdqtab = kmem_zalloc(qmtest_hashmask *
+                                   sizeof(xfs_dqhash_t), KM_SLEEP);
+       do {
+               /*
+                * Iterate thru all the inodes in the file system,
+                * adjusting the corresponding dquot counters
+                */
+               if ((error = xfs_bulkstat(mp, NULL, &lastino, &count,
+                                xfs_qm_internalqcheck_adjust,
+                                0, NULL, BULKSTAT_FG_IGET, &done))) {
+                       break;
+               }
+       } while (! done);
+       if (error) {
+               cmn_err(CE_DEBUG, "Bulkstat returned error 0x%x", error);
+       }
+       cmn_err(CE_DEBUG, "Checking results against system dquots");
+       for (i = 0; i < qmtest_hashmask; i++) {
+               h1 = &qmtest_udqtab[i];
+               for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) {
+                       xfs_dqtest_cmp(d);
+                       e = (xfs_dqtest_t *) d->HL_NEXT;
+                       kmem_free(d, sizeof(xfs_dqtest_t));
+                       d = e;
+               }
+               h1 = &qmtest_gdqtab[i];
+               for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) {
+                       xfs_dqtest_cmp(d);
+                       e = (xfs_dqtest_t *) d->HL_NEXT;
+                       kmem_free(d, sizeof(xfs_dqtest_t));
+                       d = e;
+               }
+       }
+
+       if (qmtest_nfails) {
+               cmn_err(CE_DEBUG, "******** quotacheck failed  ********");
+               cmn_err(CE_DEBUG, "failures = %d", qmtest_nfails);
+       } else {
+               cmn_err(CE_DEBUG, "******** quotacheck successful! ********");
+       }
+       kmem_free(qmtest_udqtab, qmtest_hashmask * sizeof(xfs_dqhash_t));
+       kmem_free(qmtest_gdqtab, qmtest_hashmask * sizeof(xfs_dqhash_t));
+       mutex_unlock(&qcheck_lock);
+       return (qmtest_nfails);
+}
+
+#endif /* DEBUG */
diff --git a/fs/xfs/quota/xfs_quota_priv.h b/fs/xfs/quota/xfs_quota_priv.h
new file mode 100644 (file)
index 0000000..eeda93a
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.         Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_QUOTA_PRIV_H__
+#define __XFS_QUOTA_PRIV_H__
+
+/*
+ * Number of bmaps that we ask from bmapi when doing a quotacheck.
+ * We make this restriction to keep the memory usage to a minimum.
+ */
+#define XFS_DQITER_MAP_SIZE    10
+
+/* Number of dquots that fit in to a dquot block */
+#define XFS_QM_DQPERBLK(mp)    ((mp)->m_quotainfo->qi_dqperchunk)
+
+#define XFS_ISLOCKED_INODE(ip)         (ismrlocked(&(ip)->i_lock, \
+                                           MR_UPDATE | MR_ACCESS) != 0)
+#define XFS_ISLOCKED_INODE_EXCL(ip)    (ismrlocked(&(ip)->i_lock, \
+                                           MR_UPDATE) != 0)
+
+#define XFS_DQ_IS_ADDEDTO_TRX(t, d)    ((d)->q_transp == (t))
+
+#define XFS_QI_MPLRECLAIMS(mp) ((mp)->m_quotainfo->qi_dqreclaims)
+#define XFS_QI_UQIP(mp)                ((mp)->m_quotainfo->qi_uquotaip)
+#define XFS_QI_GQIP(mp)                ((mp)->m_quotainfo->qi_gquotaip)
+#define XFS_QI_DQCHUNKLEN(mp)  ((mp)->m_quotainfo->qi_dqchunklen)
+#define XFS_QI_BTIMELIMIT(mp)  ((mp)->m_quotainfo->qi_btimelimit)
+#define XFS_QI_RTBTIMELIMIT(mp) ((mp)->m_quotainfo->qi_rtbtimelimit)
+#define XFS_QI_ITIMELIMIT(mp)  ((mp)->m_quotainfo->qi_itimelimit)
+#define XFS_QI_BWARNLIMIT(mp)  ((mp)->m_quotainfo->qi_bwarnlimit)
+#define XFS_QI_IWARNLIMIT(mp)  ((mp)->m_quotainfo->qi_iwarnlimit)
+#define XFS_QI_QOFFLOCK(mp)    ((mp)->m_quotainfo->qi_quotaofflock)
+
+#define XFS_QI_MPL_LIST(mp)    ((mp)->m_quotainfo->qi_dqlist)
+#define XFS_QI_MPLLOCK(mp)     ((mp)->m_quotainfo->qi_dqlist.qh_lock)
+#define XFS_QI_MPLNEXT(mp)     ((mp)->m_quotainfo->qi_dqlist.qh_next)
+#define XFS_QI_MPLNDQUOTS(mp)  ((mp)->m_quotainfo->qi_dqlist.qh_nelems)
+
+#define XQMLCK(h)                      (mutex_lock(&((h)->qh_lock), PINOD))
+#define XQMUNLCK(h)                    (mutex_unlock(&((h)->qh_lock)))
+#ifdef DEBUG
+struct xfs_dqhash;
+static inline int XQMISLCKD(struct xfs_dqhash *h)
+{
+       if (mutex_trylock(&h->qh_lock)) {
+               mutex_unlock(&h->qh_lock);
+               return 0;
+       }
+       return 1;
+}
+#endif
+
+#define XFS_DQ_HASH_LOCK(h)            XQMLCK(h)
+#define XFS_DQ_HASH_UNLOCK(h)          XQMUNLCK(h)
+#define XFS_DQ_IS_HASH_LOCKED(h)       XQMISLCKD(h)
+
+#define xfs_qm_mplist_lock(mp)         XQMLCK(&(XFS_QI_MPL_LIST(mp)))
+#define xfs_qm_mplist_unlock(mp)       XQMUNLCK(&(XFS_QI_MPL_LIST(mp)))
+#define XFS_QM_IS_MPLIST_LOCKED(mp)    XQMISLCKD(&(XFS_QI_MPL_LIST(mp)))
+
+#define xfs_qm_freelist_lock(qm)       XQMLCK(&((qm)->qm_dqfreelist))
+#define xfs_qm_freelist_unlock(qm)     XQMUNLCK(&((qm)->qm_dqfreelist))
+#define XFS_QM_IS_FREELIST_LOCKED(qm)  XQMISLCKD(&((qm)->qm_dqfreelist))
+
+/*
+ * Hash into a bucket in the dquot hash table, based on <mp, id>.
+ */
+#define XFS_DQ_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \
+                                (__psunsigned_t)(id)) & \
+                               (xfs_Gqm->qm_dqhashmask - 1))
+#define XFS_DQ_HASH(mp, id, type)   (type == XFS_DQ_USER ? \
+                                    (xfs_Gqm->qm_usr_dqhtable + \
+                                     XFS_DQ_HASHVAL(mp, id)) : \
+                                    (xfs_Gqm->qm_grp_dqhtable + \
+                                     XFS_DQ_HASHVAL(mp, id)))
+#define XFS_IS_DQTYPE_ON(mp, type)   (type == XFS_DQ_USER ? \
+                                     XFS_IS_UQUOTA_ON(mp):XFS_IS_GQUOTA_ON(mp))
+#define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \
+       INT_ISZERO(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT) && \
+       INT_ISZERO(dqp->q_core.d_blk_softlimit, ARCH_CONVERT) && \
+       INT_ISZERO(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT) && \
+       INT_ISZERO(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT) && \
+       INT_ISZERO(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) && \
+       INT_ISZERO(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) && \
+       INT_ISZERO(dqp->q_core.d_bcount, ARCH_CONVERT)        && \
+       INT_ISZERO(dqp->q_core.d_rtbcount, ARCH_CONVERT)      && \
+       INT_ISZERO(dqp->q_core.d_icount, ARCH_CONVERT))
+
+#define HL_PREVP       dq_hashlist.ql_prevp
+#define HL_NEXT                dq_hashlist.ql_next
+#define MPL_PREVP      dq_mplist.ql_prevp
+#define MPL_NEXT       dq_mplist.ql_next
+
+
+#define _LIST_REMOVE(h, dqp, PVP, NXT)                         \
+       {                                                       \
+                xfs_dquot_t *d;                                \
+                if (((d) = (dqp)->NXT))                                \
+                        (d)->PVP = (dqp)->PVP;                 \
+                *((dqp)->PVP) = d;                             \
+                (dqp)->NXT = NULL;                             \
+                (dqp)->PVP = NULL;                             \
+                (h)->qh_version++;                             \
+                (h)->qh_nelems--;                              \
+       }
+
+#define _LIST_INSERT(h, dqp, PVP, NXT)                         \
+       {                                                       \
+                xfs_dquot_t *d;                                \
+                if (((d) = (h)->qh_next))                      \
+                        (d)->PVP = &((dqp)->NXT);              \
+                (dqp)->NXT = d;                                \
+                (dqp)->PVP = &((h)->qh_next);                  \
+                (h)->qh_next = dqp;                            \
+                (h)->qh_version++;                             \
+                (h)->qh_nelems++;                              \
+        }
+
+#define FOREACH_DQUOT_IN_MP(dqp, mp) \
+       for ((dqp) = XFS_QI_MPLNEXT(mp); (dqp) != NULL; (dqp) = (dqp)->MPL_NEXT)
+
+#define FOREACH_DQUOT_IN_FREELIST(dqp, qlist)  \
+for ((dqp) = (qlist)->qh_next; (dqp) != (xfs_dquot_t *)(qlist); \
+     (dqp) = (dqp)->dq_flnext)
+
+#define XQM_HASHLIST_INSERT(h, dqp)    \
+        _LIST_INSERT(h, dqp, HL_PREVP, HL_NEXT)
+
+#define XQM_FREELIST_INSERT(h, dqp)    \
+        xfs_qm_freelist_append(h, dqp)
+
+#define XQM_MPLIST_INSERT(h, dqp)      \
+        _LIST_INSERT(h, dqp, MPL_PREVP, MPL_NEXT)
+
+#define XQM_HASHLIST_REMOVE(h, dqp)    \
+        _LIST_REMOVE(h, dqp, HL_PREVP, HL_NEXT)
+#define XQM_FREELIST_REMOVE(dqp)       \
+        xfs_qm_freelist_unlink(dqp)
+#define XQM_MPLIST_REMOVE(h, dqp)      \
+       { _LIST_REMOVE(h, dqp, MPL_PREVP, MPL_NEXT); \
+         XFS_QI_MPLRECLAIMS((dqp)->q_mount)++; }
+
+#define XFS_DQ_IS_LOGITEM_INITD(dqp)   ((dqp)->q_logitem.qli_dquot == (dqp))
+
+#define XFS_QM_DQP_TO_DQACCT(tp, dqp)  (XFS_QM_ISUDQ(dqp) ? \
+                                        (tp)->t_dqinfo->dqa_usrdquots : \
+                                        (tp)->t_dqinfo->dqa_grpdquots)
+#define XFS_IS_SUSER_DQUOT(dqp)                \
+       (INT_ISZERO((dqp)->q_core.d_id, ARCH_CONVERT))
+
+#define XFS_PURGE_INODE(ip)            \
+       {                               \
+         vmap_t dqvmap;                \
+         vnode_t *dqvp;                \
+         dqvp = XFS_ITOV(ip);          \
+         VMAP(dqvp, dqvmap);           \
+         VN_RELE(dqvp);                \
+       }
+
+#define DQFLAGTO_TYPESTR(d)    (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \
+                                (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : "???"))
+#define DQFLAGTO_DIRTYSTR(d)   (XFS_DQ_IS_DIRTY(d) ? "DIRTY" : "NOTDIRTY")
+
+#endif /* __XFS_QUOTA_PRIV_H__ */
diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c
new file mode 100644 (file)
index 0000000..bf91133
--- /dev/null
@@ -0,0 +1,894 @@
+/*
+ * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.         Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+#include "xfs_qm.h"
+
+STATIC void    xfs_trans_alloc_dqinfo(xfs_trans_t *);
+
+/*
+ * Add the locked dquot to the transaction.
+ * The dquot must be locked, and it cannot be associated with any
+ * transaction.
+ */
+void
+xfs_trans_dqjoin(
+       xfs_trans_t     *tp,
+       xfs_dquot_t     *dqp)
+{
+       xfs_dq_logitem_t    *lp;
+
+       ASSERT(! XFS_DQ_IS_ADDEDTO_TRX(tp, dqp));
+       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+       ASSERT(XFS_DQ_IS_LOGITEM_INITD(dqp));
+       lp = &dqp->q_logitem;
+
+       /*
+        * Get a log_item_desc to point at the new item.
+        */
+       (void) xfs_trans_add_item(tp, (xfs_log_item_t*)(lp));
+
+       /*
+        * Initialize i_transp so we can later determine if this dquot is
+        * associated with this transaction.
+        */
+       dqp->q_transp = tp;
+}
+
+
+/*
+ * This is called to mark the dquot as needing
+ * to be logged when the transaction is committed.  The dquot must
+ * already be associated with the given transaction.
+ * Note that it marks the entire transaction as dirty. In the ordinary
+ * case, this gets called via xfs_trans_commit, after the transaction
+ * is already dirty. However, there's nothing stop this from getting
+ * called directly, as done by xfs_qm_scall_setqlim. Hence, the TRANS_DIRTY
+ * flag.
+ */
+void
+xfs_trans_log_dquot(
+       xfs_trans_t     *tp,
+       xfs_dquot_t     *dqp)
+{
+       xfs_log_item_desc_t     *lidp;
+
+       ASSERT(XFS_DQ_IS_ADDEDTO_TRX(tp, dqp));
+       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+
+       lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(&dqp->q_logitem));
+       ASSERT(lidp != NULL);
+
+       tp->t_flags |= XFS_TRANS_DIRTY;
+       lidp->lid_flags |= XFS_LID_DIRTY;
+}
+
+/*
+ * Carry forward whatever is left of the quota blk reservation to
+ * the spanky new transaction
+ */
+STATIC void
+xfs_trans_dup_dqinfo(
+       xfs_trans_t     *otp,
+       xfs_trans_t     *ntp)
+{
+       xfs_dqtrx_t     *oq, *nq;
+       int             i,j;
+       xfs_dqtrx_t     *oqa, *nqa;
+
+       if (!otp->t_dqinfo)
+               return;
+
+       xfs_trans_alloc_dqinfo(ntp);
+       oqa = otp->t_dqinfo->dqa_usrdquots;
+       nqa = ntp->t_dqinfo->dqa_usrdquots;
+
+       /*
+        * Because the quota blk reservation is carried forward,
+        * it is also necessary to carry forward the DQ_DIRTY flag.
+        */
+       if(otp->t_flags & XFS_TRANS_DQ_DIRTY)
+               ntp->t_flags |= XFS_TRANS_DQ_DIRTY;
+
+       for (j = 0; j < 2; j++) {
+               for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
+                       if (oqa[i].qt_dquot == NULL)
+                               break;
+                       oq = &oqa[i];
+                       nq = &nqa[i];
+
+                       nq->qt_dquot = oq->qt_dquot;
+                       nq->qt_bcount_delta = nq->qt_icount_delta = 0;
+                       nq->qt_rtbcount_delta = 0;
+
+                       /*
+                        * Transfer whatever is left of the reservations.
+                        */
+                       nq->qt_blk_res = oq->qt_blk_res - oq->qt_blk_res_used;
+                       oq->qt_blk_res = oq->qt_blk_res_used;
+
+                       nq->qt_rtblk_res = oq->qt_rtblk_res -
+                               oq->qt_rtblk_res_used;
+                       oq->qt_rtblk_res = oq->qt_rtblk_res_used;
+
+                       nq->qt_ino_res = oq->qt_ino_res - oq->qt_ino_res_used;
+                       oq->qt_ino_res = oq->qt_ino_res_used;
+
+               }
+               oqa = otp->t_dqinfo->dqa_grpdquots;
+               nqa = ntp->t_dqinfo->dqa_grpdquots;
+       }
+}
+
+/*
+ * Wrap around mod_dquot to account for both user and group quotas.
+ */
+void
+xfs_trans_mod_dquot_byino(
+       xfs_trans_t     *tp,
+       xfs_inode_t     *ip,
+       uint            field,
+       long            delta)
+{
+       xfs_mount_t     *mp;
+
+       ASSERT(tp);
+       mp = tp->t_mountp;
+
+       if (!XFS_IS_QUOTA_ON(mp) ||
+           ip->i_ino == mp->m_sb.sb_uquotino ||
+           ip->i_ino == mp->m_sb.sb_gquotino)
+               return;
+
+       if (tp->t_dqinfo == NULL)
+               xfs_trans_alloc_dqinfo(tp);
+
+       if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot) {
+               (void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta);
+       }
+       if (XFS_IS_GQUOTA_ON(mp) && ip->i_gdquot) {
+               (void) xfs_trans_mod_dquot(tp, ip->i_gdquot, field, delta);
+       }
+}
+
+STATIC xfs_dqtrx_t *
+xfs_trans_get_dqtrx(
+       xfs_trans_t     *tp,
+       xfs_dquot_t     *dqp)
+{
+       int             i;
+       xfs_dqtrx_t     *qa;
+
+       for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
+               qa = XFS_QM_DQP_TO_DQACCT(tp, dqp);
+
+               if (qa[i].qt_dquot == NULL ||
+                   qa[i].qt_dquot == dqp) {
+                       return (&qa[i]);
+               }
+       }
+
+       return (NULL);
+}
+
+/*
+ * Make the changes in the transaction structure.
+ * The moral equivalent to xfs_trans_mod_sb().
+ * We don't touch any fields in the dquot, so we don't care
+ * if it's locked or not (most of the time it won't be).
+ */
+void
+xfs_trans_mod_dquot(
+       xfs_trans_t     *tp,
+       xfs_dquot_t     *dqp,
+       uint            field,
+       long            delta)
+{
+       xfs_dqtrx_t     *qtrx;
+
+       ASSERT(tp);
+       qtrx = NULL;
+
+       if (tp->t_dqinfo == NULL)
+               xfs_trans_alloc_dqinfo(tp);
+       /*
+        * Find either the first free slot or the slot that belongs
+        * to this dquot.
+        */
+       qtrx = xfs_trans_get_dqtrx(tp, dqp);
+       ASSERT(qtrx);
+       if (qtrx->qt_dquot == NULL)
+               qtrx->qt_dquot = dqp;
+
+       switch (field) {
+
+               /*
+                * regular disk blk reservation
+                */
+             case XFS_TRANS_DQ_RES_BLKS:
+               qtrx->qt_blk_res += (ulong)delta;
+               break;
+
+               /*
+                * inode reservation
+                */
+             case XFS_TRANS_DQ_RES_INOS:
+               qtrx->qt_ino_res += (ulong)delta;
+               break;
+
+               /*
+                * disk blocks used.
+                */
+             case XFS_TRANS_DQ_BCOUNT:
+               if (qtrx->qt_blk_res && delta > 0) {
+                       qtrx->qt_blk_res_used += (ulong)delta;
+                       ASSERT(qtrx->qt_blk_res >= qtrx->qt_blk_res_used);
+               }
+               qtrx->qt_bcount_delta += delta;
+               break;
+
+             case XFS_TRANS_DQ_DELBCOUNT:
+               qtrx->qt_delbcnt_delta += delta;
+               break;
+
+               /*
+                * Inode Count
+                */
+             case XFS_TRANS_DQ_ICOUNT:
+               if (qtrx->qt_ino_res && delta > 0) {
+                       qtrx->qt_ino_res_used += (ulong)delta;
+                       ASSERT(qtrx->qt_ino_res >= qtrx->qt_ino_res_used);
+               }
+               qtrx->qt_icount_delta += delta;
+               break;
+
+               /*
+                * rtblk reservation
+                */
+             case XFS_TRANS_DQ_RES_RTBLKS:
+               qtrx->qt_rtblk_res += (ulong)delta;
+               break;
+
+               /*
+                * rtblk count
+                */
+             case XFS_TRANS_DQ_RTBCOUNT:
+               if (qtrx->qt_rtblk_res && delta > 0) {
+                       qtrx->qt_rtblk_res_used += (ulong)delta;
+                       ASSERT(qtrx->qt_rtblk_res >= qtrx->qt_rtblk_res_used);
+               }
+               qtrx->qt_rtbcount_delta += delta;
+               break;
+
+             case XFS_TRANS_DQ_DELRTBCOUNT:
+               qtrx->qt_delrtb_delta += delta;
+               break;
+
+             default:
+               ASSERT(0);
+       }
+       tp->t_flags |= XFS_TRANS_DQ_DIRTY;
+}
+
+
+/*
+ * Given an array of dqtrx structures, lock all the dquots associated
+ * and join them to the transaction, provided they have been modified.
+ * We know that the highest number of dquots (of one type - usr OR grp),
+ * involved in a transaction is 2 and that both usr and grp combined - 3.
+ * So, we don't attempt to make this very generic.
+ */
+STATIC void
+xfs_trans_dqlockedjoin(
+       xfs_trans_t     *tp,
+       xfs_dqtrx_t     *q)
+{
+       ASSERT(q[0].qt_dquot != NULL);
+       if (q[1].qt_dquot == NULL) {
+               xfs_dqlock(q[0].qt_dquot);
+               xfs_trans_dqjoin(tp, q[0].qt_dquot);
+       } else {
+               ASSERT(XFS_QM_TRANS_MAXDQS == 2);
+               xfs_dqlock2(q[0].qt_dquot, q[1].qt_dquot);
+               xfs_trans_dqjoin(tp, q[0].qt_dquot);
+               xfs_trans_dqjoin(tp, q[1].qt_dquot);
+       }
+}
+
+
+/*
+ * Called by xfs_trans_commit() and similar in spirit to
+ * xfs_trans_apply_sb_deltas().
+ * Go thru all the dquots belonging to this transaction and modify the
+ * INCORE dquot to reflect the actual usages.
+ * Unreserve just the reservations done by this transaction.
+ * dquot is still left locked at exit.
+ */
+void
+xfs_trans_apply_dquot_deltas(
+       xfs_trans_t             *tp)
+{
+       int                     i, j;
+       xfs_dquot_t             *dqp;
+       xfs_dqtrx_t             *qtrx, *qa;
+       xfs_disk_dquot_t        *d;
+       long                    totalbdelta;
+       long                    totalrtbdelta;
+
+       if (! (tp->t_flags & XFS_TRANS_DQ_DIRTY))
+               return;
+
+       ASSERT(tp->t_dqinfo);
+       qa = tp->t_dqinfo->dqa_usrdquots;
+       for (j = 0; j < 2; j++) {
+               if (qa[0].qt_dquot == NULL) {
+                       qa = tp->t_dqinfo->dqa_grpdquots;
+                       continue;
+               }
+
+               /*
+                * Lock all of the dquots and join them to the transaction.
+                */
+               xfs_trans_dqlockedjoin(tp, qa);
+
+               for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
+                       qtrx = &qa[i];
+                       /*
+                        * The array of dquots is filled
+                        * sequentially, not sparsely.
+                        */
+                       if ((dqp = qtrx->qt_dquot) == NULL)
+                               break;
+
+                       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+                       ASSERT(XFS_DQ_IS_ADDEDTO_TRX(tp, dqp));
+
+                       /*
+                        * adjust the actual number of blocks used
+                        */
+                       d = &dqp->q_core;
+
+                       /*
+                        * The issue here is - sometimes we don't make a blkquota
+                        * reservation intentionally to be fair to users
+                        * (when the amount is small). On the other hand,
+                        * delayed allocs do make reservations, but that's
+                        * outside of a transaction, so we have no
+                        * idea how much was really reserved.
+                        * So, here we've accumulated delayed allocation blks and
+                        * non-delay blks. The assumption is that the
+                        * delayed ones are always reserved (outside of a
+                        * transaction), and the others may or may not have
+                        * quota reservations.
+                        */
+                       totalbdelta = qtrx->qt_bcount_delta +
+                               qtrx->qt_delbcnt_delta;
+                       totalrtbdelta = qtrx->qt_rtbcount_delta +
+                               qtrx->qt_delrtb_delta;
+#ifdef QUOTADEBUG
+                       if (totalbdelta < 0)
+                               ASSERT(INT_GET(d->d_bcount, ARCH_CONVERT) >=
+                                      (xfs_qcnt_t) -totalbdelta);
+
+                       if (totalrtbdelta < 0)
+                               ASSERT(INT_GET(d->d_rtbcount, ARCH_CONVERT) >=
+                                      (xfs_qcnt_t) -totalrtbdelta);
+
+                       if (qtrx->qt_icount_delta < 0)
+                               ASSERT(INT_GET(d->d_icount, ARCH_CONVERT) >=
+                                      (xfs_qcnt_t) -qtrx->qt_icount_delta);
+#endif
+                       if (totalbdelta)
+                               INT_MOD(d->d_bcount, ARCH_CONVERT, (xfs_qcnt_t)totalbdelta);
+
+                       if (qtrx->qt_icount_delta)
+                               INT_MOD(d->d_icount, ARCH_CONVERT, (xfs_qcnt_t)qtrx->qt_icount_delta);
+
+                       if (totalrtbdelta)
+                               INT_MOD(d->d_rtbcount, ARCH_CONVERT, (xfs_qcnt_t)totalrtbdelta);
+
+                       /*
+                        * Start/reset the timer(s) if needed.
+                        */
+                       xfs_qm_adjust_dqtimers(tp->t_mountp, d);
+
+                       dqp->dq_flags |= XFS_DQ_DIRTY;
+                       /*
+                        * add this to the list of items to get logged
+                        */
+                       xfs_trans_log_dquot(tp, dqp);
+                       /*
+                        * Take off what's left of the original reservation.
+                        * In case of delayed allocations, there's no
+                        * reservation that a transaction structure knows of.
+                        */
+                       if (qtrx->qt_blk_res != 0) {
+                               if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) {
+                                       if (qtrx->qt_blk_res >
+                                           qtrx->qt_blk_res_used)
+                                               dqp->q_res_bcount -= (xfs_qcnt_t)
+                                                       (qtrx->qt_blk_res -
+                                                        qtrx->qt_blk_res_used);
+                                       else
+                                               dqp->q_res_bcount -= (xfs_qcnt_t)
+                                                       (qtrx->qt_blk_res_used -
+                                                        qtrx->qt_blk_res);
+                               }
+                       } else {
+                               /*
+                                * These blks were never reserved, either inside
+                                * a transaction or outside one (in a delayed
+                                * allocation). Also, this isn't always a
+                                * negative number since we sometimes
+                                * deliberately skip quota reservations.
+                                */
+                               if (qtrx->qt_bcount_delta) {
+                                       dqp->q_res_bcount +=
+                                             (xfs_qcnt_t)qtrx->qt_bcount_delta;
+                               }
+                       }
+                       /*
+                        * Adjust the RT reservation.
+                        */
+                       if (qtrx->qt_rtblk_res != 0) {
+                               if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) {
+                                       if (qtrx->qt_rtblk_res >
+                                           qtrx->qt_rtblk_res_used)
+                                              dqp->q_res_rtbcount -= (xfs_qcnt_t)
+                                                      (qtrx->qt_rtblk_res -
+                                                       qtrx->qt_rtblk_res_used);
+                                       else
+                                              dqp->q_res_rtbcount -= (xfs_qcnt_t)
+                                                      (qtrx->qt_rtblk_res_used -
+                                                       qtrx->qt_rtblk_res);
+                               }
+                       } else {
+                               if (qtrx->qt_rtbcount_delta)
+                                       dqp->q_res_rtbcount +=
+                                           (xfs_qcnt_t)qtrx->qt_rtbcount_delta;
+                       }
+
+                       /*
+                        * Adjust the inode reservation.
+                        */
+                       if (qtrx->qt_ino_res != 0) {
+                               ASSERT(qtrx->qt_ino_res >=
+                                      qtrx->qt_ino_res_used);
+                               if (qtrx->qt_ino_res > qtrx->qt_ino_res_used)
+                                       dqp->q_res_icount -= (xfs_qcnt_t)
+                                               (qtrx->qt_ino_res -
+                                                qtrx->qt_ino_res_used);
+                       } else {
+                               if (qtrx->qt_icount_delta)
+                                       dqp->q_res_icount +=
+                                           (xfs_qcnt_t)qtrx->qt_icount_delta;
+                       }
+
+
+#ifdef QUOTADEBUG
+                       if (qtrx->qt_rtblk_res != 0)
+                               cmn_err(CE_DEBUG, "RT res %d for 0x%p\n",
+                                       (int) qtrx->qt_rtblk_res, dqp);
+#endif
+                       ASSERT(dqp->q_res_bcount >=
+                               INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
+                       ASSERT(dqp->q_res_icount >=
+                               INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
+                       ASSERT(dqp->q_res_rtbcount >=
+                               INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT));
+               }
+               /*
+                * Do the group quotas next
+                */
+               qa = tp->t_dqinfo->dqa_grpdquots;
+       }
+}
+
+/*
+ * Release the reservations, and adjust the dquots accordingly.
+ * This is called only when the transaction is being aborted. If by
+ * any chance we have done dquot modifications incore (ie. deltas) already,
+ * we simply throw those away, since that's the expected behavior
+ * when a transaction is curtailed without a commit.
+ */
+STATIC void
+xfs_trans_unreserve_and_mod_dquots(
+       xfs_trans_t             *tp)
+{
+       int                     i, j;
+       xfs_dquot_t             *dqp;
+       xfs_dqtrx_t             *qtrx, *qa;
+       boolean_t               locked;
+
+       if (!tp->t_dqinfo || !(tp->t_flags & XFS_TRANS_DQ_DIRTY))
+               return;
+
+       qa = tp->t_dqinfo->dqa_usrdquots;
+
+       for (j = 0; j < 2; j++) {
+               for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
+                       qtrx = &qa[i];
+                       /*
+                        * We assume that the array of dquots is filled
+                        * sequentially, not sparsely.
+                        */
+                       if ((dqp = qtrx->qt_dquot) == NULL)
+                               break;
+                       /*
+                        * Unreserve the original reservation. We don't care
+                        * about the number of blocks used field, or deltas.
+                        * Also we don't bother to zero the fields.
+                        */
+                       locked = B_FALSE;
+                       if (qtrx->qt_blk_res) {
+                               xfs_dqlock(dqp);
+                               locked = B_TRUE;
+                               dqp->q_res_bcount -=
+                                       (xfs_qcnt_t)qtrx->qt_blk_res;
+                       }
+                       if (qtrx->qt_ino_res) {
+                               if (!locked) {
+                                       xfs_dqlock(dqp);
+                                       locked = B_TRUE;
+                               }
+                               dqp->q_res_icount -=
+                                       (xfs_qcnt_t)qtrx->qt_ino_res;
+                       }
+
+                       if (qtrx->qt_rtblk_res) {
+                               if (!locked) {
+                                       xfs_dqlock(dqp);
+                                       locked = B_TRUE;
+                               }
+                               dqp->q_res_rtbcount -=
+                                       (xfs_qcnt_t)qtrx->qt_rtblk_res;
+                       }
+                       if (locked)
+                               xfs_dqunlock(dqp);
+
+               }
+               qa = tp->t_dqinfo->dqa_grpdquots;
+       }
+}
+
+/*
+ * This reserves disk blocks and inodes against a dquot.
+ * Flags indicate if the dquot is to be locked here and also
+ * if the blk reservation is for RT or regular blocks.
+ * Sending in XFS_QMOPT_FORCE_RES flag skips the quota check.
+ * Returns EDQUOT if quota is exceeded.
+ */
+STATIC int
+xfs_trans_dqresv(
+       xfs_trans_t     *tp,
+       xfs_dquot_t     *dqp,
+       long            nblks,
+       long            ninos,
+       uint            flags)
+{
+       int             error;
+       xfs_qcnt_t      hardlimit;
+       xfs_qcnt_t      softlimit;
+       time_t          btimer;
+       xfs_qcnt_t      *resbcountp;
+
+       if (! (flags & XFS_QMOPT_DQLOCK)) {
+               xfs_dqlock(dqp);
+       }
+       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+       if (flags & XFS_TRANS_DQ_RES_BLKS) {
+               hardlimit = INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT);
+               softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT);
+               btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT);
+               resbcountp = &dqp->q_res_bcount;
+       } else {
+               ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS);
+               hardlimit = INT_GET(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT);
+               softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT);
+               btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT);
+               resbcountp = &dqp->q_res_rtbcount;
+       }
+       error = 0;
+
+       if ((flags & XFS_QMOPT_FORCE_RES) == 0 &&
+           !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT) &&
+           XFS_IS_QUOTA_ENFORCED(dqp->q_mount)) {
+#ifdef QUOTADEBUG
+               cmn_err(CE_DEBUG, "BLK Res: nblks=%ld + resbcount=%Ld"
+                         " > hardlimit=%Ld?", nblks, *resbcountp, hardlimit);
+#endif
+               if (nblks > 0) {
+                       /*
+                        * dquot is locked already. See if we'd go over the
+                        * hardlimit or exceed the timelimit if we allocate
+                        * nblks.
+                        */
+                       if (hardlimit > 0ULL &&
+                            (hardlimit <= nblks + *resbcountp)) {
+                               error = EDQUOT;
+                               goto error_return;
+                       }
+
+                       if (softlimit > 0ULL &&
+                            (softlimit <= nblks + *resbcountp)) {
+                               /*
+                                * If timer or warnings has expired,
+                                * return EDQUOT
+                                */
+                               if ((btimer != 0 && get_seconds() > btimer) ||
+                                   (!INT_ISZERO(dqp->q_core.d_bwarns, ARCH_CONVERT) &&
+                                    INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) >=
+                                    XFS_QI_BWARNLIMIT(dqp->q_mount))) {
+                                       error = EDQUOT;
+                                       goto error_return;
+                               }
+                       }
+               }
+               if (ninos > 0) {
+                       if (INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) > 0ULL &&
+                           INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >=
+                           INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT)) {
+                               error = EDQUOT;
+                               goto error_return;
+                       } else if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) > 0ULL &&
+                                  INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >=
+                                  INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) {
+                               /*
+                                * If timer or warnings has expired,
+                                * return EDQUOT
+                                */
+                               if ((!INT_ISZERO(dqp->q_core.d_itimer, ARCH_CONVERT) &&
+                                    get_seconds() > INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)) ||
+                                   (!INT_ISZERO(dqp->q_core.d_iwarns, ARCH_CONVERT) &&
+                                    INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) >=
+                                    XFS_QI_IWARNLIMIT(dqp->q_mount))) {
+                                       error = EDQUOT;
+                                       goto error_return;
+                               }
+                       }
+               }
+       }
+
+       /*
+        * Change the reservation, but not the actual usage.
+        * Note that q_res_bcount = q_core.d_bcount + resv
+        */
+       (*resbcountp) += (xfs_qcnt_t)nblks;
+       if (ninos != 0)
+               dqp->q_res_icount += (xfs_qcnt_t)ninos;
+
+       /*
+        * note the reservation amt in the trans struct too,
+        * so that the transaction knows how much was reserved by
+        * it against this particular dquot.
+        * We don't do this when we are reserving for a delayed allocation,
+        * because we don't have the luxury of a transaction envelope then.
+        */
+       if (tp) {
+               ASSERT(tp->t_dqinfo);
+               ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
+               if (nblks != 0)
+                       xfs_trans_mod_dquot(tp, dqp,
+                                           flags & XFS_QMOPT_RESBLK_MASK,
+                                           nblks);
+               if (ninos != 0)
+                       xfs_trans_mod_dquot(tp, dqp,
+                                           XFS_TRANS_DQ_RES_INOS,
+                                           ninos);
+       }
+       ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
+       ASSERT(dqp->q_res_rtbcount >= INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT));
+       ASSERT(dqp->q_res_icount >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
+
+error_return:
+       if (! (flags & XFS_QMOPT_DQLOCK)) {
+               xfs_dqunlock(dqp);
+       }
+       return (error);
+}
+
+
+/*
+ * Given a dquot(s), make disk block and/or inode reservations against them.
+ * The fact that this does the reservation against both the usr and
+ * grp quotas is important, because this follows a both-or-nothing
+ * approach.
+ *
+ * flags = XFS_QMOPT_DQLOCK indicate if dquot(s) need to be locked.
+ *        XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown.
+ *        XFS_TRANS_DQ_RES_BLKS reserves regular disk blocks
+ *        XFS_TRANS_DQ_RES_RTBLKS reserves realtime disk blocks
+ * dquots are unlocked on return, if they were not locked by caller.
+ */
+int
+xfs_trans_reserve_quota_bydquots(
+       xfs_trans_t     *tp,
+       xfs_mount_t     *mp,
+       xfs_dquot_t     *udqp,
+       xfs_dquot_t     *gdqp,
+       long            nblks,
+       long            ninos,
+       uint            flags)
+{
+       int             resvd;
+
+       if (! XFS_IS_QUOTA_ON(mp))
+               return (0);
+
+       if (tp && tp->t_dqinfo == NULL)
+               xfs_trans_alloc_dqinfo(tp);
+
+       ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
+       resvd = 0;
+
+       if (udqp) {
+               if (xfs_trans_dqresv(tp, udqp, nblks, ninos, flags))
+                       return (EDQUOT);
+               resvd = 1;
+       }
+
+       if (gdqp) {
+               if (xfs_trans_dqresv(tp, gdqp, nblks, ninos, flags)) {
+                       /*
+                        * can't do it, so backout previous reservation
+                        */
+                       if (resvd) {
+                               xfs_trans_dqresv(tp, udqp,  -nblks, -ninos,
+                                                flags);
+                       }
+                       return (EDQUOT);
+               }
+       }
+
+       /*
+        * Didnt change anything critical, so, no need to log
+        */
+       return (0);
+}
+
+
+/*
+ * Lock the dquot and change the reservation if we can.
+ * This doesn't change the actual usage, just the reservation.
+ * The inode sent in is locked.
+ *
+ * Returns 0 on success, EDQUOT or other errors otherwise
+ */
+STATIC int
+xfs_trans_reserve_quota_nblks(
+       xfs_trans_t     *tp,
+       xfs_mount_t     *mp,
+       xfs_inode_t     *ip,
+       long            nblks,
+       long            ninos,
+       uint            type)
+{
+       int             error;
+
+       if (!XFS_IS_QUOTA_ON(mp))
+               return (0);
+
+       ASSERT(ip->i_ino != mp->m_sb.sb_uquotino);
+       ASSERT(ip->i_ino != mp->m_sb.sb_gquotino);
+
+#ifdef QUOTADEBUG
+       if (ip->i_udquot)
+               ASSERT(! XFS_DQ_IS_LOCKED(ip->i_udquot));
+       if (ip->i_gdquot)
+               ASSERT(! XFS_DQ_IS_LOCKED(ip->i_gdquot));
+#endif
+
+       ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+       ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
+       ASSERT((type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_RTBLKS ||
+              (type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_BLKS);
+
+       /*
+        * Reserve nblks against these dquots, with trans as the mediator.
+        */
+       error = xfs_trans_reserve_quota_bydquots(tp, mp,
+                                                ip->i_udquot, ip->i_gdquot,
+                                                nblks, ninos,
+                                                type);
+       return (error);
+}
+
+/*
+ * This routine is called to allocate a quotaoff log item.
+ */
+xfs_qoff_logitem_t *
+xfs_trans_get_qoff_item(
+       xfs_trans_t             *tp,
+       xfs_qoff_logitem_t      *startqoff,
+       uint                    flags)
+{
+       xfs_qoff_logitem_t      *q;
+
+       ASSERT(tp != NULL);
+
+       q = xfs_qm_qoff_logitem_init(tp->t_mountp, startqoff, flags);
+       ASSERT(q != NULL);
+
+       /*
+        * Get a log_item_desc to point at the new item.
+        */
+       (void) xfs_trans_add_item(tp, (xfs_log_item_t*)q);
+
+       return (q);
+}
+
+
+/*
+ * This is called to mark the quotaoff logitem as needing
+ * to be logged when the transaction is committed.  The logitem must
+ * already be associated with the given transaction.
+ */
+void
+xfs_trans_log_quotaoff_item(
+       xfs_trans_t             *tp,
+       xfs_qoff_logitem_t      *qlp)
+{
+       xfs_log_item_desc_t     *lidp;
+
+       lidp = xfs_trans_find_item(tp, (xfs_log_item_t *)qlp);
+       ASSERT(lidp != NULL);
+
+       tp->t_flags |= XFS_TRANS_DIRTY;
+       lidp->lid_flags |= XFS_LID_DIRTY;
+}
+
+STATIC void
+xfs_trans_alloc_dqinfo(
+       xfs_trans_t     *tp)
+{
+       (tp)->t_dqinfo = kmem_zone_zalloc(xfs_Gqm->qm_dqtrxzone, KM_SLEEP);
+}
+
+STATIC void
+xfs_trans_free_dqinfo(
+       xfs_trans_t     *tp)
+{
+       if (!tp->t_dqinfo)
+               return;
+       kmem_zone_free(xfs_Gqm->qm_dqtrxzone, (tp)->t_dqinfo);
+       (tp)->t_dqinfo = NULL;
+}
+
+xfs_dqtrxops_t xfs_trans_dquot_ops = {
+       .qo_dup_dqinfo                  = xfs_trans_dup_dqinfo,
+       .qo_free_dqinfo                 = xfs_trans_free_dqinfo,
+       .qo_mod_dquot_byino             = xfs_trans_mod_dquot_byino,
+       .qo_apply_dquot_deltas          = xfs_trans_apply_dquot_deltas,
+       .qo_reserve_quota_nblks         = xfs_trans_reserve_quota_nblks,
+       .qo_reserve_quota_bydquots      = xfs_trans_reserve_quota_bydquots,
+       .qo_unreserve_and_mod_dquots    = xfs_trans_unreserve_and_mod_dquots,
+};
index eb5370140f537ed7d7259e38ff0dad2683cc3a2f..0c869d102fd0be27aafb7fd30ab0d752b7bad690 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -66,6 +66,9 @@
 #include <xfs_dir.h>
 #include <xfs_dir2.h>
 #include <xfs_imap.h>
+#include <xfs_alloc.h>
+#include <xfs_dmapi.h>
+#include <xfs_quota.h>
 #include <xfs_mount.h>
 #include <xfs_alloc_btree.h>
 #include <xfs_bmap_btree.h>
 #include <xfs_dir2_sf.h>
 #include <xfs_dinode.h>
 #include <xfs_inode.h>
-#include <xfs_alloc.h>
 #include <xfs_bmap.h>
 #include <xfs_bit.h>
 #include <xfs_rtalloc.h>
 #include <xfs_error.h>
-#include <xfs_quota.h>
 #include <xfs_itable.h>
-#include <xfs_dqblk.h>
-#include <xfs_dquot_item.h>
-#include <xfs_dquot.h>
-#include <xfs_qm.h>
 #include <xfs_rw.h>
 #include <xfs_da_btree.h>
 #include <xfs_dir_leaf.h>
 #include <xfs_trans_priv.h>
 #include <xfs_trans_space.h>
 #include <xfs_utils.h>
-#include <xfs_dmapi.h>
 
 #endif /* __XFS_H__ */
index aeebe527657c3e47d82b44f5a5673a84309370dc..9035b4796c3f962d6188a85c654278fbfe75aff5 100644 (file)
@@ -197,10 +197,8 @@ xfs_attr_set(bhv_desc_t *bdp, char *name, char *value, int valuelen, int flags,
        /*
         * Attach the dquots to the inode.
         */
-       if (XFS_IS_QUOTA_ON(mp)) {
-               if ((error = xfs_qm_dqattach(dp, 0)))
-                       return (error);
-       }
+       if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
+               return (error);
 
        /*
         * If the inode doesn't have an attribute fork, add one.
@@ -280,19 +278,13 @@ xfs_attr_set(bhv_desc_t *bdp, char *name, char *value, int valuelen, int flags,
        }
        xfs_ilock(dp, XFS_ILOCK_EXCL);
 
-       if (XFS_IS_QUOTA_ON(mp)) {
-               if (rsvd) {
-                       error = xfs_trans_reserve_blkquota_force(args.trans,
-                                       dp, nblks);
-               } else {
-                       error = xfs_trans_reserve_blkquota(args.trans,
-                                       dp, nblks);
-               }
-               if (error) {
-                       xfs_iunlock(dp, XFS_ILOCK_EXCL);
-                       xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
-                       return (error);
-               }
+       error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, nblks, 0,
+                        rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
+                               XFS_QMOPT_RES_REGBLKS);
+       if (error) {
+               xfs_iunlock(dp, XFS_ILOCK_EXCL);
+               xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
+               return (error);
        }
 
        xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
@@ -483,12 +475,9 @@ xfs_attr_remove(bhv_desc_t *bdp, char *name, int flags, struct cred *cred)
        /*
         * Attach the dquots to the inode.
         */
-       if (XFS_IS_QUOTA_ON(mp)) {
-               if (XFS_NOT_DQATTACHED(mp, dp)) {
-                       if ((error = xfs_qm_dqattach(dp, 0)))
-                               return (error);
-               }
-       }
+       if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
+               return (error);
+
        /*
         * Start our first transaction of the day.
         *
index 344a52aa9fcdd9dba59242fbded0f8a9a8eb63aa..2f742c82c2d67a7ce90ab8b2ab29c4673fe74a0f 100644 (file)
@@ -2145,7 +2145,7 @@ xfs_bmap_alloc(
         */
        mp = ap->ip->i_mount;
        nullfb = ap->firstblock == NULLFSBLOCK;
-       rt = (ap->ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && ap->userdata;
+       rt = XFS_IS_REALTIME_INODE(ap->ip) && ap->userdata;
        fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock);
 #ifdef __KERNEL__
        if (rt) {
@@ -2467,14 +2467,10 @@ xfs_bmap_alloc(
                         * Adjust the disk quota also. This was reserved
                         * earlier.
                         */
-                       if (XFS_IS_QUOTA_ON(mp) &&
-                           ap->ip->i_ino != mp->m_sb.sb_uquotino &&
-                           ap->ip->i_ino != mp->m_sb.sb_gquotino)
-                               xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
-                                       ap->wasdel ?
-                                               XFS_TRANS_DQ_DELRTBCOUNT :
+                       XFS_TRANS_MOD_DQUOT_BYINO(mp, ap->tp, ap->ip,
+                               ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT :
                                                XFS_TRANS_DQ_RTBCOUNT,
-                                       (long)ralen);
+                               (long) ralen);
                } else
                        ap->alen = 0;
 #endif /* __KERNEL__ */
@@ -2691,14 +2687,10 @@ xfs_bmap_alloc(
                         * Adjust the disk quota also. This was reserved
                         * earlier.
                         */
-                       if (XFS_IS_QUOTA_ON(mp) &&
-                           ap->ip->i_ino != mp->m_sb.sb_uquotino &&
-                           ap->ip->i_ino != mp->m_sb.sb_gquotino)
-                               xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
-                                       ap->wasdel ?
-                                               XFS_TRANS_DQ_DELBCOUNT :
+                       XFS_TRANS_MOD_DQUOT_BYINO(mp, ap->tp, ap->ip,
+                               ap->wasdel ? XFS_TRANS_DQ_DELBCOUNT :
                                                XFS_TRANS_DQ_BCOUNT,
-                                       (long)args.len);
+                               (long) args.len);
                } else {
                        ap->rval = NULLFSBLOCK;
                        ap->alen = 0;
@@ -2755,10 +2747,7 @@ xfs_bmap_btree_to_extents(
                return error;
        xfs_bmap_add_free(cbno, 1, cur->bc_private.b.flist, mp);
        ip->i_d.di_nblocks--;
-       if (XFS_IS_QUOTA_ON(mp) &&
-           ip->i_ino != mp->m_sb.sb_uquotino &&
-           ip->i_ino != mp->m_sb.sb_gquotino)
-               xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
+       XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
        xfs_trans_binval(tp, cbp);
        if (cur->bc_bufs[0] == cbp)
                cur->bc_bufs[0] = NULL;
@@ -2854,10 +2843,7 @@ xfs_bmap_del_extent(
                                goto done;
                        do_fx = 0;
                        nblks = len * mp->m_sb.sb_rextsize;
-                       if (XFS_IS_QUOTA_ON(mp) &&
-                           ip->i_ino != mp->m_sb.sb_uquotino &&
-                           ip->i_ino != mp->m_sb.sb_gquotino)
-                               qfield = XFS_TRANS_DQ_RTBCOUNT;
+                       qfield = XFS_TRANS_DQ_RTBCOUNT;
                }
                /*
                 * Ordinary allocation.
@@ -2865,10 +2851,7 @@ xfs_bmap_del_extent(
                else {
                        do_fx = 1;
                        nblks = del->br_blockcount;
-                       if (XFS_IS_QUOTA_ON(mp) &&
-                           ip->i_ino != mp->m_sb.sb_uquotino &&
-                           ip->i_ino != mp->m_sb.sb_gquotino)
-                               qfield = XFS_TRANS_DQ_BCOUNT;
+                       qfield = XFS_TRANS_DQ_BCOUNT;
                }
                /*
                 * Set up del_endblock and cur for later.
@@ -3088,7 +3071,8 @@ xfs_bmap_del_extent(
         * Adjust quota data.
         */
        if (qfield)
-               xfs_trans_mod_dquot_byino(tp, ip, qfield, (long)-nblks);
+               XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, qfield, (long)-nblks);
+
        /*
         * Account for change in delayed indirect blocks.
         * Nothing to do for disk quota accounting here.
@@ -3239,10 +3223,7 @@ xfs_bmap_extents_to_btree(
        *firstblock = cur->bc_private.b.firstblock = args.fsbno;
        cur->bc_private.b.allocated++;
        ip->i_d.di_nblocks++;
-       if (XFS_IS_QUOTA_ON(mp) &&
-           ip->i_ino != mp->m_sb.sb_uquotino &&
-           ip->i_ino != mp->m_sb.sb_gquotino)
-               xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
+       XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_BCOUNT, 1L);
        abp = xfs_btree_get_bufl(mp, tp, args.fsbno, 0);
        /*
         * Fill in the child block.
@@ -3385,11 +3366,8 @@ xfs_bmap_local_to_extents(
                xfs_bmap_trace_post_update(fname, "new", ip, 0, whichfork);
                XFS_IFORK_NEXT_SET(ip, whichfork, 1);
                ip->i_d.di_nblocks = 1;
-               if (XFS_IS_QUOTA_ON(args.mp) &&
-                   ip->i_ino != args.mp->m_sb.sb_uquotino &&
-                   ip->i_ino != args.mp->m_sb.sb_gquotino)
-                       xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT,
-                               1L);
+               XFS_TRANS_MOD_DQUOT_BYINO(args.mp, tp, ip,
+                       XFS_TRANS_DQ_BCOUNT, 1L);
                flags |= XFS_ILOG_FEXT(whichfork);
        } else
                ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0);
@@ -3772,18 +3750,13 @@ xfs_bmap_add_attrfork(
                        XFS_TRANS_PERM_LOG_RES, XFS_ADDAFORK_LOG_COUNT)))
                goto error0;
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-       if (XFS_IS_QUOTA_ON(mp)) {
-               if (rsvd) {
-                       error = xfs_trans_reserve_blkquota_force(tp, ip, blks);
-               } else {
-                       error = xfs_trans_reserve_blkquota(tp, ip, blks);
-               }
-
-               if (error) {
-                       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-                       xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES);
-                       return error;
-               }
+       error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, blks, 0, rsvd ?
+                       XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
+                       XFS_QMOPT_RES_REGBLKS);
+       if (error) {
+               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+               xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES);
+               return error;
        }
        if (XFS_IFORK_Q(ip))
                goto error1;
@@ -4655,8 +4628,8 @@ xfs_bmapi(
        cur = NULL;
        if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
                ASSERT(wr && tp);
-               if ((error = xfs_bmap_local_to_extents(tp, ip, firstblock, total,
-                               &logflags, whichfork)))
+               if ((error = xfs_bmap_local_to_extents(tp, ip,
+                               firstblock, total, &logflags, whichfork)))
                        goto error0;
        }
        if (wr && *firstblock == NULLFSBLOCK) {
@@ -4730,9 +4703,8 @@ xfs_bmapi(
                                 * We return EDQUOT if we haven't allocated
                                 * blks already inside this loop;
                                 */
-                               if (XFS_IS_QUOTA_ON(ip->i_mount) &&
-                                   xfs_trans_reserve_blkquota(NULL, ip,
-                                           (long)alen)) {
+                               if (XFS_TRANS_RESERVE_BLKQUOTA(
+                                               mp, NULL, ip, (long)alen)) {
                                        if (n == 0) {
                                                *nmap = 0;
                                                ASSERT(cur == NULL);
@@ -4740,12 +4712,10 @@ xfs_bmapi(
                                        }
                                        break;
                                }
-                               if (xfs_mod_incore_sb(ip->i_mount,
-                                               XFS_SBS_FDBLOCKS,
+                               if (xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS,
                                                -(alen + indlen), rsvd)) {
-                                       if (XFS_IS_QUOTA_ON(ip->i_mount))
-                                               xfs_trans_unreserve_blkquota(
-                                                       NULL, ip, (long)alen);
+                                       XFS_TRANS_UNRESERVE_BLKQUOTA(
+                                               mp, NULL, ip, (long)alen);
                                        break;
                                }
                                ip->i_delayed_blks += alen;
@@ -4808,15 +4778,11 @@ xfs_bmapi(
                                alen = bma.alen;
                                aoff = bma.off;
                                ASSERT(*firstblock == NULLFSBLOCK ||
-                                      XFS_FSB_TO_AGNO(ip->i_mount,
-                                              *firstblock) ==
-                                      XFS_FSB_TO_AGNO(ip->i_mount,
-                                              bma.firstblock) ||
+                                      XFS_FSB_TO_AGNO(mp, *firstblock) ==
+                                      XFS_FSB_TO_AGNO(mp, bma.firstblock) ||
                                       (flist->xbf_low &&
-                                       XFS_FSB_TO_AGNO(ip->i_mount,
-                                               *firstblock) <
-                                       XFS_FSB_TO_AGNO(ip->i_mount,
-                                               bma.firstblock)));
+                                       XFS_FSB_TO_AGNO(mp, *firstblock) <
+                                       XFS_FSB_TO_AGNO(mp, bma.firstblock)));
                                *firstblock = bma.firstblock;
                                if (cur)
                                        cur->bc_private.b.firstblock =
@@ -4824,7 +4790,7 @@ xfs_bmapi(
                                if (abno == NULLFSBLOCK)
                                        break;
                                if ((ifp->if_flags & XFS_IFBROOT) && !cur) {
-                                       cur = xfs_btree_init_cursor(ip->i_mount,
+                                       cur = xfs_btree_init_cursor(mp,
                                                tp, NULL, 0, XFS_BTNUM_BMAP,
                                                ip, whichfork);
                                        cur->bc_private.b.firstblock =
@@ -4941,7 +4907,7 @@ xfs_bmapi(
                         */
                        ASSERT(mval->br_blockcount <= len);
                        if ((ifp->if_flags & XFS_IFBROOT) && !cur) {
-                               cur = xfs_btree_init_cursor(ip->i_mount,
+                               cur = xfs_btree_init_cursor(mp,
                                        tp, NULL, 0, XFS_BTNUM_BMAP,
                                        ip, whichfork);
                                cur->bc_private.b.firstblock =
@@ -5063,12 +5029,12 @@ error0:
        if (cur) {
                if (!error) {
                        ASSERT(*firstblock == NULLFSBLOCK ||
-                              XFS_FSB_TO_AGNO(ip->i_mount, *firstblock) ==
-                              XFS_FSB_TO_AGNO(ip->i_mount,
+                              XFS_FSB_TO_AGNO(mp, *firstblock) ==
+                              XFS_FSB_TO_AGNO(mp,
                                       cur->bc_private.b.firstblock) ||
                               (flist->xbf_low &&
-                               XFS_FSB_TO_AGNO(ip->i_mount, *firstblock) <
-                               XFS_FSB_TO_AGNO(ip->i_mount,
+                               XFS_FSB_TO_AGNO(mp, *firstblock) <
+                               XFS_FSB_TO_AGNO(mp,
                                        cur->bc_private.b.firstblock)));
                        *firstblock = cur->bc_private.b.firstblock;
                }
@@ -5378,16 +5344,11 @@ xfs_bunmapi(
                        ASSERT(STARTBLOCKVAL(del.br_startblock) > 0);
                        xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS,
                                (int)del.br_blockcount, rsvd);
-                       if (XFS_IS_QUOTA_ON(ip->i_mount)) {
-                               ASSERT(ip->i_ino != mp->m_sb.sb_uquotino);
-                               ASSERT(ip->i_ino != mp->m_sb.sb_gquotino);
-                               if (!isrt)
-                                       xfs_trans_unreserve_blkquota(NULL, ip,
-                                             (long)del.br_blockcount);
-                               else
-                                       xfs_trans_unreserve_rtblkquota(NULL, ip,
-                                             (long)del.br_blockcount);
-                       }
+                       /* Unreserve our quota space */
+                       XFS_TRANS_RESERVE_QUOTA_NBLKS(
+                               mp, NULL, ip, -((long)del.br_blockcount), 0,
+                               isrt ?  XFS_QMOPT_RES_RTBLKS :
+                                       XFS_QMOPT_RES_REGBLKS);
                        ip->i_delayed_blks -= del.br_blockcount;
                        if (cur)
                                cur->bc_private.b.flags |=
@@ -5556,8 +5517,7 @@ xfs_getbmap(
            && DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ)
            && whichfork == XFS_DATA_FORK) {
 
-               error = xfs_dm_send_data_event(DM_EVENT_READ, bdp,
-                               0, 0, 0, NULL);
+               error = XFS_SEND_DATA(mp, DM_EVENT_READ, bdp, 0, 0, 0, NULL);
                if (error)
                        return XFS_ERROR(error);
        }
@@ -5579,7 +5539,6 @@ xfs_getbmap(
                   ip->i_d.di_format != XFS_DINODE_FMT_BTREE &&
                   ip->i_d.di_format != XFS_DINODE_FMT_LOCAL)
                return XFS_ERROR(EINVAL);
-
        if (whichfork == XFS_DATA_FORK) {
                if (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) {
                        prealloced = 1;
@@ -5928,10 +5887,13 @@ xfs_check_block(
                                thispa = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize,
                                        xfs_bmbt, block, j, dmxr);
                        }
-                       if (INT_GET(*thispa, ARCH_CONVERT) == INT_GET(*pp, ARCH_CONVERT)) {
-                               printk("xfs_check_block: thispa(%d) == pp(%d) %Ld\n",
-                                               j, i, INT_GET(*thispa, ARCH_CONVERT));
-                               panic("xfs_check_block: ptrs are equal in node\n");
+                       if (INT_GET(*thispa, ARCH_CONVERT) ==
+                           INT_GET(*pp, ARCH_CONVERT)) {
+                               cmn_err(CE_WARN, "%s: thispa(%d) == pp(%d) %Ld",
+                                       __FUNCTION__, j, i,
+                                       INT_GET(*thispa, ARCH_CONVERT));
+                               panic("%s: ptrs are equal in node\n",
+                                       __FUNCTION__);
                        }
                }
        }
@@ -6089,12 +6051,13 @@ xfs_bmap_check_leaf_extents(
        return;
 
 error0:
-       printk("at error0\n");
+       cmn_err(CE_WARN, "%s: at error0", __FUNCTION__);
        if (bp_release)
                xfs_trans_brelse(NULL, bp);
 error_norelse:
-       printk("xfs_bmap_check_leaf_extents: BAD after btree leaves for %d extents\n", i);
-       panic("xfs_bmap_check_leaf_extents: CORRUPTED BTREE OR SOMETHING");
+       cmn_err(CE_WARN, "%s: BAD after btree leaves for %d extents",
+               i, __FUNCTION__);
+       panic("%s: CORRUPTED BTREE OR SOMETHING", __FUNCTION__);
        return;
 }
 #endif
index f49fc3fd305ee00788832ed8dd3695d64d4a34b6..43a0680371f43a7dd279b7263e282313bcde8ac5 100644 (file)
@@ -629,8 +629,8 @@ xfs_bmbt_delrec(
        xfs_bmbt_log_block(cur, lbp, XFS_BB_RIGHTSIB | XFS_BB_NUMRECS);
        if (INT_GET(left->bb_rightsib, ARCH_CONVERT) != NULLDFSBNO) {
                if ((error = xfs_btree_read_bufl(mp, cur->bc_tp,
-                               INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, &rrbp,
-                               XFS_BMAP_BTREE_REF))) {
+                               INT_GET(left->bb_rightsib, ARCH_CONVERT),
+                               0, &rrbp, XFS_BMAP_BTREE_REF))) {
                        XFS_BMBT_TRACE_CURSOR(cur, ERROR);
                        goto error0;
                }
@@ -646,10 +646,7 @@ xfs_bmbt_delrec(
                cur->bc_private.b.flist, mp);
        cur->bc_private.b.ip->i_d.di_nblocks--;
        xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, XFS_ILOG_CORE);
-       if (XFS_IS_QUOTA_ON(mp) &&
-           cur->bc_private.b.ip->i_ino != mp->m_sb.sb_uquotino &&
-           cur->bc_private.b.ip->i_ino != mp->m_sb.sb_gquotino)
-               xfs_trans_mod_dquot_byino(cur->bc_tp, cur->bc_private.b.ip,
+       XFS_TRANS_MOD_DQUOT_BYINO(mp, cur->bc_tp, cur->bc_private.b.ip,
                        XFS_TRANS_DQ_BCOUNT, -1L);
        xfs_trans_binval(cur->bc_tp, rbp);
        if (bp != lbp) {
@@ -986,13 +983,10 @@ xfs_bmbt_killroot(
 #endif
        memcpy(pp, cpp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*pp));
        xfs_bmap_add_free(XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(cbp)), 1,
-               cur->bc_private.b.flist, cur->bc_mp);
+                       cur->bc_private.b.flist, cur->bc_mp);
        ip->i_d.di_nblocks--;
-       if (XFS_IS_QUOTA_ON(cur->bc_mp) &&
-           ip->i_ino != cur->bc_mp->m_sb.sb_uquotino &&
-           ip->i_ino != cur->bc_mp->m_sb.sb_gquotino)
-               xfs_trans_mod_dquot_byino(cur->bc_tp, ip, XFS_TRANS_DQ_BCOUNT,
-                       -1L);
+       XFS_TRANS_MOD_DQUOT_BYINO(cur->bc_mp, cur->bc_tp, ip,
+                       XFS_TRANS_DQ_BCOUNT, -1L);
        xfs_trans_binval(cur->bc_tp, cbp);
        cur->bc_bufs[level - 1] = NULL;
        INT_MOD(block->bb_level, ARCH_CONVERT, -1);
@@ -1589,10 +1583,7 @@ xfs_bmbt_split(
        cur->bc_private.b.allocated++;
        cur->bc_private.b.ip->i_d.di_nblocks++;
        xfs_trans_log_inode(args.tp, cur->bc_private.b.ip, XFS_ILOG_CORE);
-       if (XFS_IS_QUOTA_ON(args.mp) &&
-           cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_uquotino &&
-           cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_gquotino)
-               xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip,
+       XFS_TRANS_MOD_DQUOT_BYINO(args.mp, args.tp, cur->bc_private.b.ip,
                        XFS_TRANS_DQ_BCOUNT, 1L);
        rbp = xfs_btree_get_bufl(args.mp, args.tp, args.fsbno, 0);
        right = XFS_BUF_TO_BMBT_BLOCK(rbp);
@@ -2390,11 +2381,8 @@ xfs_bmbt_newroot(
        cur->bc_private.b.firstblock = args.fsbno;
        cur->bc_private.b.allocated++;
        cur->bc_private.b.ip->i_d.di_nblocks++;
-       if (XFS_IS_QUOTA_ON(args.mp) &&
-           cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_uquotino &&
-           cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_gquotino)
-               xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip,
-                                         XFS_TRANS_DQ_BCOUNT, 1L);
+       XFS_TRANS_MOD_DQUOT_BYINO(args.mp, args.tp, cur->bc_private.b.ip,
+                         XFS_TRANS_DQ_BCOUNT, 1L);
        bp = xfs_btree_get_bufl(args.mp, cur->bc_tp, args.fsbno, 0);
        cblock = XFS_BUF_TO_BMBT_BLOCK(bp);
        *cblock = *block;
index 19de506c5da78b79035335146c1c1ac9d958c488..08f6da752fa7d267684e3c32aed5aed6b84b7bec 100644 (file)
 #ifndef __XFS_DMAPI_H__
 #define __XFS_DMAPI_H__
 
-#ifdef CONFIG_XFS_DMAPI
-
-#include <dmapi/dmapi.h>
-#include <dmapi/dmapi_kern.h>
-
 /*     Values used to define the on-disk version of dm_attrname_t. All
  *     on-disk attribute names start with the 8-byte string "SGI_DMI_".
  *
 #define DMATTR_PREFIXLEN       8
 #define DMATTR_PREFIXSTRING    "SGI_DMI_"
 
+typedef enum {
+       DM_EVENT_INVALID        = -1,
+       DM_EVENT_CANCEL         = 0,            /* not supported */
+       DM_EVENT_MOUNT          = 1,
+       DM_EVENT_PREUNMOUNT     = 2,
+       DM_EVENT_UNMOUNT        = 3,
+       DM_EVENT_DEBUT          = 4,            /* not supported */
+       DM_EVENT_CREATE         = 5,
+       DM_EVENT_CLOSE          = 6,            /* not supported */
+       DM_EVENT_POSTCREATE     = 7,
+       DM_EVENT_REMOVE         = 8,
+       DM_EVENT_POSTREMOVE     = 9,
+       DM_EVENT_RENAME         = 10,
+       DM_EVENT_POSTRENAME     = 11,
+       DM_EVENT_LINK           = 12,
+       DM_EVENT_POSTLINK       = 13,
+       DM_EVENT_SYMLINK        = 14,
+       DM_EVENT_POSTSYMLINK    = 15,
+       DM_EVENT_READ           = 16,
+       DM_EVENT_WRITE          = 17,
+       DM_EVENT_TRUNCATE       = 18,
+       DM_EVENT_ATTRIBUTE      = 19,
+       DM_EVENT_DESTROY        = 20,
+       DM_EVENT_NOSPACE        = 21,
+       DM_EVENT_USER           = 22,
+       DM_EVENT_MAX            = 23
+} dm_eventtype_t;
+#define HAVE_DM_EVENTTYPE_T
+
+typedef enum {
+       DM_RIGHT_NULL,
+       DM_RIGHT_SHARED,
+       DM_RIGHT_EXCL
+} dm_right_t;
+#define HAVE_DM_RIGHT_T
+
 /* Defines for determining if an event message should be sent. */
 #define DM_EVENT_ENABLED(vfsp, ip, event) ( \
        unlikely ((vfsp)->vfs_flag & VFS_DMI) && \
 #define DM_EVENT_ENABLED_IO(vfsp, io, event) ( \
        unlikely ((vfsp)->vfs_flag & VFS_DMI) && \
                ( ((io)->io_dmevmask & (1 << event)) || \
-                 ((io)->io_mount->m_dmevmask & (1 << event)) ) \
-       )
-
-/*
- *     Macros to turn caller specified delay/block flags into
- *     dm_send_xxxx_event flag DM_FLAGS_NDELAY.
- */
-
-#define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \
-                       DM_FLAGS_NDELAY : 0)
-#define AT_DELAY_FLAG(f) ((f&ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0)
-
-
-
-/* events valid in dm_set_eventlist() when called with a filesystem handle.
-   These events are not persistent.
-*/
 
 #define DM_XFS_VALID_FS_EVENTS         ( \
        (1 << DM_EVENT_PREUNMOUNT)      | \
        (1 << DM_EVENT_ATTRIBUTE)       | \
        (1 << DM_EVENT_DESTROY)         )
 
-
 /* Events supported by the XFS filesystem. */
 #define DM_XFS_SUPPORTED_EVENTS                ( \
        (1 << DM_EVENT_MOUNT)           | \
        (1 << DM_EVENT_DESTROY)         )
 
 
-extern int
-xfs_dm_get_fsys_vector(
-       bhv_desc_t      *bdp,
-       caddr_t         vecrq);
-
-extern int
-xfs_dm_send_data_event(
-       dm_eventtype_t  event,
-       bhv_desc_t      *bdp,
-       xfs_off_t       offset,
-       size_t          length,
-       int             flags,
-       vrwlock_t       *locktype);
-
-extern int
-xfs_dm_send_mmap_event(
-       struct vm_area_struct *vma,
-       unsigned int    wantflag);
-
-#else /* CONFIG_XFS_DMAPI */
-
-/*
- *     Flags needed to build with dmapi disabled.
- */
-
-typedef enum {
-       DM_EVENT_INVALID        = -1,
-       DM_EVENT_CANCEL         = 0,            /* not supported */
-       DM_EVENT_MOUNT          = 1,
-       DM_EVENT_PREUNMOUNT     = 2,
-       DM_EVENT_UNMOUNT        = 3,
-       DM_EVENT_DEBUT          = 4,            /* not supported */
-       DM_EVENT_CREATE         = 5,
-       DM_EVENT_CLOSE          = 6,            /* not supported */
-       DM_EVENT_POSTCREATE     = 7,
-       DM_EVENT_REMOVE         = 8,
-       DM_EVENT_POSTREMOVE     = 9,
-       DM_EVENT_RENAME         = 10,
-       DM_EVENT_POSTRENAME     = 11,
-       DM_EVENT_LINK           = 12,
-       DM_EVENT_POSTLINK       = 13,
-       DM_EVENT_SYMLINK        = 14,
-       DM_EVENT_POSTSYMLINK    = 15,
-       DM_EVENT_READ           = 16,
-       DM_EVENT_WRITE          = 17,
-       DM_EVENT_TRUNCATE       = 18,
-       DM_EVENT_ATTRIBUTE      = 19,
-       DM_EVENT_DESTROY        = 20,
-       DM_EVENT_NOSPACE        = 21,
-       DM_EVENT_USER           = 22,
-       DM_EVENT_MAX            = 23
-} dm_eventtype_t;
-
-typedef enum {
-       DM_RIGHT_NULL,
-       DM_RIGHT_SHARED,
-       DM_RIGHT_EXCL
-} dm_right_t;
-
-/*
- *     Defines for determining if an event message should be sent.
- */
-#define DM_EVENT_ENABLED(vfsp, ip, event)      0
-#define DM_EVENT_ENABLED_IO(vfsp, io, event)   0
-
-/*
- *     Stubbed out DMAPI delay macros.
- */
-
-#define FILP_DELAY_FLAG(filp)                  0
-#define AT_DELAY_FLAG(f)                       0
-
-/*
- *     Events supported by the XFS filesystem.
- */
-
-#define DM_XFS_VALID_FS_EVENTS                 0
-#define DM_XFS_VALID_FILE_EVENTS               0
-#define DM_XFS_VALID_DIRECTORY_EVENTS          0
-#define DM_XFS_SUPPORTED_EVENTS                        0
-
 /*
- *     Dummy definitions used for the flags field on dm_send_*_event().
+ *     Definitions used for the flags field on dm_send_*_event().
  */
 
 #define DM_FLAGS_NDELAY                0x001   /* return EAGAIN after dm_pending() */
 #define DM_FLAGS_UNWANTED      0x002   /* event not in fsys dm_eventset_t */
 
 /*
- *     Stubs for XFS DMAPI utility routines.
+ *     Macros to turn caller specified delay/block flags into
+ *     dm_send_xxxx_event flag DM_FLAGS_NDELAY.
  */
 
-static __inline int
-xfs_dm_send_data_event(
-       dm_eventtype_t  event,
-       bhv_desc_t      *bdp,
-       xfs_off_t       offset,
-       size_t          length,
-       int             flags,
-       vrwlock_t       *locktype)
-{
-       return ENOSYS;
-}
-
-static __inline int
-xfs_dm_send_mmap_event(
-       struct vm_area_struct *vma,
-       unsigned int    wantflag)
-{
-       return 0;
-}
+#define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \
+                       DM_FLAGS_NDELAY : 0)
+#define AT_DELAY_FLAG(f) ((f&ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0)
 
 /*
- *     Stubs for routines needed for the X/Open version of DMAPI.
+ *     Macros to turn caller specified delay/block flags into
+ *     dm_send_xxxx_event flag DM_FLAGS_NDELAY.
  */
 
-static __inline int
-dm_send_destroy_event(
-       bhv_desc_t      *bdp,
-       dm_right_t      vp_right)
-{
-       return ENOSYS;
-}
+#define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \
+                       DM_FLAGS_NDELAY : 0)
+
 
-static __inline int
-dm_send_namesp_event(
-       dm_eventtype_t  event,
-       bhv_desc_t      *bdp1,
-       dm_right_t      vp1_right,
-       bhv_desc_t      *bdp2,
-       dm_right_t      vp2_right,
-       char            *name1,
-       char            *name2,
-       mode_t          mode,
-       int             retcode,
-       int             flags)
-{
-       return ENOSYS;
-}
+extern struct bhv_vfsops xfs_dmops;
 
-static __inline void
-dm_send_unmount_event(
-       vfs_t           *vfsp,
-       vnode_t         *vp,
-       dm_right_t      vfsp_right,
-       mode_t          mode,
-       int             retcode,
-       int             flags)
-{
-}
+extern void xfs_dm_init(void);
+extern void xfs_dm_exit(void);
 
-#endif /* CONFIG_XFS_DMAPI */
 #endif /* __XFS_DMAPI_H__ */
index 2992261c1337b3f045f8b1001ca838063e2f5482..7448bac1e6423e7408e5a8ce95787689a15dc691 100644 (file)
  *
  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  */
-
 #include <xfs.h>
 
-#define MNTOPT_DMAPI   "dmapi"         /* DMI enabled (DMAPI / XDSM) */
-#define MNTOPT_XDSM    "xdsm"          /* DMI enabled (DMAPI / XDSM) */
-
-STATIC int
-xfs_dm_parseargs(
-       struct bhv_desc         *bhv,
-       char                    *options,
-       struct xfs_mount_args   *args,
-       int                     update)
-{
-       size_t                  length;
-       char                    *local_options = options;
-       char                    *this_char;
-       int                     error;
-
-       while ((this_char = strsep(&local_options, ",")) != NULL) {
-               length = strlen(this_char);
-               if (local_options)
-                       length++;
-
-               if (!strcmp(this_char, MNTOPT_DMAPI)) {
-                       args->flags |= XFSMNT_DMAPI;
-               } else if (!strcmp(this_char, MNTOPT_XDSM)) {
-                       args->flags |= XFSMNT_DMAPI;
-               } else {
-                       if (local_options)
-                               *(local_options-1) = ',';
-                       continue;
-               }
-
-               while (length--)
-                       *this_char++ = ',';
-       }
-
-       PVFS_PARSEARGS(BHV_NEXT(bhv), options, args, update, error);
-       if (!error && (args->flags & XFSMNT_DMAPI) && (*args->mtpt == '\0'))
-               error = EINVAL;
-       if (!error && !update && !(args->flags & XFSMNT_DMAPI))
-               bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_DM);
-       return error;
-}
-
-STATIC int
-xfs_dm_showargs(
-       struct bhv_desc         *bhv,
-       struct seq_file         *m)
-{
-       struct vfs              *vfsp = bhvtovfs(bhv);
-       int                     error;
-
-       if (vfsp->vfs_flag & VFS_DMI)
-               seq_puts(m, "," MNTOPT_DMAPI);
-
-       PVFS_SHOWARGS(BHV_NEXT(bhv), m, error);
-       return error;
-}
-
-STATIC int
-xfs_dm_mount(
-       struct bhv_desc         *bhv,
-       struct xfs_mount_args   *args,
-       struct cred             *cr)
-{
-       struct bhv_desc         *rootbdp;
-       struct vnode            *rootvp;
-       struct vfs              *vfsp;
-       int                     error = 0;
-
-       PVFS_MOUNT(BHV_NEXT(bhv), args, cr, error);
-       if (error)
-               return error;
-
-       if (args->flags & XFSMNT_DMAPI) {
-               vfsp = bhvtovfs(bhv);
-               VFS_ROOT(vfsp, &rootvp, error);
-               if (!error) {
-                       vfsp->vfs_flag |= VFS_DMI;
-                       rootbdp = vn_bhv_lookup_unlocked(
-                                       VN_BHV_HEAD(rootvp), &xfs_vnodeops);
-                       VN_RELE(rootvp);
-                       error = dm_send_mount_event(vfsp, DM_RIGHT_NULL, NULL,
-                                       DM_RIGHT_NULL, rootbdp, DM_RIGHT_NULL,
-                                       args->mtpt, args->fsname);
-               }
-       }
-
-       return error;
-}
-
-
-vfsops_t xfs_dmops_xfs = {
-       BHV_IDENTITY_INIT(VFS_BHV_DM, VFS_POSITION_DM),
-       .vfs_mount              = xfs_dm_mount,
-       .vfs_parseargs          = xfs_dm_parseargs,
-       .vfs_showargs           = xfs_dm_showargs,
-       .vfs_dmapiops           = xfs_dm_get_fsys_vector,
+#ifndef CONFIG_XFS_DMAPI
+xfs_dmops_t    xfs_dmcore_xfs = {
+       .xfs_send_data          = (xfs_send_data_t)fs_nosys,
+       .xfs_send_mmap          = (xfs_send_mmap_t)fs_noerr,
+       .xfs_send_destroy       = (xfs_send_destroy_t)fs_nosys,
+       .xfs_send_namesp        = (xfs_send_namesp_t)fs_nosys,
+       .xfs_send_unmount       = (xfs_send_unmount_t)fs_noval,
 };
+#endif /* CONFIG_XFS_DMAPI */
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
deleted file mode 100644 (file)
index 2a8c831..0000000
+++ /dev/null
@@ -1,1660 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.         Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include <xfs.h>
-#include <xfs_quota_priv.h>
-
-
-/*
-   LOCK ORDER
-
-   inode lock              (ilock)
-   dquot hash-chain lock    (hashlock)
-   xqm dquot freelist lock  (freelistlock
-   mount's dquot list lock  (mplistlock)
-   user dquot lock - lock ordering among dquots is based on the uid or gid
-   group dquot lock - similar to udquots. Between the two dquots, the udquot
-                     has to be locked first.
-   pin lock - the dquot lock must be held to take this lock.
-   flush lock - ditto.
-*/
-
-STATIC void            xfs_qm_dqflush_done(xfs_buf_t *, xfs_dq_logitem_t *);
-
-#ifdef DEBUG
-dev_t xfs_dqerror_dev = 0;
-int xfs_do_dqerror = 0;
-int xfs_dqreq_num = 0;
-int xfs_dqerror_mod = 33;
-#endif
-
-/*
- * Allocate and initialize a dquot. We don't always allocate fresh memory;
- * we try to reclaim a free dquot if the number of incore dquots are above
- * a threshold.
- * The only field inside the core that gets initialized at this point
- * is the d_id field. The idea is to fill in the entire q_core
- * when we read in the on disk dquot.
- */
-xfs_dquot_t *
-xfs_qm_dqinit(
-       xfs_mount_t  *mp,
-       xfs_dqid_t   id,
-       uint         type)
-{
-       xfs_dquot_t     *dqp;
-       boolean_t       brandnewdquot;
-
-       brandnewdquot = xfs_qm_dqalloc_incore(&dqp);
-       dqp->dq_flags = type;
-       INT_SET(dqp->q_core.d_id, ARCH_CONVERT, id);
-       dqp->q_mount = mp;
-
-       /*
-        * No need to re-initialize these if this is a reclaimed dquot.
-        */
-       if (brandnewdquot) {
-               dqp->dq_flnext = dqp->dq_flprev = dqp;
-               mutex_init(&dqp->q_qlock,  MUTEX_DEFAULT, "xdq");
-               initnsema(&dqp->q_flock, 1, "fdq");
-               sv_init(&dqp->q_pinwait, SV_DEFAULT, "pdq");
-
-#ifdef DQUOT_TRACING
-               dqp->q_trace = ktrace_alloc(DQUOT_TRACE_SIZE, KM_SLEEP);
-               xfs_dqtrace_entry(dqp, "DQINIT");
-#endif
-       } else {
-               /*
-                * Only the q_core portion was zeroed in dqreclaim_one().
-                * So, we need to reset others.
-                */
-                dqp->q_nrefs = 0;
-                dqp->q_blkno = 0;
-                dqp->MPL_NEXT = dqp->HL_NEXT = NULL;
-                dqp->HL_PREVP = dqp->MPL_PREVP = NULL;
-                dqp->q_bufoffset = 0;
-                dqp->q_fileoffset = 0;
-                dqp->q_transp = NULL;
-                dqp->q_gdquot = NULL;
-                dqp->q_res_bcount = 0;
-                dqp->q_res_icount = 0;
-                dqp->q_res_rtbcount = 0;
-                dqp->q_pincount = 0;
-                dqp->q_hash = 0;
-                ASSERT(dqp->dq_flnext == dqp->dq_flprev);
-
-#ifdef DQUOT_TRACING
-                ASSERT(dqp->q_trace);
-                xfs_dqtrace_entry(dqp, "DQRECLAIMED_INIT");
-#endif
-        }
-
-       /*
-        * log item gets initialized later
-        */
-       return (dqp);
-}
-
-/*
- * This is called to free all the memory associated with a dquot
- */
-void
-xfs_qm_dqdestroy(
-       xfs_dquot_t     *dqp)
-{
-       ASSERT(! XFS_DQ_IS_ON_FREELIST(dqp));
-
-       mutex_destroy(&dqp->q_qlock);
-       freesema(&dqp->q_flock);
-       sv_destroy(&dqp->q_pinwait);
-
-#ifdef DQUOT_TRACING
-       if (dqp->q_trace)
-            ktrace_free(dqp->q_trace);
-       dqp->q_trace = NULL;
-#endif
-       kmem_zone_free(xfs_Gqm->qm_dqzone, dqp);
-       atomic_dec(&xfs_Gqm->qm_totaldquots);
-}
-
-/*
- * This is what a 'fresh' dquot inside a dquot chunk looks like on disk.
- */
-STATIC void
-xfs_qm_dqinit_core(
-       xfs_dqid_t       id,
-       uint             type,
-       xfs_dqblk_t      *d)
-{
-       /*
-        * Caller has zero'd the entire dquot 'chunk' already.
-        */
-       INT_SET(d->dd_diskdq.d_magic, ARCH_CONVERT, XFS_DQUOT_MAGIC);
-       INT_SET(d->dd_diskdq.d_version, ARCH_CONVERT, XFS_DQUOT_VERSION);
-       INT_SET(d->dd_diskdq.d_id, ARCH_CONVERT, id);
-       INT_SET(d->dd_diskdq.d_flags, ARCH_CONVERT, type);
-}
-
-
-#ifdef DQUOT_TRACING
-/*
- * Dquot tracing for debugging.
- */
-/* ARGSUSED */
-void
-xfs_dqtrace_entry__(
-       xfs_dquot_t *dqp,
-       char *func,
-       void *retaddr,
-       xfs_inode_t *ip)
-{
-       xfs_dquot_t *udqp = NULL;
-       int ino;
-
-       ASSERT(dqp->q_trace);
-       if (ip) {
-               ino = ip->i_ino;
-               udqp = ip->i_udquot;
-       }
-       ktrace_enter(dqp->q_trace,
-                    (void *)(__psint_t)DQUOT_KTRACE_ENTRY,
-                    (void *)func,
-                    (void *)(__psint_t)dqp->q_nrefs,
-                    (void *)(__psint_t)dqp->dq_flags,
-                    (void *)(__psint_t)dqp->q_res_bcount,
-                    (void *)(__psint_t)INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT),
-                    (void *)(__psint_t)INT_GET(dqp->q_core.d_icount, ARCH_CONVERT),
-                    (void *)(__psint_t)INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT),
-                    (void *)(__psint_t)INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT),
-                    (void *)(__psint_t)INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT),
-                    (void *)(__psint_t)INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT),
-                    (void *)(__psint_t)INT_GET(dqp->q_core.d_id, ARCH_CONVERT), /* 11 */
-                    (void *)(__psint_t)current_pid(),
-                    (void *)(__psint_t)ino,
-                    (void *)(__psint_t)retaddr,
-                    (void *)(__psint_t)udqp);
-       return;
-}
-#endif
-
-
-/*
- * Check the limits and timers of a dquot and start or reset timers
- * if necessary.
- * This gets called even when quota enforcement is OFF, which makes our
- * life a little less complicated. (We just don't reject any quota
- * reservations in that case, when enforcement is off).
- * We also return 0 as the values of the timers in Q_GETQUOTA calls, when
- * enforcement's off.
- * In contrast, warnings are a little different in that they don't
- * 'automatically' get started when limits get exceeded.
- */
-void
-xfs_qm_adjust_dqtimers(
-       xfs_mount_t             *mp,
-       xfs_disk_dquot_t        *d)
-{
-       /*
-        * 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
-       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));
-       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));
-#endif
-       if (INT_ISZERO(d->d_btimer, 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_blk_hardlimit, ARCH_CONVERT) &&
-                   (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) {
-                       INT_SET(d->d_btimer, ARCH_CONVERT, get_seconds() + XFS_QI_BTIMELIMIT(mp));
-               }
-       } else {
-               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_ISZERO(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);
-               }
-       }
-
-       if (INT_ISZERO(d->d_itimer, 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_ino_hardlimit, ARCH_CONVERT) &&
-                   (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) {
-                       INT_SET(d->d_itimer, ARCH_CONVERT, get_seconds() + XFS_QI_ITIMELIMIT(mp));
-               }
-       } else {
-               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_ISZERO(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);
-               }
-       }
-}
-
-/*
- * Increment or reset warnings of a given dquot.
- */
-int
-xfs_qm_dqwarn(
-       xfs_disk_dquot_t        *d,
-       uint                    flags)
-{
-       int     warned;
-
-       /*
-        * root's limits are not real limits.
-        */
-       if (INT_ISZERO(d->d_id, ARCH_CONVERT))
-               return (0);
-
-       warned = 0;
-       if (INT_GET(d->d_blk_softlimit, ARCH_CONVERT) &&
-           (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) {
-               if (flags & XFS_QMOPT_DOWARN) {
-                       INT_MOD(d->d_bwarns, ARCH_CONVERT, +1);
-                       warned++;
-               }
-       } else {
-               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_ZERO(d->d_bwarns, ARCH_CONVERT);
-               }
-       }
-
-       if (INT_GET(d->d_ino_softlimit, ARCH_CONVERT) > 0 &&
-           (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) {
-               if (flags & XFS_QMOPT_DOWARN) {
-                       INT_MOD(d->d_iwarns, ARCH_CONVERT, +1);
-                       warned++;
-               }
-       } else {
-               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_ZERO(d->d_iwarns, ARCH_CONVERT);
-               }
-       }
-#ifdef QUOTADEBUG
-       if (INT_GET(d->d_iwarns, ARCH_CONVERT))
-               printk("--------@@Inode warnings running : %Lu >= %Lu\n",
-                      INT_GET(d->d_icount, ARCH_CONVERT), INT_GET(d->d_ino_softlimit, ARCH_CONVERT));
-       if (INT_GET(d->d_bwarns, ARCH_CONVERT))
-               printk("--------@@Blks warnings running : %Lu >= %Lu\n",
-                      INT_GET(d->d_bcount, ARCH_CONVERT), INT_GET(d->d_blk_softlimit, ARCH_CONVERT));
-#endif
-       return (warned);
-}
-
-
-/*
- * initialize a buffer full of dquots and log the whole thing
- */
-STATIC void
-xfs_qm_init_dquot_blk(
-       xfs_trans_t     *tp,
-       xfs_mount_t     *mp,
-       xfs_dqid_t      id,
-       uint            type,
-       xfs_buf_t       *bp)
-{
-       xfs_dqblk_t     *d;
-       int             curid, i;
-
-       ASSERT(tp);
-       ASSERT(XFS_BUF_ISBUSY(bp));
-       ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
-
-       d = (xfs_dqblk_t *)XFS_BUF_PTR(bp);
-
-       /*
-        * ID of the first dquot in the block - id's are zero based.
-        */
-       curid = id - (id % XFS_QM_DQPERBLK(mp));
-       ASSERT(curid >= 0);
-       memset(d, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)));
-       for (i = 0; i < XFS_QM_DQPERBLK(mp); i++, d++, curid++)
-               xfs_qm_dqinit_core(curid, type, d);
-       xfs_trans_dquot_buf(tp, bp,
-                           type & XFS_DQ_USER ?
-                           XFS_BLI_UDQUOT_BUF :
-                           XFS_BLI_GDQUOT_BUF);
-       xfs_trans_log_buf(tp, bp, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1);
-}
-
-
-
-/*
- * Allocate a block and fill it with dquots.
- * This is called when the bmapi finds a hole.
- */
-STATIC int
-xfs_qm_dqalloc(
-       xfs_trans_t     *tp,
-       xfs_mount_t     *mp,
-       xfs_dquot_t     *dqp,
-       xfs_inode_t     *quotip,
-       xfs_fileoff_t   offset_fsb,
-       xfs_buf_t       **O_bpp)
-{
-       xfs_fsblock_t   firstblock;
-       xfs_bmap_free_t flist;
-       xfs_bmbt_irec_t map;
-       int             nmaps, error, committed;
-       xfs_buf_t       *bp;
-
-       ASSERT(tp != NULL);
-       xfs_dqtrace_entry(dqp, "DQALLOC");
-
-       /*
-        * Initialize the bmap freelist prior to calling bmapi code.
-        */
-       XFS_BMAP_INIT(&flist, &firstblock);
-       xfs_ilock(quotip, XFS_ILOCK_EXCL);
-       /*
-        * Return if this type of quotas is turned off while we didn't
-        * have an inode lock
-        */
-       if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
-               xfs_iunlock(quotip, XFS_ILOCK_EXCL);
-               return (ESRCH);
-       }
-
-       /*
-        * xfs_trans_commit normally decrements the vnode ref count
-        * when it unlocks the inode. Since we want to keep the quota
-        * inode around, we bump the vnode ref count now.
-        */
-       VN_HOLD(XFS_ITOV(quotip));
-
-       xfs_trans_ijoin(tp, quotip, XFS_ILOCK_EXCL);
-       nmaps = 1;
-       if ((error = xfs_bmapi(tp, quotip,
-                             offset_fsb, XFS_DQUOT_CLUSTER_SIZE_FSB,
-                             XFS_BMAPI_METADATA | XFS_BMAPI_WRITE,
-                             &firstblock,
-                             XFS_QM_DQALLOC_SPACE_RES(mp),
-                             &map, &nmaps, &flist))) {
-               goto error0;
-       }
-       ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB);
-       ASSERT(nmaps == 1);
-       ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
-              (map.br_startblock != HOLESTARTBLOCK));
-
-       /*
-        * Keep track of the blkno to save a lookup later
-        */
-       dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock);
-
-       /* now we can just get the buffer (there's nothing to read yet) */
-       bp = xfs_trans_get_buf(tp, mp->m_ddev_targp,
-                              dqp->q_blkno,
-                              XFS_QI_DQCHUNKLEN(mp),
-                              0);
-       if (!bp || (error = XFS_BUF_GETERROR(bp)))
-               goto error1;
-       /*
-        * Make a chunk of dquots out of this buffer and log
-        * the entire thing.
-        */
-       xfs_qm_init_dquot_blk(tp, mp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT),
-                             dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP),
-                             bp);
-
-       if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) {
-               goto error1;
-       }
-
-       *O_bpp = bp;
-       return 0;
-
-      error1:
-       xfs_bmap_cancel(&flist);
-      error0:
-       xfs_iunlock(quotip, XFS_ILOCK_EXCL);
-
-       return (error);
-}
-
-/*
- * Maps a dquot to the buffer containing its on-disk version.
- * This returns a ptr to the buffer containing the on-disk dquot
- * in the bpp param, and a ptr to the on-disk dquot within that buffer
- */
-STATIC int
-xfs_qm_dqtobp(
-       xfs_trans_t             *tp,
-       xfs_dquot_t             *dqp,
-       xfs_disk_dquot_t        **O_ddpp,
-       xfs_buf_t               **O_bpp,
-       uint                    flags)
-{
-       xfs_bmbt_irec_t map;
-       int             nmaps, error;
-       xfs_buf_t       *bp;
-       xfs_inode_t     *quotip;
-       xfs_mount_t     *mp;
-       xfs_disk_dquot_t *ddq;
-       xfs_dqid_t      id;
-       boolean_t       newdquot;
-
-       mp = dqp->q_mount;
-       id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT);
-       nmaps = 1;
-       newdquot = B_FALSE;
-
-       /*
-        * If we don't know where the dquot lives, find out.
-        */
-       if (dqp->q_blkno == (xfs_daddr_t) 0) {
-               /* We use the id as an index */
-               dqp->q_fileoffset = (xfs_fileoff_t) ((uint)id /
-                                                    XFS_QM_DQPERBLK(mp));
-               nmaps = 1;
-               quotip = XFS_DQ_TO_QIP(dqp);
-               xfs_ilock(quotip, XFS_ILOCK_SHARED);
-               /*
-                * Return if this type of quotas is turned off while we didn't
-                * have an inode lock
-                */
-               if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
-                       xfs_iunlock(quotip, XFS_ILOCK_SHARED);
-                       return (ESRCH);
-               }
-               /*
-                * Find the block map; no allocations yet
-                */
-               error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset,
-                                 XFS_DQUOT_CLUSTER_SIZE_FSB,
-                                 XFS_BMAPI_METADATA,
-                                 NULL, 0, &map, &nmaps, NULL);
-
-               xfs_iunlock(quotip, XFS_ILOCK_SHARED);
-               if (error)
-                       return (error);
-               ASSERT(nmaps == 1);
-               ASSERT(map.br_blockcount == 1);
-
-               /*
-                * offset of dquot in the (fixed sized) dquot chunk.
-                */
-               dqp->q_bufoffset = (id % XFS_QM_DQPERBLK(mp)) *
-                       sizeof(xfs_dqblk_t);
-               if (map.br_startblock == HOLESTARTBLOCK) {
-                       /*
-                        * We don't allocate unless we're asked to
-                        */
-                       if (!(flags & XFS_QMOPT_DQALLOC))
-                               return (ENOENT);
-
-                       ASSERT(tp);
-                       if ((error = xfs_qm_dqalloc(tp, mp, dqp, quotip,
-                                               dqp->q_fileoffset, &bp)))
-                               return (error);
-                       newdquot = B_TRUE;
-               } else {
-                       /*
-                        * store the blkno etc so that we don't have to do the
-                        * mapping all the time
-                        */
-                       dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock);
-               }
-       }
-       ASSERT(dqp->q_blkno != DELAYSTARTBLOCK);
-       ASSERT(dqp->q_blkno != HOLESTARTBLOCK);
-
-       /*
-        * Read in the buffer, unless we've just done the allocation
-        * (in which case we already have the buf).
-        */
-       if (! newdquot) {
-               xfs_dqtrace_entry(dqp, "DQTOBP READBUF");
-               if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
-                                              dqp->q_blkno,
-                                              XFS_QI_DQCHUNKLEN(mp),
-                                              0, &bp))) {
-                       return (error);
-               }
-               if (error || !bp)
-                       return XFS_ERROR(error);
-       }
-       ASSERT(XFS_BUF_ISBUSY(bp));
-       ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
-
-       /*
-        * calculate the location of the dquot inside the buffer.
-        */
-       ddq = (xfs_disk_dquot_t *)((char *)XFS_BUF_PTR(bp) + dqp->q_bufoffset);
-
-       /*
-        * A simple sanity check in case we got a corrupted dquot...
-        */
-       if (xfs_qm_dqcheck(ddq, id,
-                          dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP),
-                          flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN),
-                          "dqtobp")) {
-               if (!(flags & XFS_QMOPT_DQREPAIR)) {
-                       xfs_trans_brelse(tp, bp);
-                       return XFS_ERROR(EIO);
-               }
-               XFS_BUF_BUSY(bp); /* We dirtied this */
-       }
-
-       *O_bpp = bp;
-       *O_ddpp = ddq;
-
-       return (0);
-}
-
-
-/*
- * Read in the ondisk dquot using dqtobp() then copy it to an incore version,
- * and release the buffer immediately.
- *
- */
-/* ARGSUSED */
-STATIC int
-xfs_qm_dqread(
-       xfs_trans_t     *tp,
-       xfs_dqid_t      id,
-       xfs_dquot_t     *dqp,   /* dquot to get filled in */
-       uint            flags)
-{
-       xfs_disk_dquot_t *ddqp;
-       xfs_buf_t        *bp;
-       int              error;
-
-       /*
-        * get a pointer to the on-disk dquot and the buffer containing it
-        * dqp already knows its own type (GROUP/USER).
-        */
-       xfs_dqtrace_entry(dqp, "DQREAD");
-       if ((error = xfs_qm_dqtobp(tp, dqp, &ddqp, &bp, flags))) {
-               return (error);
-       }
-
-       /* copy everything from disk dquot to the incore dquot */
-       memcpy(&dqp->q_core, ddqp, sizeof(xfs_disk_dquot_t));
-       ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id);
-       xfs_qm_dquot_logitem_init(dqp);
-
-       /*
-        * Reservation counters are defined as reservation plus current usage
-        * to avoid having to add everytime.
-        */
-       dqp->q_res_bcount = INT_GET(ddqp->d_bcount, ARCH_CONVERT);
-       dqp->q_res_icount = INT_GET(ddqp->d_icount, ARCH_CONVERT);
-       dqp->q_res_rtbcount = INT_GET(ddqp->d_rtbcount, ARCH_CONVERT);
-
-       /* Mark the buf so that this will stay incore a little longer */
-       XFS_BUF_SET_VTYPE_REF(bp, B_FS_DQUOT, XFS_DQUOT_REF);
-
-       /*
-        * We got the buffer with a xfs_trans_read_buf() (in dqtobp())
-        * So we need to release with xfs_trans_brelse().
-        * The strategy here is identical to that of inodes; we lock
-        * the dquot in xfs_qm_dqget() before making it accessible to
-        * others. This is because dquots, like inodes, need a good level of
-        * concurrency, and we don't want to take locks on the entire buffers
-        * for dquot accesses.
-        * Note also that the dquot buffer may even be dirty at this point, if
-        * this particular dquot was repaired. We still aren't afraid to
-        * brelse it because we have the changes incore.
-        */
-       ASSERT(XFS_BUF_ISBUSY(bp));
-       ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
-       xfs_trans_brelse(tp, bp);
-
-       return (error);
-}
-
-
-/*
- * allocate an incore dquot from the kernel heap,
- * and fill its core with quota information kept on disk.
- * If XFS_QMOPT_DQALLOC is set, it'll allocate a dquot on disk
- * if it wasn't already allocated.
- */
-STATIC int
-xfs_qm_idtodq(
-       xfs_mount_t     *mp,
-       xfs_dqid_t      id,      /* gid or uid, depending on type */
-       uint            type,    /* UDQUOT or GDQUOT */
-       uint            flags,   /* DQALLOC, DQREPAIR */
-       xfs_dquot_t     **O_dqpp)/* OUT : incore dquot, not locked */
-{
-       xfs_dquot_t     *dqp;
-       int             error;
-       xfs_trans_t     *tp;
-       int             cancelflags=0;
-
-       dqp = xfs_qm_dqinit(mp, id, type);
-       tp = NULL;
-       if (flags & XFS_QMOPT_DQALLOC) {
-               tp = xfs_trans_alloc(mp, XFS_TRANS_QM_DQALLOC);
-               if ((error = xfs_trans_reserve(tp,
-                                      XFS_QM_DQALLOC_SPACE_RES(mp),
-                                      XFS_WRITE_LOG_RES(mp) +
-                                             BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1 +
-                                             128,
-                                      0,
-                                      XFS_TRANS_PERM_LOG_RES,
-                                      XFS_WRITE_LOG_COUNT))) {
-                       cancelflags = 0;
-                       goto error0;
-               }
-               cancelflags = XFS_TRANS_RELEASE_LOG_RES;
-       }
-
-       /*
-        * Read it from disk; xfs_dqread() takes care of
-        * all the necessary initialization of dquot's fields (locks, etc)
-        */
-       if ((error = xfs_qm_dqread(tp, id, dqp, flags))) {
-               /*
-                * This can happen if quotas got turned off (ESRCH),
-                * or if the dquot didn't exist on disk and we ask to
-                * allocate (ENOENT).
-                */
-               xfs_dqtrace_entry(dqp, "DQREAD FAIL");
-               cancelflags |= XFS_TRANS_ABORT;
-               goto error0;
-       }
-       if (tp) {
-               if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
-                                            NULL)))
-                       goto error1;
-       }
-
-       *O_dqpp = dqp;
-       ASSERT(! XFS_DQ_IS_LOCKED(dqp));
-       return (0);
-
- error0:
-       ASSERT(error);
-       if (tp)
-               xfs_trans_cancel(tp, cancelflags);
- error1:
-       xfs_qm_dqdestroy(dqp);
-       *O_dqpp = NULL;
-       return (error);
-}
-
-/*
- * Lookup a dquot in the incore dquot hashtable. We keep two separate
- * hashtables for user and group dquots; and, these are global tables
- * inside the XQM, not per-filesystem tables.
- * The hash chain must be locked by caller, and it is left locked
- * on return. Returning dquot is locked.
- */
-STATIC int
-xfs_qm_dqlookup(
-       xfs_mount_t             *mp,
-       xfs_dqid_t              id,
-       xfs_dqhash_t            *qh,
-       xfs_dquot_t             **O_dqpp)
-{
-       xfs_dquot_t             *dqp;
-       uint                    flist_locked;
-       xfs_dquot_t             *d;
-
-       ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
-
-       flist_locked = B_FALSE;
-
-       /*
-        * Traverse the hashchain looking for a match
-        */
-       for (dqp = qh->qh_next; dqp != NULL; dqp = dqp->HL_NEXT) {
-               /*
-                * We already have the hashlock. We don't need the
-                * dqlock to look at the id field of the dquot, since the
-                * id can't be modified without the hashlock anyway.
-                */
-               if (INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id && dqp->q_mount == mp) {
-                       xfs_dqtrace_entry(dqp, "DQFOUND BY LOOKUP");
-                       /*
-                        * All in core dquots must be on the dqlist of mp
-                        */
-                       ASSERT(dqp->MPL_PREVP != NULL);
-
-                       xfs_dqlock(dqp);
-                       if (dqp->q_nrefs == 0) {
-                               ASSERT (XFS_DQ_IS_ON_FREELIST(dqp));
-                               if (! xfs_qm_freelist_lock_nowait(xfs_Gqm)) {
-                                       xfs_dqtrace_entry(dqp, "DQLOOKUP: WANT");
-
-                                       /*
-                                        * We may have raced with dqreclaim_one()
-                                        * (and lost). So, flag that we don't
-                                        * want the dquot to be reclaimed.
-                                        */
-                                       dqp->dq_flags |= XFS_DQ_WANT;
-                                       xfs_dqunlock(dqp);
-                                       xfs_qm_freelist_lock(xfs_Gqm);
-                                       xfs_dqlock(dqp);
-                                       dqp->dq_flags &= ~(XFS_DQ_WANT);
-                               }
-                               flist_locked = B_TRUE;
-                       }
-
-                       /*
-                        * id couldn't have changed; we had the hashlock all
-                        * along
-                        */
-                       ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id);
-
-                       if (flist_locked) {
-                               if (dqp->q_nrefs != 0) {
-                                       xfs_qm_freelist_unlock(xfs_Gqm);
-                                       flist_locked = B_FALSE;
-                               } else {
-                                       /*
-                                        * take it off the freelist
-                                        */
-                                       xfs_dqtrace_entry(dqp,
-                                                       "DQLOOKUP: TAKEOFF FL");
-                                       XQM_FREELIST_REMOVE(dqp);
-                                       /* xfs_qm_freelist_print(&(xfs_Gqm->
-                                                       qm_dqfreelist),
-                                                       "after removal"); */
-                               }
-                       }
-
-                       /*
-                        * grab a reference
-                        */
-                       XFS_DQHOLD(dqp);
-
-                       if (flist_locked)
-                               xfs_qm_freelist_unlock(xfs_Gqm);
-                       /*
-                        * move the dquot to the front of the hashchain
-                        */
-                       ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
-                       if (dqp->HL_PREVP != &qh->qh_next) {
-                               xfs_dqtrace_entry(dqp,
-                                                 "DQLOOKUP: HASH MOVETOFRONT");
-                               if ((d = dqp->HL_NEXT))
-                                       d->HL_PREVP = dqp->HL_PREVP;
-                               *(dqp->HL_PREVP) = d;
-                               d = qh->qh_next;
-                               d->HL_PREVP = &dqp->HL_NEXT;
-                               dqp->HL_NEXT = d;
-                               dqp->HL_PREVP = &qh->qh_next;
-                               qh->qh_next = dqp;
-                       }
-                       xfs_dqtrace_entry(dqp, "LOOKUP END");
-                       *O_dqpp = dqp;
-                       ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
-                       return (0);
-               }
-       }
-
-       *O_dqpp = NULL;
-       ASSERT(XFS_DQ_IS_HASH_LOCKED(qh));
-       return (1);
-}
-
-/*
- * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a
- * a locked dquot, doing an allocation (if requested) as needed.
- * When both an inode and an id are given, the inode's id takes precedence.
- * That is, if the id changes while we don't hold the ilock inside this
- * function, the new dquot is returned, not necessarily the one requested
- * in the id argument.
- */
-int
-xfs_qm_dqget(
-       xfs_mount_t     *mp,
-       xfs_inode_t     *ip,      /* locked inode (optional) */
-       xfs_dqid_t      id,       /* gid or uid, depending on type */
-       uint            type,     /* UDQUOT or GDQUOT */
-       uint            flags,    /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */
-       xfs_dquot_t     **O_dqpp) /* OUT : locked incore dquot */
-{
-       xfs_dquot_t     *dqp;
-       xfs_dqhash_t    *h;
-       uint            version;
-       int             error;
-
-       ASSERT(XFS_IS_QUOTA_RUNNING(mp));
-       if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) ||
-           (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) {
-               return (ESRCH);
-       }
-       h = XFS_DQ_HASH(mp, id, type);
-
-#ifdef DEBUG
-       if (xfs_do_dqerror) {
-               if ((xfs_dqerror_dev == mp->m_dev) &&
-                   (xfs_dqreq_num++ % xfs_dqerror_mod) == 0) {
-                       printk("Returning error in dqget\n");
-                       return (EIO);
-               }
-       }
-#endif
-
- again:
-
-#ifdef DEBUG
-       ASSERT(type == XFS_DQ_USER || type == XFS_DQ_GROUP);
-       if (ip) {
-               ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-               if (type == XFS_DQ_USER)
-                       ASSERT(ip->i_udquot == NULL);
-               else
-                       ASSERT(ip->i_gdquot == NULL);
-       }
-#endif
-       XFS_DQ_HASH_LOCK(h);
-
-       /*
-        * Look in the cache (hashtable).
-        * The chain is kept locked during lookup.
-        */
-       if (xfs_qm_dqlookup(mp, id, h, O_dqpp) == 0) {
-               XFS_STATS_INC(xfsstats.xs_qm_dqcachehits);
-               /*
-                * The dquot was found, moved to the front of the chain,
-                * taken off the freelist if it was on it, and locked
-                * at this point. Just unlock the hashchain and return.
-                */
-               ASSERT(*O_dqpp);
-               ASSERT(XFS_DQ_IS_LOCKED(*O_dqpp));
-               XFS_DQ_HASH_UNLOCK(h);
-               xfs_dqtrace_entry(*O_dqpp, "DQGET DONE (FROM CACHE)");
-               return (0);     /* success */
-       }
-       XFS_STATS_INC(xfsstats.xs_qm_dqcachemisses);
-
-       /*
-        * Dquot cache miss. We don't want to keep the inode lock across
-        * a (potential) disk read. Also we don't want to deal with the lock
-        * ordering between quotainode and this inode. OTOH, dropping the inode
-        * lock here means dealing with a chown that can happen before
-        * we re-acquire the lock.
-        */
-       if (ip)
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       /*
-        * Save the hashchain version stamp, and unlock the chain, so that
-        * we don't keep the lock across a disk read
-        */
-       version = h->qh_version;
-       XFS_DQ_HASH_UNLOCK(h);
-
-       /*
-        * Allocate the dquot on the kernel heap, and read the ondisk
-        * portion off the disk. Also, do all the necessary initialization
-        * This can return ENOENT if dquot didn't exist on disk and we didn't
-        * ask it to allocate; ESRCH if quotas got turned off suddenly.
-        */
-       if ((error = xfs_qm_idtodq(mp, id, type,
-                                 flags & (XFS_QMOPT_DQALLOC|XFS_QMOPT_DQREPAIR|
-                                          XFS_QMOPT_DOWARN),
-                                 &dqp))) {
-               if (ip)
-                       xfs_ilock(ip, XFS_ILOCK_EXCL);
-               return (error);
-       }
-
-       /*
-        * See if this is mount code calling to look at the overall quota limits
-        * which are stored in the id == 0 user or group's dquot.
-        * Since we may not have done a quotacheck by this point, just return
-        * the dquot without attaching it to any hashtables, lists, etc, or even
-        * taking a reference.
-        * The caller must dqdestroy this once done.
-        */
-       if (flags & XFS_QMOPT_DQSUSER) {
-               ASSERT(id == 0);
-               ASSERT(! ip);
-               goto dqret;
-       }
-
-       /*
-        * Dquot lock comes after hashlock in the lock ordering
-        */
-       ASSERT(! XFS_DQ_IS_LOCKED(dqp));
-       if (ip) {
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               if (! XFS_IS_DQTYPE_ON(mp, type)) {
-                       /* inode stays locked on return */
-                       xfs_qm_dqdestroy(dqp);
-                       return XFS_ERROR(ESRCH);
-               }
-               /*
-                * A dquot could be attached to this inode by now, since
-                * we had dropped the ilock.
-                */
-               if (type == XFS_DQ_USER) {
-                       if (ip->i_udquot) {
-                               xfs_qm_dqdestroy(dqp);
-                               dqp = ip->i_udquot;
-                               xfs_dqlock(dqp);
-                               goto dqret;
-                       }
-               } else {
-                       if (ip->i_gdquot) {
-                               xfs_qm_dqdestroy(dqp);
-                               dqp = ip->i_gdquot;
-                               xfs_dqlock(dqp);
-                               goto dqret;
-                       }
-               }
-       }
-
-       /*
-        * Hashlock comes after ilock in lock order
-        */
-       XFS_DQ_HASH_LOCK(h);
-       if (version != h->qh_version) {
-               xfs_dquot_t *tmpdqp;
-               /*
-                * Now, see if somebody else put the dquot in the
-                * hashtable before us. This can happen because we didn't
-                * keep the hashchain lock. We don't have to worry about
-                * lock order between the two dquots here since dqp isn't
-                * on any findable lists yet.
-                */
-               if (xfs_qm_dqlookup(mp, id, h, &tmpdqp) == 0) {
-                       /*
-                        * Duplicate found. Just throw away the new dquot
-                        * and start over.
-                        */
-                       xfs_qm_dqput(tmpdqp);
-                       XFS_DQ_HASH_UNLOCK(h);
-                       xfs_qm_dqdestroy(dqp);
-                       XFS_STATS_INC(xfsstats.xs_qm_dquot_dups);
-                       goto again;
-               }
-       }
-
-       /*
-        * Put the dquot at the beginning of the hash-chain and mp's list
-        * LOCK ORDER: hashlock, freelistlock, mplistlock, udqlock, gdqlock ..
-        */
-       ASSERT(XFS_DQ_IS_HASH_LOCKED(h));
-       dqp->q_hash = h;
-       XQM_HASHLIST_INSERT(h, dqp);
-
-       /*
-        * Attach this dquot to this filesystem's list of all dquots,
-        * kept inside the mount structure in m_quotainfo field
-        */
-       xfs_qm_mplist_lock(mp);
-
-       /*
-        * We return a locked dquot to the caller, with a reference taken
-        */
-       xfs_dqlock(dqp);
-       dqp->q_nrefs = 1;
-
-       XQM_MPLIST_INSERT(&(XFS_QI_MPL_LIST(mp)), dqp);
-
-       xfs_qm_mplist_unlock(mp);
-       XFS_DQ_HASH_UNLOCK(h);
- dqret:
-       ASSERT((ip == NULL) || XFS_ISLOCKED_INODE_EXCL(ip));
-       xfs_dqtrace_entry(dqp, "DQGET DONE");
-       *O_dqpp = dqp;
-       return (0);
-}
-
-
-/*
- * Release a reference to the dquot (decrement ref-count)
- * and unlock it. If there is a group quota attached to this
- * dquot, carefully release that too without tripping over
- * deadlocks'n'stuff.
- */
-void
-xfs_qm_dqput(
-       xfs_dquot_t     *dqp)
-{
-       xfs_dquot_t     *gdqp;
-
-       ASSERT(dqp->q_nrefs > 0);
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-       xfs_dqtrace_entry(dqp, "DQPUT");
-
-       if (dqp->q_nrefs != 1) {
-               dqp->q_nrefs--;
-               xfs_dqunlock(dqp);
-               return;
-       }
-
-       /*
-        * drop the dqlock and acquire the freelist and dqlock
-        * in the right order; but try to get it out-of-order first
-        */
-       if (! xfs_qm_freelist_lock_nowait(xfs_Gqm)) {
-               xfs_dqtrace_entry(dqp, "DQPUT: FLLOCK-WAIT");
-               xfs_dqunlock(dqp);
-               xfs_qm_freelist_lock(xfs_Gqm);
-               xfs_dqlock(dqp);
-       }
-
-       while (1) {
-               gdqp = NULL;
-
-               /* We can't depend on nrefs being == 1 here */
-               if (--dqp->q_nrefs == 0) {
-                       xfs_dqtrace_entry(dqp, "DQPUT: ON FREELIST");
-                       /*
-                        * insert at end of the freelist.
-                        */
-                       XQM_FREELIST_INSERT(&(xfs_Gqm->qm_dqfreelist), dqp);
-
-                       /*
-                        * If we just added a udquot to the freelist, then
-                        * we want to release the gdquot reference that
-                        * it (probably) has. Otherwise it'll keep the
-                        * gdquot from getting reclaimed.
-                        */
-                       if ((gdqp = dqp->q_gdquot)) {
-                               /*
-                                * Avoid a recursive dqput call
-                                */
-                               xfs_dqlock(gdqp);
-                               dqp->q_gdquot = NULL;
-                       }
-
-                       /* xfs_qm_freelist_print(&(xfs_Gqm->qm_dqfreelist),
-                          "@@@@@++ Free list (after append) @@@@@+");
-                          */
-               }
-               xfs_dqunlock(dqp);
-
-               /*
-                * If we had a group quota inside the user quota as a hint,
-                * release it now.
-                */
-               if (! gdqp)
-                       break;
-               dqp = gdqp;
-       }
-       xfs_qm_freelist_unlock(xfs_Gqm);
-}
-
-/*
- * Release a dquot. Flush it if dirty, then dqput() it.
- * dquot must not be locked.
- */
-void
-xfs_qm_dqrele(
-       xfs_dquot_t     *dqp)
-{
-       ASSERT(dqp);
-       xfs_dqtrace_entry(dqp, "DQRELE");
-
-       xfs_dqlock(dqp);
-       /*
-        * We don't care to flush it if the dquot is dirty here.
-        * That will create stutters that we want to avoid.
-        * Instead we do a delayed write when we try to reclaim
-        * a dirty dquot. Also xfs_sync will take part of the burden...
-        */
-       xfs_qm_dqput(dqp);
-}
-
-
-/*
- * Write a modified dquot to disk.
- * The dquot must be locked and the flush lock too taken by caller.
- * The flush lock will not be unlocked until the dquot reaches the disk,
- * but the dquot is free to be unlocked and modified by the caller
- * in the interim. Dquot is still locked on return. This behavior is
- * identical to that of inodes.
- */
-int
-xfs_qm_dqflush(
-       xfs_dquot_t             *dqp,
-       uint                    flags)
-{
-       xfs_mount_t             *mp;
-       xfs_buf_t               *bp;
-       xfs_disk_dquot_t        *ddqp;
-       int                     error;
-       SPLDECL(s);
-
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-       ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp));
-       xfs_dqtrace_entry(dqp, "DQFLUSH");
-
-       /*
-        * If not dirty, nada.
-        */
-       if (!XFS_DQ_IS_DIRTY(dqp)) {
-               xfs_dqfunlock(dqp);
-               return (0);
-       }
-
-       /*
-        * Cant flush a pinned dquot. Wait for it.
-        */
-       xfs_qm_dqunpin_wait(dqp);
-
-       /*
-        * This may have been unpinned because the filesystem is shutting
-        * down forcibly. If that's the case we must not write this dquot
-        * to disk, because the log record didn't make it to disk!
-        */
-       if (XFS_FORCED_SHUTDOWN(dqp->q_mount)) {
-               dqp->dq_flags &= ~(XFS_DQ_DIRTY);
-               xfs_dqfunlock(dqp);
-               return XFS_ERROR(EIO);
-       }
-
-       /*
-        * Get the buffer containing the on-disk dquot
-        * We don't need a transaction envelope because we know that the
-        * the ondisk-dquot has already been allocated for.
-        */
-       if ((error = xfs_qm_dqtobp(NULL, dqp, &ddqp, &bp, XFS_QMOPT_DOWARN))) {
-               xfs_dqtrace_entry(dqp, "DQTOBP FAIL");
-               ASSERT(error != ENOENT);
-               /*
-                * Quotas could have gotten turned off (ESRCH)
-                */
-               xfs_dqfunlock(dqp);
-               return (error);
-       }
-
-       if (xfs_qm_dqcheck(&dqp->q_core, INT_GET(ddqp->d_id, ARCH_CONVERT), 0, XFS_QMOPT_DOWARN,
-                          "dqflush (incore copy)")) {
-               xfs_force_shutdown(dqp->q_mount, XFS_CORRUPT_INCORE);
-               return XFS_ERROR(EIO);
-       }
-
-       /* This is the only portion of data that needs to persist */
-       memcpy(ddqp, &(dqp->q_core), sizeof(xfs_disk_dquot_t));
-
-       /*
-        * Clear the dirty field and remember the flush lsn for later use.
-        */
-       dqp->dq_flags &= ~(XFS_DQ_DIRTY);
-       mp = dqp->q_mount;
-
-       /* lsn is 64 bits */
-       AIL_LOCK(mp, s);
-       dqp->q_logitem.qli_flush_lsn = dqp->q_logitem.qli_item.li_lsn;
-       AIL_UNLOCK(mp, s);
-
-       /*
-        * Attach an iodone routine so that we can remove this dquot from the
-        * AIL and release the flush lock once the dquot is synced to disk.
-        */
-       xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t *, xfs_log_item_t *))
-                             xfs_qm_dqflush_done, &(dqp->q_logitem.qli_item));
-       /*
-        * If the buffer is pinned then push on the log so we won't
-        * get stuck waiting in the write for too long.
-        */
-       if (XFS_BUF_ISPINNED(bp)) {
-               xfs_dqtrace_entry(dqp, "DQFLUSH LOG FORCE");
-               xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE);
-       }
-
-       if (flags & XFS_QMOPT_DELWRI) {
-               xfs_bdwrite(mp, bp);
-       } else if (flags & XFS_QMOPT_ASYNC) {
-               xfs_bawrite(mp, bp);
-       } else {
-               error = xfs_bwrite(mp, bp);
-       }
-       xfs_dqtrace_entry(dqp, "DQFLUSH END");
-       /*
-        * dqp is still locked, but caller is free to unlock it now.
-        */
-       return (error);
-
-}
-
-/*
- * This is the dquot flushing I/O completion routine.  It is called
- * from interrupt level when the buffer containing the dquot is
- * flushed to disk.  It is responsible for removing the dquot logitem
- * from the AIL if it has not been re-logged, and unlocking the dquot's
- * flush lock. This behavior is very similar to that of inodes..
- */
-/*ARGSUSED*/
-STATIC void
-xfs_qm_dqflush_done(
-       xfs_buf_t               *bp,
-       xfs_dq_logitem_t        *qip)
-{
-       xfs_dquot_t             *dqp;
-       SPLDECL(s);
-
-       dqp = qip->qli_dquot;
-
-       /*
-        * We only want to pull the item from the AIL if its
-        * location in the log has not changed since we started the flush.
-        * Thus, we only bother if the dquot's lsn has
-        * not changed. First we check the lsn outside the lock
-        * since it's cheaper, and then we recheck while
-        * holding the lock before removing the dquot from the AIL.
-        */
-       if ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
-           qip->qli_item.li_lsn == qip->qli_flush_lsn) {
-
-               AIL_LOCK(dqp->q_mount, s);
-               /*
-                * xfs_trans_delete_ail() drops the AIL lock.
-                */
-               if (qip->qli_item.li_lsn == qip->qli_flush_lsn)
-                       xfs_trans_delete_ail(dqp->q_mount,
-                                            (xfs_log_item_t*)qip, s);
-               else
-                       AIL_UNLOCK(dqp->q_mount, s);
-       }
-
-       /*
-        * Release the dq's flush lock since we're done with it.
-        */
-       xfs_dqfunlock(dqp);
-}
-
-
-int
-xfs_qm_dqflock_nowait(
-       xfs_dquot_t *dqp)
-{
-       int locked;
-
-       locked = cpsema(&((dqp)->q_flock));
-
-       /* XXX ifdef these out */
-       if (locked)
-               (dqp)->dq_flags |= XFS_DQ_FLOCKED;
-       return (locked);
-}
-
-
-int
-xfs_qm_dqlock_nowait(
-       xfs_dquot_t *dqp)
-{
-       return (mutex_trylock(&((dqp)->q_qlock)));
-}
-
-void
-xfs_dqlock(
-       xfs_dquot_t *dqp)
-{
-       mutex_lock(&(dqp->q_qlock), PINOD);
-}
-
-void
-xfs_dqunlock(
-       xfs_dquot_t *dqp)
-{
-       mutex_unlock(&(dqp->q_qlock));
-       if (dqp->q_logitem.qli_dquot == dqp) {
-               /* Once was dqp->q_mount, but might just have been cleared */
-               xfs_trans_unlocked_item(dqp->q_logitem.qli_item.li_mountp,
-                                       (xfs_log_item_t*)&(dqp->q_logitem));
-       }
-}
-
-
-void
-xfs_dqunlock_nonotify(
-       xfs_dquot_t *dqp)
-{
-       mutex_unlock(&(dqp->q_qlock));
-}
-
-void
-xfs_dqlock2(
-       xfs_dquot_t     *d1,
-       xfs_dquot_t     *d2)
-{
-       if (d1 && d2) {
-               ASSERT(d1 != d2);
-               if (INT_GET(d1->q_core.d_id, ARCH_CONVERT) > INT_GET(d2->q_core.d_id, ARCH_CONVERT)) {
-                       xfs_dqlock(d2);
-                       xfs_dqlock(d1);
-               } else {
-                       xfs_dqlock(d1);
-                       xfs_dqlock(d2);
-               }
-       } else {
-               if (d1) {
-                       xfs_dqlock(d1);
-               } else if (d2) {
-                       xfs_dqlock(d2);
-               }
-       }
-}
-
-
-/*
- * A rarely used accessor. This exists because we don't really want
- * to expose the internals of a dquot to the outside world.
- */
-xfs_dqid_t
-xfs_qm_dqid(
-       xfs_dquot_t     *dqp)
-{
-       return (INT_GET(dqp->q_core.d_id, ARCH_CONVERT));
-}
-
-
-/*
- * Take a dquot out of the mount's dqlist as well as the hashlist.
- * This is called via unmount as well as quotaoff, and the purge
- * will always succeed unless there are soft (temp) references
- * outstanding.
- *
- * This returns 0 if it was purged, 1 if it wasn't. It's not an error code
- * that we're returning! XXXsup - not cool.
- */
-/* ARGSUSED */
-int
-xfs_qm_dqpurge(
-       xfs_dquot_t     *dqp,
-       uint            flags)
-{
-       xfs_dqhash_t    *thishash;
-       xfs_mount_t     *mp;
-
-       mp = dqp->q_mount;
-
-       ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
-       ASSERT(XFS_DQ_IS_HASH_LOCKED(dqp->q_hash));
-
-       xfs_dqlock(dqp);
-       /*
-        * We really can't afford to purge a dquot that is
-        * referenced, because these are hard refs.
-        * It shouldn't happen in general because we went thru _all_ inodes in
-        * dqrele_all_inodes before calling this and didn't let the mountlock go.
-        * However it is possible that we have dquots with temporary
-        * references that are not attached to an inode. e.g. see xfs_setattr().
-        */
-       if (dqp->q_nrefs != 0) {
-               xfs_dqunlock(dqp);
-               XFS_DQ_HASH_UNLOCK(dqp->q_hash);
-               return (1);
-       }
-
-       ASSERT(XFS_DQ_IS_ON_FREELIST(dqp));
-
-       /*
-        * If we're turning off quotas, we have to make sure that, for
-        * example, we don't delete quota disk blocks while dquots are
-        * in the process of getting written to those disk blocks.
-        * This dquot might well be on AIL, and we can't leave it there
-        * if we're turning off quotas. Basically, we need this flush
-        * lock, and are willing to block on it.
-        */
-       if (! xfs_qm_dqflock_nowait(dqp)) {
-               /*
-                * Block on the flush lock after nudging dquot buffer,
-                * if it is incore.
-                */
-               xfs_qm_dqflock_pushbuf_wait(dqp);
-       }
-
-       /*
-        * XXXIf we're turning this type of quotas off, we don't care
-        * about the dirty metadata sitting in this dquot. OTOH, if
-        * we're unmounting, we do care, so we flush it and wait.
-        */
-       if (XFS_DQ_IS_DIRTY(dqp)) {
-               xfs_dqtrace_entry(dqp, "DQPURGE ->DQFLUSH: DQDIRTY");
-               /* dqflush unlocks dqflock */
-               /*
-                * Given that dqpurge is a very rare occurrence, it is OK
-                * that we're holding the hashlist and mplist locks
-                * across the disk write. But, ... XXXsup
-                *
-                * We don't care about getting disk errors here. We need
-                * to purge this dquot anyway, so we go ahead regardless.
-                */
-               (void) xfs_qm_dqflush(dqp, XFS_QMOPT_SYNC);
-               xfs_dqflock(dqp);
-       }
-       ASSERT(dqp->q_pincount == 0);
-       ASSERT(XFS_FORCED_SHUTDOWN(mp) ||
-              !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL));
-
-       thishash = dqp->q_hash;
-       XQM_HASHLIST_REMOVE(thishash, dqp);
-       XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(mp)), dqp);
-       /*
-        * XXX Move this to the front of the freelist, if we can get the
-        * freelist lock.
-        */
-       ASSERT(XFS_DQ_IS_ON_FREELIST(dqp));
-
-       dqp->q_mount = NULL;;
-       dqp->q_hash = NULL;
-       dqp->dq_flags = XFS_DQ_INACTIVE;
-       memset(&dqp->q_core, 0, sizeof(dqp->q_core));
-       xfs_dqfunlock(dqp);
-       xfs_dqunlock(dqp);
-       XFS_DQ_HASH_UNLOCK(thishash);
-       return (0);
-}
-
-
-/*
- * Do some primitive error checking on ondisk dquot
- * data structures. Not just for debugging, actually;
- * this can be useful for detecting data corruption mainly due to
- * disk failures.
- */
-/* ARGSUSED */
-int
-xfs_qm_dqcheck(
-       xfs_disk_dquot_t *ddq,
-       xfs_dqid_t       id,
-       uint             type,    /* used only when IO_dorepair is true */
-       uint             flags,
-       char             *str)
-{
-       int errs;
-
-       errs = 0;
-       /* ASSERT(flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN)); */
-       /*
-        * We can encounter an uninitialized dquot buffer for 2 reasons:
-        * 1. If we crash while deleting the quotainode(s), and those blks get used
-        *    for some user data. This is because we take the path of regular
-        *    file deletion; however, the size field of quotainodes is never
-        *    updated, so all the tricks that we play in itruncate_finish
-        *    don't quite matter.
-        *
-        * 2. We don't play the quota buffers when there's a quotaoff logitem.
-        *    But the allocation will be replayed so we'll end up with an
-        *    uninitialized quota block.
-        *
-        * This is all fine; things are still consistent, and we haven't lost
-        * any quota information. Just don't complain about bad dquot blks.
-        */
-       if (INT_GET(ddq->d_magic, ARCH_CONVERT) != XFS_DQUOT_MAGIC) {
-               if (flags & XFS_QMOPT_DOWARN)
-                       cmn_err(CE_ALERT,
-                       "%s : XFS dquot ID 0x%x, magic 0x%x != 0x%x",
-                       str, id, INT_GET(ddq->d_magic, ARCH_CONVERT), XFS_DQUOT_MAGIC);
-               errs++;
-       }
-       if (INT_GET(ddq->d_version, ARCH_CONVERT) != XFS_DQUOT_VERSION) {
-               if (flags & XFS_QMOPT_DOWARN)
-                       cmn_err(CE_ALERT,
-                       "%s : XFS dquot ID 0x%x, version 0x%x != 0x%x",
-                       str, id, INT_GET(ddq->d_magic, ARCH_CONVERT), XFS_DQUOT_VERSION);
-               errs++;
-       }
-
-       if (INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_USER && INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_GROUP) {
-               if (flags & XFS_QMOPT_DOWARN)
-                       cmn_err(CE_ALERT,
-                       "%s : XFS dquot ID 0x%x, unknown flags 0x%x",
-                       str, id, INT_GET(ddq->d_flags, ARCH_CONVERT));
-               errs++;
-       }
-
-       if (id != -1 && id != INT_GET(ddq->d_id, ARCH_CONVERT)) {
-               if (flags & XFS_QMOPT_DOWARN)
-                       cmn_err(CE_ALERT,
-                       "%s : ondisk-dquot 0x%x, ID mismatch: "
-                       "0x%x expected, found id 0x%x",
-                       str, ddq, id, INT_GET(ddq->d_id, ARCH_CONVERT));
-               errs++;
-       }
-
-       if (! errs) {
-               if (INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT) &&
-                   INT_GET(ddq->d_bcount, ARCH_CONVERT) >= INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT)) {
-                       if (INT_ISZERO(ddq->d_btimer, ARCH_CONVERT) && !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) {
-                               if (flags & XFS_QMOPT_DOWARN)
-                                       cmn_err(CE_ALERT,
-                                       "%s : Dquot ID 0x%x (0x%x) "
-                                       "BLK TIMER NOT STARTED",
-                                       str, (int) INT_GET(ddq->d_id, ARCH_CONVERT), ddq);
-                               errs++;
-                       }
-               }
-               if (INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT) &&
-                   INT_GET(ddq->d_icount, ARCH_CONVERT) >= INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT)) {
-                       if (INT_ISZERO(ddq->d_itimer, ARCH_CONVERT) && !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) {
-                               if (flags & XFS_QMOPT_DOWARN)
-                                       cmn_err(CE_ALERT,
-                                       "%s : Dquot ID 0x%x (0x%x) "
-                                       "INODE TIMER NOT STARTED",
-                                       str, (int) INT_GET(ddq->d_id, ARCH_CONVERT), ddq);
-                               errs++;
-                       }
-               }
-       }
-
-       if (!errs || !(flags & XFS_QMOPT_DQREPAIR))
-               return (errs);
-
-       if (flags & XFS_QMOPT_DOWARN)
-               cmn_err(CE_NOTE, "Re-initializing dquot ID 0x%x", id);
-
-       /*
-        * Typically, a repair is only requested by quotacheck.
-        */
-       ASSERT(id != -1);
-       ASSERT(flags & XFS_QMOPT_DQREPAIR);
-       memset(ddq, 0, sizeof(xfs_dqblk_t));
-       xfs_qm_dqinit_core(id, type, (xfs_dqblk_t *)ddq);
-       return (errs);
-}
-
-#ifdef QUOTADEBUG
-void
-xfs_qm_dqprint(xfs_dquot_t *dqp)
-{
-       printk( "-----------KERNEL DQUOT----------------\n");
-       printk( "---- dquot ID  =  %d\n", (int) INT_GET(dqp->q_core.d_id, ARCH_CONVERT));
-       printk( "---- type      =  %s\n", XFS_QM_ISUDQ(dqp) ? "USR" : "GRP");
-       printk( "---- fs        =  0x%p\n", dqp->q_mount);
-       printk( "---- blkno     =  0x%x\n", (int) dqp->q_blkno);
-       printk( "---- boffset   =  0x%x\n", (int) dqp->q_bufoffset);
-       printk( "---- blkhlimit =  %Lu (0x%x)\n",
-              INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT),
-              (int) INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT));
-       printk( "---- blkslimit =  %Lu (0x%x)\n",
-              INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT),
-              (int)INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT));
-       printk( "---- inohlimit =  %Lu (0x%x)\n",
-              INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT),
-              (int)INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT));
-       printk( "---- inoslimit =  %Lu (0x%x)\n",
-              INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT),
-              (int)INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT));
-       printk( "---- bcount    =  %Lu (0x%x)\n",
-              INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT),
-              (int)INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
-       printk( "---- icount    =  %Lu (0x%x)\n",
-              INT_GET(dqp->q_core.d_icount, ARCH_CONVERT),
-              (int)INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
-       printk( "---- btimer    =  %d\n", (int)INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT));
-       printk( "---- itimer    =  %d\n", (int)INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT));
-
-       printk( "---------------------------\n");
-}
-#endif
-
-/*
- * Give the buffer a little push if it is incore and
- * wait on the flush lock.
- */
-void
-xfs_qm_dqflock_pushbuf_wait(
-       xfs_dquot_t     *dqp)
-{
-       xfs_buf_t       *bp;
-
-       /*
-        * Check to see if the dquot has been flushed delayed
-        * write.  If so, grab its buffer and send it
-        * out immediately.  We'll be able to acquire
-        * the flush lock when the I/O completes.
-        */
-       bp = xfs_incore(dqp->q_mount->m_ddev_targp, dqp->q_blkno,
-                   XFS_QI_DQCHUNKLEN(dqp->q_mount),
-                   XFS_INCORE_TRYLOCK);
-       if (bp != NULL) {
-               if (XFS_BUF_ISDELAYWRITE(bp)) {
-                       if (XFS_BUF_ISPINNED(bp)) {
-                               xfs_log_force(dqp->q_mount,
-                                             (xfs_lsn_t)0,
-                                             XFS_LOG_FORCE);
-                       }
-                       xfs_bawrite(dqp->q_mount, bp);
-               } else {
-                       xfs_buf_relse(bp);
-               }
-       }
-       xfs_dqflock(dqp);
-}
diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h
deleted file mode 100644 (file)
index 455830a..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.         Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-#ifndef __XFS_DQUOT_H__
-#define __XFS_DQUOT_H__
-
-/*
- * Dquots are structures that hold quota information about a user or a group,
- * much like inodes are for files. In fact, dquots share many characteristics
- * with inodes. However, dquots can also be a centralized resource, relative
- * to a collection of inodes. In this respect, dquots share some characteristics
- * of the superblock.
- * XFS dquots exploit both those in its algorithms. They make every attempt
- * to not be a bottleneck when quotas are on and have minimal impact, if any,
- * when quotas are off.
- */
-
-/*
- * The hash chain headers (hash buckets)
- */
-typedef struct xfs_dqhash {
-       struct xfs_dquot *qh_next;
-       mutex_t           qh_lock;
-       uint              qh_version;   /* ever increasing version */
-       uint              qh_nelems;    /* number of dquots on the list */
-} xfs_dqhash_t;
-
-typedef struct xfs_dqlink {
-       struct xfs_dquot  *ql_next;     /* forward link */
-       struct xfs_dquot **ql_prevp;    /* pointer to prev ql_next */
-} xfs_dqlink_t;
-
-struct xfs_mount;
-struct xfs_trans;
-
-/*
- * This is the marker which is designed to occupy the first few
- * bytes of the xfs_dquot_t structure. Even inside this, the freelist pointers
- * must come first.
- * This serves as the marker ("sentinel") when we have to restart list
- * iterations because of locking considerations.
- */
-typedef struct xfs_dqmarker {
-       struct xfs_dquot*dqm_flnext;    /* link to freelist: must be first */
-       struct xfs_dquot*dqm_flprev;
-       xfs_dqlink_t     dqm_mplist;    /* link to mount's list of dquots */
-       xfs_dqlink_t     dqm_hashlist;  /* link to the hash chain */
-       uint             dqm_flags;     /* various flags (XFS_DQ_*) */
-} xfs_dqmarker_t;
-
-/*
- * The incore dquot structure
- */
-typedef struct xfs_dquot {
-       xfs_dqmarker_t   q_lists;       /* list ptrs, q_flags (marker) */
-       xfs_dqhash_t    *q_hash;        /* the hashchain header */
-       struct xfs_mount*q_mount;       /* filesystem this relates to */
-       struct xfs_trans*q_transp;      /* trans this belongs to currently */
-       uint             q_nrefs;       /* # active refs from inodes */
-       xfs_daddr_t      q_blkno;       /* blkno of dquot buffer */
-       int              q_bufoffset;   /* off of dq in buffer (# dquots) */
-       xfs_fileoff_t    q_fileoffset;  /* offset in quotas file */
-
-       struct xfs_dquot*q_gdquot;      /* group dquot, hint only */
-       xfs_disk_dquot_t q_core;        /* actual usage & quotas */
-       xfs_dq_logitem_t q_logitem;     /* dquot log item */
-       xfs_qcnt_t       q_res_bcount;  /* total regular nblks used+reserved */
-       xfs_qcnt_t       q_res_icount;  /* total inos allocd+reserved */
-       xfs_qcnt_t       q_res_rtbcount;/* total realtime blks used+reserved */
-       mutex_t          q_qlock;       /* quota lock */
-       sema_t           q_flock;       /* flush lock */
-       uint             q_pincount;    /* pin count for this dquot */
-       sv_t             q_pinwait;     /* sync var for pinning */
-#ifdef DQUOT_TRACING
-       struct ktrace   *q_trace;       /* trace header structure */
-#endif
-} xfs_dquot_t;
-
-
-#define dq_flnext      q_lists.dqm_flnext
-#define dq_flprev      q_lists.dqm_flprev
-#define dq_mplist      q_lists.dqm_mplist
-#define dq_hashlist    q_lists.dqm_hashlist
-#define dq_flags       q_lists.dqm_flags
-
-#define XFS_DQHOLD(dqp)                ((dqp)->q_nrefs++)
-
-/*
- * Quota Accounting flags
- */
-#define XFS_ALL_QUOTA_ACCT     (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT)
-#define XFS_ALL_QUOTA_ENFD     (XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD)
-#define XFS_ALL_QUOTA_CHKD     (XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD)
-#define XFS_ALL_QUOTA_ACTV     (XFS_UQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE)
-#define XFS_ALL_QUOTA_ACCT_ENFD (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
-                                XFS_GQUOTA_ACCT|XFS_GQUOTA_ENFD)
-
-#define XFS_IS_QUOTA_RUNNING(mp)  ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
-#define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT)
-#define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT)
-
-/*
- * Quota Limit Enforcement flags
- */
-#define XFS_IS_QUOTA_ENFORCED(mp)      ((mp)->m_qflags & XFS_ALL_QUOTA_ENFD)
-#define XFS_IS_UQUOTA_ENFORCED(mp)     ((mp)->m_qflags & XFS_UQUOTA_ENFD)
-#define XFS_IS_GQUOTA_ENFORCED(mp)     ((mp)->m_qflags & XFS_GQUOTA_ENFD)
-
-#ifdef DEBUG
-static inline int
-XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp)
-{
-       if (mutex_trylock(&dqp->q_qlock)) {
-               mutex_unlock(&dqp->q_qlock);
-               return 0;
-       }
-       return 1;
-}
-#endif
-
-/*
- * The following three routines simply manage the q_flock
- * semaphore embedded in the dquot.  This semaphore synchronizes
- * processes attempting to flush the in-core dquot back to disk.
- */
-#define xfs_dqflock(dqp)        { psema(&((dqp)->q_flock), PINOD | PRECALC);\
-                                  (dqp)->dq_flags |= XFS_DQ_FLOCKED; }
-#define xfs_dqfunlock(dqp)      { ASSERT(valusema(&((dqp)->q_flock)) <= 0); \
-                                  vsema(&((dqp)->q_flock)); \
-                                  (dqp)->dq_flags &= ~(XFS_DQ_FLOCKED); }
-
-#define XFS_DQ_PINLOCK(dqp)       mutex_spinlock( \
-                                    &(XFS_DQ_TO_QINF(dqp)->qi_pinlock))
-#define XFS_DQ_PINUNLOCK(dqp, s)   mutex_spinunlock( \
-                                    &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s)
-
-#define XFS_DQ_IS_FLUSH_LOCKED(dqp) (valusema(&((dqp)->q_flock)) <= 0)
-#define XFS_DQ_IS_ON_FREELIST(dqp)  ((dqp)->dq_flnext != (dqp))
-#define XFS_DQ_IS_DIRTY(dqp)   ((dqp)->dq_flags & XFS_DQ_DIRTY)
-#define XFS_QM_ISUDQ(dqp)      ((dqp)->dq_flags & XFS_DQ_USER)
-#define XFS_DQ_TO_QINF(dqp)    ((dqp)->q_mount->m_quotainfo)
-#define XFS_DQ_TO_QIP(dqp)     (XFS_QM_ISUDQ(dqp) ? \
-                                XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \
-                                XFS_DQ_TO_QINF(dqp)->qi_gquotaip)
-
-#define XFS_IS_THIS_QUOTA_OFF(d) (! (XFS_QM_ISUDQ(d) ? \
-                                    (XFS_IS_UQUOTA_ON((d)->q_mount)) : \
-                                    (XFS_IS_GQUOTA_ON((d)->q_mount))))
-#ifdef DQUOT_TRACING
-/*
- * Dquot Tracing stuff.
- */
-#define DQUOT_TRACE_SIZE       64
-#define DQUOT_KTRACE_ENTRY     1
-
-#define xfs_dqtrace_entry_ino(a,b,ip) \
-xfs_dqtrace_entry__((a), (b), (void*)__return_address, (ip))
-#define xfs_dqtrace_entry(a,b) \
-xfs_dqtrace_entry__((a), (b), (void*)__return_address, NULL)
-extern void            xfs_dqtrace_entry__(xfs_dquot_t *dqp, char *func,
-                                           void *, xfs_inode_t *);
-#else
-#define xfs_dqtrace_entry(a,b)
-#define xfs_dqtrace_entry_ino(a,b,ip)
-#endif
-#ifdef QUOTADEBUG
-extern void            xfs_qm_dqprint(xfs_dquot_t *);
-#else
-#define xfs_qm_dqprint(a)
-#endif
-
-extern xfs_dquot_t     *xfs_qm_dqinit(xfs_mount_t *, xfs_dqid_t, uint);
-extern void            xfs_qm_dqdestroy(xfs_dquot_t *);
-extern int             xfs_qm_dqflush(xfs_dquot_t *, uint);
-extern int             xfs_qm_dqpurge(xfs_dquot_t *, uint);
-extern void            xfs_qm_dqunpin_wait(xfs_dquot_t *);
-extern int             xfs_qm_dqlock_nowait(xfs_dquot_t *);
-extern int             xfs_qm_dqflock_nowait(xfs_dquot_t *);
-extern void            xfs_qm_dqflock_pushbuf_wait(xfs_dquot_t *dqp);
-extern void            xfs_qm_adjust_dqtimers(xfs_mount_t *,
-                                              xfs_disk_dquot_t *);
-extern int             xfs_qm_dqwarn(xfs_disk_dquot_t *, uint);
-
-#endif /* __XFS_DQUOT_H__ */
diff --git a/fs/xfs/xfs_dquot_item.c b/fs/xfs/xfs_dquot_item.c
deleted file mode 100644 (file)
index 2d5c619..0000000
+++ /dev/null
@@ -1,680 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.         Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include <xfs.h>
-#include <xfs_quota_priv.h>
-
-
-/*
- * returns the number of iovecs needed to log the given dquot item.
- */
-/* ARGSUSED */
-STATIC uint
-xfs_qm_dquot_logitem_size(
-       xfs_dq_logitem_t        *logitem)
-{
-       /*
-        * we need only two iovecs, one for the format, one for the real thing
-        */
-       return (2);
-}
-
-/*
- * fills in the vector of log iovecs for the given dquot log item.
- */
-STATIC void
-xfs_qm_dquot_logitem_format(
-       xfs_dq_logitem_t        *logitem,
-       xfs_log_iovec_t         *logvec)
-{
-       ASSERT(logitem);
-       ASSERT(logitem->qli_dquot);
-
-       logvec->i_addr = (xfs_caddr_t)&logitem->qli_format;
-       logvec->i_len  = sizeof(xfs_dq_logformat_t);
-       logvec++;
-       logvec->i_addr = (xfs_caddr_t)&logitem->qli_dquot->q_core;
-       logvec->i_len  = sizeof(xfs_disk_dquot_t);
-
-       ASSERT(2 == logitem->qli_item.li_desc->lid_size);
-       logitem->qli_format.qlf_size = 2;
-
-}
-
-/*
- * Increment the pin count of the given dquot.
- * This value is protected by pinlock spinlock in the xQM structure.
- */
-STATIC void
-xfs_qm_dquot_logitem_pin(
-       xfs_dq_logitem_t *logitem)
-{
-       unsigned long   s;
-       xfs_dquot_t *dqp;
-
-       dqp = logitem->qli_dquot;
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-       s = XFS_DQ_PINLOCK(dqp);
-       dqp->q_pincount++;
-       XFS_DQ_PINUNLOCK(dqp, s);
-}
-
-/*
- * Decrement the pin count of the given dquot, and wake up
- * anyone in xfs_dqwait_unpin() if the count goes to 0.         The
- * dquot must have been previously pinned with a call to xfs_dqpin().
- */
-/* ARGSUSED */
-STATIC void
-xfs_qm_dquot_logitem_unpin(
-       xfs_dq_logitem_t *logitem,
-       int               stale)
-{
-       unsigned long   s;
-       xfs_dquot_t *dqp;
-
-       dqp = logitem->qli_dquot;
-       ASSERT(dqp->q_pincount > 0);
-       s = XFS_DQ_PINLOCK(dqp);
-       dqp->q_pincount--;
-       if (dqp->q_pincount == 0) {
-               sv_broadcast(&dqp->q_pinwait);
-       }
-       XFS_DQ_PINUNLOCK(dqp, s);
-}
-
-/* ARGSUSED */
-STATIC void
-xfs_qm_dquot_logitem_unpin_remove(
-       xfs_dq_logitem_t *logitem,
-       xfs_trans_t      *tp)
-{
-       xfs_qm_dquot_logitem_unpin(logitem, 0);
-}
-
-/*
- * Given the logitem, this writes the corresponding dquot entry to disk
- * asynchronously. This is called with the dquot entry securely locked;
- * we simply get xfs_qm_dqflush() to do the work, and unlock the dquot
- * at the end.
- */
-STATIC void
-xfs_qm_dquot_logitem_push(
-       xfs_dq_logitem_t        *logitem)
-{
-       xfs_dquot_t     *dqp;
-
-       dqp = logitem->qli_dquot;
-
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-       ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp));
-
-       /*
-        * Since we were able to lock the dquot's flush lock and
-        * we found it on the AIL, the dquot must be dirty.  This
-        * is because the dquot is removed from the AIL while still
-        * holding the flush lock in xfs_dqflush_done().  Thus, if
-        * we found it in the AIL and were able to obtain the flush
-        * lock without sleeping, then there must not have been
-        * anyone in the process of flushing the dquot.
-        */
-       xfs_qm_dqflush(dqp, XFS_B_DELWRI);
-       xfs_dqunlock(dqp);
-}
-
-/*ARGSUSED*/
-STATIC xfs_lsn_t
-xfs_qm_dquot_logitem_committed(
-       xfs_dq_logitem_t        *l,
-       xfs_lsn_t               lsn)
-{
-       /*
-        * We always re-log the entire dquot when it becomes dirty,
-        * so, the latest copy _is_ the only one that matters.
-        */
-       return (lsn);
-}
-
-
-/*
- * This is called to wait for the given dquot to be unpinned.
- * Most of these pin/unpin routines are plagiarized from inode code.
- */
-void
-xfs_qm_dqunpin_wait(
-       xfs_dquot_t     *dqp)
-{
-       SPLDECL(s);
-
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-       if (dqp->q_pincount == 0) {
-               return;
-       }
-
-       /*
-        * Give the log a push so we don't wait here too long.
-        */
-       xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, XFS_LOG_FORCE);
-       s = XFS_DQ_PINLOCK(dqp);
-       if (dqp->q_pincount == 0) {
-               XFS_DQ_PINUNLOCK(dqp, s);
-               return;
-       }
-       sv_wait(&(dqp->q_pinwait), PINOD,
-               &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s);
-}
-
-/*
- * This is called when IOP_TRYLOCK returns XFS_ITEM_PUSHBUF to indicate that
- * the dquot is locked by us, but the flush lock isn't. So, here we are
- * going to see if the relevant dquot buffer is incore, waiting on DELWRI.
- * If so, we want to push it out to help us take this item off the AIL as soon
- * as possible.
- *
- * We must not be holding the AIL_LOCK at this point. Calling incore() to
- * search the buffercache can be a time consuming thing, and AIL_LOCK is a
- * spinlock.
- */
-STATIC void
-xfs_qm_dquot_logitem_pushbuf(
-       xfs_dq_logitem_t    *qip)
-{
-       xfs_dquot_t     *dqp;
-       xfs_mount_t     *mp;
-       xfs_buf_t       *bp;
-       uint            dopush;
-
-       dqp = qip->qli_dquot;
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-
-       /*
-        * The qli_pushbuf_flag keeps others from
-        * trying to duplicate our effort.
-        */
-       ASSERT(qip->qli_pushbuf_flag != 0);
-       ASSERT(qip->qli_push_owner == get_thread_id());
-
-       /*
-        * If flushlock isn't locked anymore, chances are that the
-        * inode flush completed and the inode was taken off the AIL.
-        * So, just get out.
-        */
-       if ((valusema(&(dqp->q_flock)) > 0)  ||
-           ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) {
-               qip->qli_pushbuf_flag = 0;
-               xfs_dqunlock(dqp);
-               return;
-       }
-       mp = dqp->q_mount;
-       bp = xfs_incore(mp->m_ddev_targp, qip->qli_format.qlf_blkno,
-                   XFS_QI_DQCHUNKLEN(mp),
-                   XFS_INCORE_TRYLOCK);
-       if (bp != NULL) {
-               if (XFS_BUF_ISDELAYWRITE(bp)) {
-                       dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
-                                 (valusema(&(dqp->q_flock)) <= 0));
-                       qip->qli_pushbuf_flag = 0;
-                       xfs_dqunlock(dqp);
-
-                       if (XFS_BUF_ISPINNED(bp)) {
-                               xfs_log_force(mp, (xfs_lsn_t)0,
-                                             XFS_LOG_FORCE);
-                       }
-                       if (dopush) {
-#ifdef XFSRACEDEBUG
-                               delay_for_intr();
-                               delay(300);
-#endif
-                               xfs_bawrite(mp, bp);
-                       } else {
-                               xfs_buf_relse(bp);
-                       }
-               } else {
-                       qip->qli_pushbuf_flag = 0;
-                       xfs_dqunlock(dqp);
-                       xfs_buf_relse(bp);
-               }
-               return;
-       }
-
-       qip->qli_pushbuf_flag = 0;
-       xfs_dqunlock(dqp);
-}
-
-/*
- * This is called to attempt to lock the dquot associated with this
- * dquot log item.  Don't sleep on the dquot lock or the flush lock.
- * If the flush lock is already held, indicating that the dquot has
- * been or is in the process of being flushed, then see if we can
- * find the dquot's buffer in the buffer cache without sleeping.  If
- * we can and it is marked delayed write, then we want to send it out.
- * We delay doing so until the push routine, though, to avoid sleeping
- * in any device strategy routines.
- */
-STATIC uint
-xfs_qm_dquot_logitem_trylock(
-       xfs_dq_logitem_t        *qip)
-{
-       xfs_dquot_t             *dqp;
-       uint                    retval;
-
-       dqp = qip->qli_dquot;
-       if (dqp->q_pincount > 0)
-               return (XFS_ITEM_PINNED);
-
-       if (! xfs_qm_dqlock_nowait(dqp))
-               return (XFS_ITEM_LOCKED);
-
-       retval = XFS_ITEM_SUCCESS;
-       if (! xfs_qm_dqflock_nowait(dqp)) {
-               /*
-                * The dquot is already being flushed.  It may have been
-                * flushed delayed write, however, and we don't want to
-                * get stuck waiting for that to complete.  So, we want to check
-                * to see if we can lock the dquot's buffer without sleeping.
-                * If we can and it is marked for delayed write, then we
-                * hold it and send it out from the push routine.  We don't
-                * want to do that now since we might sleep in the device
-                * strategy routine.  We also don't want to grab the buffer lock
-                * here because we'd like not to call into the buffer cache
-                * while holding the AIL_LOCK.
-                * Make sure to only return PUSHBUF if we set pushbuf_flag
-                * ourselves.  If someone else is doing it then we don't
-                * want to go to the push routine and duplicate their efforts.
-                */
-               if (qip->qli_pushbuf_flag == 0) {
-                       qip->qli_pushbuf_flag = 1;
-                       ASSERT(qip->qli_format.qlf_blkno == dqp->q_blkno);
-#ifdef DEBUG
-                       qip->qli_push_owner = get_thread_id();
-#endif
-                       /*
-                        * The dquot is left locked.
-                        */
-                       retval = XFS_ITEM_PUSHBUF;
-               } else {
-                       retval = XFS_ITEM_FLUSHING;
-                       xfs_dqunlock_nonotify(dqp);
-               }
-       }
-
-       ASSERT(qip->qli_item.li_flags & XFS_LI_IN_AIL);
-       return (retval);
-}
-
-
-/*
- * Unlock the dquot associated with the log item.
- * Clear the fields of the dquot and dquot log item that
- * are specific to the current transaction.  If the
- * hold flags is set, do not unlock the dquot.
- */
-STATIC void
-xfs_qm_dquot_logitem_unlock(
-       xfs_dq_logitem_t    *ql)
-{
-       xfs_dquot_t     *dqp;
-
-       ASSERT(ql != NULL);
-       dqp = ql->qli_dquot;
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-
-       /*
-        * Clear the transaction pointer in the dquot
-        */
-       dqp->q_transp = NULL;
-
-       /*
-        * dquots are never 'held' from getting unlocked at the end of
-        * a transaction.  Their locking and unlocking is hidden inside the
-        * transaction layer, within trans_commit. Hence, no LI_HOLD flag
-        * for the logitem.
-        */
-       xfs_dqunlock(dqp);
-}
-
-
-/*
- * The transaction with the dquot locked has aborted.  The dquot
- * must not be dirty within the transaction.  We simply unlock just
- * as if the transaction had been cancelled.
- */
-STATIC void
-xfs_qm_dquot_logitem_abort(
-       xfs_dq_logitem_t    *ql)
-{
-       xfs_qm_dquot_logitem_unlock(ql);
-}
-
-/*
- * this needs to stamp an lsn into the dquot, I think.
- * rpc's that look at user dquot's would then have to
- * push on the dependency recorded in the dquot
- */
-/* ARGSUSED */
-STATIC void
-xfs_qm_dquot_logitem_committing(
-       xfs_dq_logitem_t        *l,
-       xfs_lsn_t               lsn)
-{
-       return;
-}
-
-
-/*
- * This is the ops vector for dquots
- */
-struct xfs_item_ops xfs_dquot_item_ops = {
-       .iop_size       = (uint(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_size,
-       .iop_format     = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
-                                       xfs_qm_dquot_logitem_format,
-       .iop_pin        = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_pin,
-       .iop_unpin      = (void(*)(xfs_log_item_t*, int))
-                                       xfs_qm_dquot_logitem_unpin,
-       .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*))
-                                       xfs_qm_dquot_logitem_unpin_remove,
-       .iop_trylock    = (uint(*)(xfs_log_item_t*))
-                                       xfs_qm_dquot_logitem_trylock,
-       .iop_unlock     = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_unlock,
-       .iop_committed  = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_qm_dquot_logitem_committed,
-       .iop_push       = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_push,
-       .iop_abort      = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_abort,
-       .iop_pushbuf    = (void(*)(xfs_log_item_t*))
-                                       xfs_qm_dquot_logitem_pushbuf,
-       .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_qm_dquot_logitem_committing
-};
-
-/*
- * Initialize the dquot log item for a newly allocated dquot.
- * The dquot isn't locked at this point, but it isn't on any of the lists
- * either, so we don't care.
- */
-void
-xfs_qm_dquot_logitem_init(
-       struct xfs_dquot *dqp)
-{
-       xfs_dq_logitem_t  *lp;
-       lp = &dqp->q_logitem;
-
-       lp->qli_item.li_type = XFS_LI_DQUOT;
-       lp->qli_item.li_ops = &xfs_dquot_item_ops;
-       lp->qli_item.li_mountp = dqp->q_mount;
-       lp->qli_dquot = dqp;
-       lp->qli_format.qlf_type = XFS_LI_DQUOT;
-       lp->qli_format.qlf_id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT);
-       lp->qli_format.qlf_blkno = dqp->q_blkno;
-       lp->qli_format.qlf_len = 1;
-       /*
-        * This is just the offset of this dquot within its buffer
-        * (which is currently 1 FSB and probably won't change).
-        * Hence 32 bits for this offset should be just fine.
-        * Alternatively, we can store (bufoffset / sizeof(xfs_dqblk_t))
-        * here, and recompute it at recovery time.
-        */
-       lp->qli_format.qlf_boffset = (__uint32_t)dqp->q_bufoffset;
-}
-
-/*------------------  QUOTAOFF LOG ITEMS  -------------------*/
-
-/*
- * This returns the number of iovecs needed to log the given quotaoff item.
- * We only need 1 iovec for an quotaoff item.  It just logs the
- * quotaoff_log_format structure.
- */
-/*ARGSUSED*/
-STATIC uint
-xfs_qm_qoff_logitem_size(xfs_qoff_logitem_t *qf)
-{
-       return (1);
-}
-
-/*
- * This is called to fill in the vector of log iovecs for the
- * given quotaoff log item. We use only 1 iovec, and we point that
- * at the quotaoff_log_format structure embedded in the quotaoff item.
- * It is at this point that we assert that all of the extent
- * slots in the quotaoff item have been filled.
- */
-STATIC void
-xfs_qm_qoff_logitem_format(xfs_qoff_logitem_t  *qf,
-                          xfs_log_iovec_t      *log_vector)
-{
-       ASSERT(qf->qql_format.qf_type == XFS_LI_QUOTAOFF);
-
-       log_vector->i_addr = (xfs_caddr_t)&(qf->qql_format);
-       log_vector->i_len = sizeof(xfs_qoff_logitem_t);
-       qf->qql_format.qf_size = 1;
-}
-
-
-/*
- * Pinning has no meaning for an quotaoff item, so just return.
- */
-/*ARGSUSED*/
-STATIC void
-xfs_qm_qoff_logitem_pin(xfs_qoff_logitem_t *qf)
-{
-       return;
-}
-
-
-/*
- * Since pinning has no meaning for an quotaoff item, unpinning does
- * not either.
- */
-/*ARGSUSED*/
-STATIC void
-xfs_qm_qoff_logitem_unpin(xfs_qoff_logitem_t *qf, int stale)
-{
-       return;
-}
-
-/*ARGSUSED*/
-STATIC void
-xfs_qm_qoff_logitem_unpin_remove(xfs_qoff_logitem_t *qf, xfs_trans_t *tp)
-{
-       return;
-}
-
-/*
- * Quotaoff items have no locking, so just return success.
- */
-/*ARGSUSED*/
-STATIC uint
-xfs_qm_qoff_logitem_trylock(xfs_qoff_logitem_t *qf)
-{
-       return XFS_ITEM_LOCKED;
-}
-
-/*
- * Quotaoff items have no locking or pushing, so return failure
- * so that the caller doesn't bother with us.
- */
-/*ARGSUSED*/
-STATIC void
-xfs_qm_qoff_logitem_unlock(xfs_qoff_logitem_t *qf)
-{
-       return;
-}
-
-/*
- * The quotaoff-start-item is logged only once and cannot be moved in the log,
- * so simply return the lsn at which it's been logged.
- */
-/*ARGSUSED*/
-STATIC xfs_lsn_t
-xfs_qm_qoff_logitem_committed(xfs_qoff_logitem_t *qf, xfs_lsn_t lsn)
-{
-       return (lsn);
-}
-
-/*
- * The transaction of which this QUOTAOFF is a part has been aborted.
- * Just clean up after ourselves.
- * Shouldn't this never happen in the case of qoffend logitems? XXX
- */
-STATIC void
-xfs_qm_qoff_logitem_abort(xfs_qoff_logitem_t *qf)
-{
-       kmem_free(qf, sizeof(xfs_qoff_logitem_t));
-}
-
-/*
- * There isn't much you can do to push on an quotaoff item.  It is simply
- * stuck waiting for the log to be flushed to disk.
- */
-/*ARGSUSED*/
-STATIC void
-xfs_qm_qoff_logitem_push(xfs_qoff_logitem_t *qf)
-{
-       return;
-}
-
-
-/*ARGSUSED*/
-STATIC xfs_lsn_t
-xfs_qm_qoffend_logitem_committed(
-       xfs_qoff_logitem_t *qfe,
-       xfs_lsn_t lsn)
-{
-       xfs_qoff_logitem_t      *qfs;
-       SPLDECL(s);
-
-       qfs = qfe->qql_start_lip;
-       AIL_LOCK(qfs->qql_item.li_mountp,s);
-       /*
-        * Delete the qoff-start logitem from the AIL.
-        * xfs_trans_delete_ail() drops the AIL lock.
-        */
-       xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs, s);
-       kmem_free(qfs, sizeof(xfs_qoff_logitem_t));
-       kmem_free(qfe, sizeof(xfs_qoff_logitem_t));
-       return (xfs_lsn_t)-1;
-}
-
-/*
- * XXX rcc - don't know quite what to do with this.  I think we can
- * just ignore it.  The only time that isn't the case is if we allow
- * the client to somehow see that quotas have been turned off in which
- * we can't allow that to get back until the quotaoff hits the disk.
- * So how would that happen?  Also, do we need different routines for
- * quotaoff start and quotaoff end?  I suspect the answer is yes but
- * to be sure, I need to look at the recovery code and see how quota off
- * recovery is handled (do we roll forward or back or do something else).
- * If we roll forwards or backwards, then we need two separate routines,
- * one that does nothing and one that stamps in the lsn that matters
- * (truly makes the quotaoff irrevocable).  If we do something else,
- * then maybe we don't need two.
- */
-/* ARGSUSED */
-STATIC void
-xfs_qm_qoff_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn)
-{
-       return;
-}
-
-/* ARGSUSED */
-STATIC void
-xfs_qm_qoffend_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn)
-{
-       return;
-}
-
-struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
-       .iop_size       = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
-       .iop_format     = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
-                                       xfs_qm_qoff_logitem_format,
-       .iop_pin        = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
-       .iop_unpin      = (void(*)(xfs_log_item_t* ,int))
-                                       xfs_qm_qoff_logitem_unpin,
-       .iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
-                                       xfs_qm_qoff_logitem_unpin_remove,
-       .iop_trylock    = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
-       .iop_unlock     = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock,
-       .iop_committed  = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_qm_qoffend_logitem_committed,
-       .iop_push       = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
-       .iop_abort      = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort,
-       .iop_pushbuf    = NULL,
-       .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_qm_qoffend_logitem_committing
-};
-
-/*
- * This is the ops vector shared by all quotaoff-start log items.
- */
-struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
-       .iop_size       = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size,
-       .iop_format     = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*))
-                                       xfs_qm_qoff_logitem_format,
-       .iop_pin        = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin,
-       .iop_unpin      = (void(*)(xfs_log_item_t*, int))
-                                       xfs_qm_qoff_logitem_unpin,
-       .iop_unpin_remove = (void(*)(xfs_log_item_t*,xfs_trans_t*))
-                                       xfs_qm_qoff_logitem_unpin_remove,
-       .iop_trylock    = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock,
-       .iop_unlock     = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock,
-       .iop_committed  = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_qm_qoff_logitem_committed,
-       .iop_push       = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
-       .iop_abort      = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort,
-       .iop_pushbuf    = NULL,
-       .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
-                                       xfs_qm_qoff_logitem_committing
-};
-
-/*
- * Allocate and initialize an quotaoff item of the correct quota type(s).
- */
-xfs_qoff_logitem_t *
-xfs_qm_qoff_logitem_init(
-       struct xfs_mount *mp,
-       xfs_qoff_logitem_t *start,
-       uint flags)
-{
-       xfs_qoff_logitem_t      *qf;
-
-       qf = (xfs_qoff_logitem_t*) kmem_zalloc(sizeof(xfs_qoff_logitem_t), KM_SLEEP);
-
-       qf->qql_item.li_type = XFS_LI_QUOTAOFF;
-       if (start)
-               qf->qql_item.li_ops = &xfs_qm_qoffend_logitem_ops;
-       else
-               qf->qql_item.li_ops = &xfs_qm_qoff_logitem_ops;
-       qf->qql_item.li_mountp = mp;
-       qf->qql_format.qf_type = XFS_LI_QUOTAOFF;
-       qf->qql_format.qf_flags = flags;
-       qf->qql_start_lip = start;
-       return (qf);
-}
diff --git a/fs/xfs/xfs_dquot_item.h b/fs/xfs/xfs_dquot_item.h
deleted file mode 100644 (file)
index a11987e..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.         Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-#ifndef __XFS_DQUOT_ITEM_H__
-#define __XFS_DQUOT_ITEM_H__
-
-/*
- * These are the structures used to lay out dquots and quotaoff
- * records on the log. Quite similar to those of inodes.
- */
-
-/*
- * log format struct for dquots.
- * The first two fields must be the type and size fitting into
- * 32 bits : log_recovery code assumes that.
- */
-typedef struct xfs_dq_logformat {
-       __uint16_t              qlf_type;      /* dquot log item type */
-       __uint16_t              qlf_size;      /* size of this item */
-       xfs_dqid_t              qlf_id;        /* usr/grp id number : 32 bits */
-       __int64_t               qlf_blkno;     /* blkno of dquot buffer */
-       __int32_t               qlf_len;       /* len of dquot buffer */
-       __uint32_t              qlf_boffset;   /* off of dquot in buffer */
-} xfs_dq_logformat_t;
-
-/*
- * log format struct for QUOTAOFF records.
- * The first two fields must be the type and size fitting into
- * 32 bits : log_recovery code assumes that.
- * We write two LI_QUOTAOFF logitems per quotaoff, the last one keeps a pointer
- * to the first and ensures that the first logitem is taken out of the AIL
- * only when the last one is securely committed.
- */
-typedef struct xfs_qoff_logformat {
-       unsigned short          qf_type;        /* quotaoff log item type */
-       unsigned short          qf_size;        /* size of this item */
-       unsigned int            qf_flags;       /* USR and/or GRP */
-       char                    qf_pad[12];     /* padding for future */
-} xfs_qoff_logformat_t;
-
-
-#ifdef __KERNEL__
-
-struct xfs_dquot;
-struct xfs_trans;
-struct xfs_mount;
-typedef struct xfs_dq_logitem {
-       xfs_log_item_t           qli_item;         /* common portion */
-       struct xfs_dquot        *qli_dquot;        /* dquot ptr */
-       xfs_lsn_t                qli_flush_lsn;    /* lsn at last flush */
-       unsigned short           qli_pushbuf_flag; /* one bit used in push_ail */
-#ifdef DEBUG
-       uint64_t                 qli_push_owner;
-#endif
-       xfs_dq_logformat_t       qli_format;       /* logged structure */
-} xfs_dq_logitem_t;
-
-
-typedef struct xfs_qoff_logitem {
-       xfs_log_item_t           qql_item;      /* common portion */
-       struct xfs_qoff_logitem *qql_start_lip; /* qoff-start logitem, if any */
-       xfs_qoff_logformat_t     qql_format;    /* logged structure */
-} xfs_qoff_logitem_t;
-
-
-extern void               xfs_qm_dquot_logitem_init(struct xfs_dquot *);
-extern xfs_qoff_logitem_t *xfs_qm_qoff_logitem_init(struct xfs_mount *,
-                                                   xfs_qoff_logitem_t *, uint);
-extern xfs_qoff_logitem_t *xfs_trans_get_qoff_item(struct xfs_trans *,
-                                                  xfs_qoff_logitem_t *, uint);
-extern void               xfs_trans_log_quotaoff_item(struct xfs_trans *,
-                                                      xfs_qoff_logitem_t *);
-
-#endif /* __KERNEL__ */
-
-#endif /* __XFS_DQUOT_ITEM_H__ */
index 14a167f6d848ae3f9490ef5ce8620351d4b9e9cf..e73ed7482b6f481a79c40ba8d0851fbb4a1da297 100644 (file)
@@ -591,9 +591,7 @@ xfs_ireclaim(xfs_inode_t *ip)
         * Release dquots (and their references) if any. An inode may escape
         * xfs_inactive and get here via vn_alloc->vn_reclaim path.
         */
-       if (ip->i_udquot || ip->i_gdquot) {
-               xfs_qm_dqdettach_inode(ip);
-       }
+       XFS_QM_DQDETACH(ip->i_mount, ip);
 
        /*
         * Pull our behavior descriptor from the vnode chain.
index 247e842f32990d179ce3b6ecd4a2ef5ee2a234ec..18eeda703102a7e8652227359400b6cbe8c1f697 100644 (file)
@@ -136,16 +136,15 @@ xlog_bwrite(
 /*
  * check log record header for recovery
  */
-
 static void
 xlog_header_check_dump(xfs_mount_t *mp, xlog_rec_header_t *head)
 {
     int b;
 
-    printk("xlog_header_check_dump:\n   SB : uuid = ");
+    printk("%s:  SB : uuid = ", __FUNCTION__);
     for (b=0;b<16;b++) printk("%02x",((unsigned char *)&mp->m_sb.sb_uuid)[b]);
     printk(", fmt = %d\n",XLOG_FMT);
-    printk("    log: uuid = ");
+    printk("    log : uuid = ");
     for (b=0;b<16;b++) printk("%02x",((unsigned char *)&head->h_fs_uuid)[b]);
     printk(", fmt = %d\n", INT_GET(head->h_fmt, ARCH_CONVERT));
 }
@@ -1813,7 +1812,6 @@ xlog_recover_do_reg_buffer(xfs_mount_t            *mp,
                 */
                error = 0;
                if (buf_f->blf_flags & (XFS_BLI_UDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) {
-                       /* OK, if this returns ENOSYS */
                        error = xfs_qm_dqcheck((xfs_disk_dquot_t *)
                                               item->ri_buf[i].i_addr,
                                               -1, 0, XFS_QMOPT_DOWARN,
@@ -1821,9 +1819,9 @@ xlog_recover_do_reg_buffer(xfs_mount_t            *mp,
                }
                if (!error)
                        memcpy(xfs_buf_offset(bp,
-                                       (uint)bit << XFS_BLI_SHIFT),    /* dest */
-                               item->ri_buf[i].i_addr,                 /* source */
-                               nbits<<XFS_BLI_SHIFT);                  /* length */
+                               (uint)bit << XFS_BLI_SHIFT),    /* dest */
+                               item->ri_buf[i].i_addr,         /* source */
+                               nbits<<XFS_BLI_SHIFT);          /* length */
                i++;
                bit += nbits;
        }
@@ -1832,6 +1830,120 @@ xlog_recover_do_reg_buffer(xfs_mount_t          *mp,
        ASSERT(i == item->ri_total);
 }      /* xlog_recover_do_reg_buffer */
 
+/*
+ * Do some primitive error checking on ondisk dquot data structures.
+ */
+int
+xfs_qm_dqcheck(
+       xfs_disk_dquot_t *ddq,
+       xfs_dqid_t       id,
+       uint             type,    /* used only when IO_dorepair is true */
+       uint             flags,
+       char             *str)
+{
+       xfs_dqblk_t      *d = (xfs_dqblk_t *)ddq;
+       int             errs = 0;
+
+       /*
+        * We can encounter an uninitialized dquot buffer for 2 reasons:
+        * 1. If we crash while deleting the quotainode(s), and those blks got
+        *    used for user data. This is because we take the path of regular
+        *    file deletion; however, the size field of quotainodes is never
+        *    updated, so all the tricks that we play in itruncate_finish
+        *    don't quite matter.
+        *
+        * 2. We don't play the quota buffers when there's a quotaoff logitem.
+        *    But the allocation will be replayed so we'll end up with an
+        *    uninitialized quota block.
+        *
+        * This is all fine; things are still consistent, and we haven't lost
+        * any quota information. Just don't complain about bad dquot blks.
+        */
+       if (INT_GET(ddq->d_magic, ARCH_CONVERT) != XFS_DQUOT_MAGIC) {
+               if (flags & XFS_QMOPT_DOWARN)
+                       cmn_err(CE_ALERT,
+                       "%s : XFS dquot ID 0x%x, magic 0x%x != 0x%x",
+                       str, id,
+                       INT_GET(ddq->d_magic, ARCH_CONVERT), XFS_DQUOT_MAGIC);
+               errs++;
+       }
+       if (INT_GET(ddq->d_version, ARCH_CONVERT) != XFS_DQUOT_VERSION) {
+               if (flags & XFS_QMOPT_DOWARN)
+                       cmn_err(CE_ALERT,
+                       "%s : XFS dquot ID 0x%x, version 0x%x != 0x%x",
+                       str, id,
+                       INT_GET(ddq->d_magic, ARCH_CONVERT), XFS_DQUOT_VERSION);
+               errs++;
+       }
+
+       if (INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_USER &&
+           INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_GROUP) {
+               if (flags & XFS_QMOPT_DOWARN)
+                       cmn_err(CE_ALERT,
+                       "%s : XFS dquot ID 0x%x, unknown flags 0x%x",
+                       str, id, INT_GET(ddq->d_flags, ARCH_CONVERT));
+               errs++;
+       }
+
+       if (id != -1 && id != INT_GET(ddq->d_id, ARCH_CONVERT)) {
+               if (flags & XFS_QMOPT_DOWARN)
+                       cmn_err(CE_ALERT,
+                       "%s : ondisk-dquot 0x%x, ID mismatch: "
+                       "0x%x expected, found id 0x%x",
+                       str, ddq, id, INT_GET(ddq->d_id, ARCH_CONVERT));
+               errs++;
+       }
+
+       if (! errs) {
+               if (INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT) &&
+                   INT_GET(ddq->d_bcount, ARCH_CONVERT) >=
+                               INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT)) {
+                       if (INT_ISZERO(ddq->d_btimer, ARCH_CONVERT) &&
+                           !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) {
+                               if (flags & XFS_QMOPT_DOWARN)
+                                       cmn_err(CE_ALERT,
+                                       "%s : Dquot ID 0x%x (0x%x) "
+                                       "BLK TIMER NOT STARTED",
+                                       str, (int)
+                                       INT_GET(ddq->d_id, ARCH_CONVERT), ddq);
+                               errs++;
+                       }
+               }
+               if (INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT) &&
+                   INT_GET(ddq->d_icount, ARCH_CONVERT) >=
+                               INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT)) {
+                       if (INT_ISZERO(ddq->d_itimer, ARCH_CONVERT) &&
+                           !INT_ISZERO(ddq->d_id, ARCH_CONVERT)) {
+                               if (flags & XFS_QMOPT_DOWARN)
+                                       cmn_err(CE_ALERT,
+                                       "%s : Dquot ID 0x%x (0x%x) "
+                                       "INODE TIMER NOT STARTED",
+                                       str, (int)
+                                       INT_GET(ddq->d_id, ARCH_CONVERT), ddq);
+                               errs++;
+                       }
+               }
+       }
+
+       if (!errs || !(flags & XFS_QMOPT_DQREPAIR))
+               return errs;
+
+       if (flags & XFS_QMOPT_DOWARN)
+               cmn_err(CE_NOTE, "Re-initializing dquot ID 0x%x", id);
+
+       /*
+        * Typically, a repair is only requested by quotacheck.
+        */
+       ASSERT(id != -1);
+       ASSERT(flags & XFS_QMOPT_DQREPAIR);
+       memset(d, 0, sizeof(xfs_dqblk_t));
+       INT_SET(d->dd_diskdq.d_magic, ARCH_CONVERT, XFS_DQUOT_MAGIC);
+       INT_SET(d->dd_diskdq.d_version, ARCH_CONVERT, XFS_DQUOT_VERSION);
+       INT_SET(d->dd_diskdq.d_id, ARCH_CONVERT, id);
+       INT_SET(d->dd_diskdq.d_flags, ARCH_CONVERT, type);
+
+       return errs;
+}
 
 /*
  * Perform a dquot buffer recovery.
@@ -2335,8 +2447,6 @@ xlog_recover_do_dquot_trans(xlog_t                *log,
                           dq_f->qlf_id,
                           0, XFS_QMOPT_DOWARN,
                           "xlog_recover_do_dquot_trans (log copy)"))) {
-               if (error == ENOSYS)
-                       return (0);
                return XFS_ERROR(EIO);
        }
        ASSERT(dq_f->qlf_len == 1);
@@ -2923,8 +3033,6 @@ xlog_recover_process_iunlinks(xlog_t      *log)
 
        /*
         * Prevent any DMAPI event from being sent while in this function.
-        * Not a problem for xfs since the file system isn't mounted
-        * yet.  It is a problem for cxfs recovery.
         */
        mp_dmevmask = mp->m_dmevmask;
        mp->m_dmevmask = 0;
@@ -2982,11 +3090,8 @@ xlog_recover_process_iunlinks(xlog_t     *log)
                                         * Prevent any DMAPI event from
                                         * being sent when the
                                         * reference on the inode is
-                                        * dropped.  Not a problem for
-                                        * xfs since the file system
-                                        * isn't mounted yet.  It is a
-                                        * problem for cxfs recovery.
-                                        */
+                                        * dropped.
+                                         */
                                        ip->i_d.di_dmevmask = 0;
 
                                        /*
index 8433471e250f724a0a2103890e8ebfe65c975e67..c3f64fb7711f4b89b4f9baf9eb87f1b7143ad02f 100644 (file)
@@ -32,7 +32,6 @@
 
 #include <xfs.h>
 
-STATIC void    xfs_mount_reset_sbqflags(xfs_mount_t *);
 STATIC void    xfs_mount_log_sbunit(xfs_mount_t *, __int64_t);
 STATIC int     xfs_uuid_mount(xfs_mount_t *);
 STATIC void    xfs_uuid_unmount(xfs_mount_t *mp);
@@ -154,13 +153,11 @@ xfs_mount_free(
        spinlock_destroy(&mp->m_sb_lock);
        mutex_destroy(&mp->m_ilock);
        freesema(&mp->m_growlock);
+       if (mp->m_quotainfo)
+               XFS_QM_DONE(mp);
 
-       if (mp->m_fsname != NULL) {
+       if (mp->m_fsname != NULL)
                kmem_free(mp->m_fsname, mp->m_fsname_len);
-       }
-       if (mp->m_quotainfo != NULL) {
-               xfs_qm_unmount_quotadestroy(mp);
-       }
 
        if (remove_bhv) {
                struct vfs      *vfsp = XFS_MTOVFS(mp);
@@ -606,10 +603,8 @@ xfs_mountfs(
        vmap_t          vmap;
        xfs_daddr_t     d;
        __uint64_t      ret64;
-       uint            quotaflags, quotaondisk;
-       uint            uquotaondisk = 0, gquotaondisk = 0;
-       boolean_t       needquotamount;
        __int64_t       update_flags;
+       uint            quotamount, quotaflags;
        int             agno, noio;
        int             uuid_mounted = 0;
        int             error = 0;
@@ -946,54 +941,22 @@ xfs_mountfs(
 
        ASSERT(rip != NULL);
        rvp = XFS_ITOV(rip);
+       VMAP(rvp, vmap);
+
        if (unlikely((rip->i_d.di_mode & IFMT) != IFDIR)) {
                cmn_err(CE_WARN, "XFS: corrupted root inode");
-               VMAP(rvp, vmap);
                prdev("Root inode %llu is not a directory",
                      mp->m_dev, (unsigned long long)rip->i_ino);
                xfs_iunlock(rip, XFS_ILOCK_EXCL);
-               VN_RELE(rvp);
-               vn_purge(rvp, &vmap);
                XFS_ERROR_REPORT("xfs_mountfs_int(2)", XFS_ERRLEVEL_LOW,
                                 mp);
                error = XFS_ERROR(EFSCORRUPTED);
-               goto error3;
+               goto error4;
        }
        mp->m_rootip = rip;     /* save it */
 
        xfs_iunlock(rip, XFS_ILOCK_EXCL);
 
-       quotaondisk = XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
-               mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT);
-
-       if (quotaondisk) {
-               uquotaondisk = mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT;
-               gquotaondisk = mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT;
-       }
-
-       /*
-        * If the device itself is read-only, we can't allow
-        * the user to change the state of quota on the mount -
-        * this would generate a transaction on the ro device,
-        * which would lead to an I/O error and shutdown
-        */
-
-       if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) ||
-           (!uquotaondisk &&  XFS_IS_UQUOTA_ON(mp)) ||
-            (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
-           (!gquotaondisk &&  XFS_IS_GQUOTA_ON(mp)))  &&
-           xfs_dev_is_read_only(mp, "changing quota state")) {
-               cmn_err(CE_WARN,
-                       "XFS: please mount with%s%s%s.",
-                       (!quotaondisk ? "out quota" : ""),
-                       (uquotaondisk ? " usrquota" : ""),
-                       (gquotaondisk ? " grpquota" : ""));
-               VN_RELE(rvp);
-               vn_remove(rvp);
-               error = XFS_ERROR(EPERM);
-               goto error3;
-       }
-
        /*
         * Initialize realtime inode pointers in the mount structure
         */
@@ -1002,10 +965,7 @@ xfs_mountfs(
                 * Free up the root inode.
                 */
                cmn_err(CE_WARN, "XFS: failed to read RT inodes");
-               VMAP(rvp, vmap);
-               VN_RELE(rvp);
-               vn_purge(rvp, &vmap);
-               goto error3;
+               goto error4;
        }
 
        /*
@@ -1015,41 +975,11 @@ xfs_mountfs(
        if (update_flags && !(vfsp->vfs_flag & VFS_RDONLY))
                xfs_mount_log_sbunit(mp, update_flags);
 
-       quotaflags = 0;
-       needquotamount = B_FALSE;
-
        /*
-        * Figure out if we'll need to do a quotacheck.
+        * Initialise the XFS quota management subsystem for this mount
         */
-       if (XFS_IS_QUOTA_ON(mp) || quotaondisk) {
-               /*
-                * Call mount_quotas at this point only if we won't have to do
-                * a quotacheck.
-                */
-               if (quotaondisk && !XFS_QM_NEED_QUOTACHECK(mp)) {
-                       /*
-                        * If the xfs quota code isn't installed,
-                        * we have to reset the quotachk'd bit.
-                        * If an error occurred, qm_mount_quotas code
-                        * has already disabled quotas. So, just finish
-                        * mounting, and get on with the boring life
-                        * without disk quotas.
-                        */
-                       if (xfs_qm_mount_quotas(mp))
-                               xfs_mount_reset_sbqflags(mp);
-               } else {
-                       /*
-                        * Clear the quota flags, but remember them. This
-                        * is so that the quota code doesn't get invoked
-                        * before we're ready. This can happen when an
-                        * inode goes inactive and wants to free blocks,
-                        * or via xfs_log_mount_finish.
-                        */
-                       quotaflags = mp->m_qflags;
-                       mp->m_qflags = 0;
-                       needquotamount = B_TRUE;
-               }
-       }
+       if ((error = XFS_QM_INIT(mp, &quotamount, &quotaflags)))
+               goto error4;
 
        /*
         * Finish recovering the file system.  This part needed to be
@@ -1059,30 +989,23 @@ xfs_mountfs(
        error = xfs_log_mount_finish(mp, mfsi_flags);
        if (error) {
                cmn_err(CE_WARN, "XFS: log mount finish failed");
-               goto error3;
-       }
-
-       if (needquotamount) {
-               ASSERT(mp->m_qflags == 0);
-               mp->m_qflags = quotaflags;
-               if (xfs_qm_mount_quotas(mp))
-                       xfs_mount_reset_sbqflags(mp);
+               goto error4;
        }
 
-#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
-       if (! (XFS_IS_QUOTA_ON(mp)))
-               xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas not turned on");
-       else
-               xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas turned on");
-#endif
-
-#ifdef QUOTADEBUG
-       if (XFS_IS_QUOTA_ON(mp) && xfs_qm_internalqcheck(mp))
-               cmn_err(CE_WARN, "XFS: mount internalqcheck failed");
-#endif
+       /*
+        * Complete the quota initialisation, post-log-replay component.
+        */
+       if ((error = XFS_QM_MOUNT(mp, quotamount, quotaflags)))
+               goto error4;
 
-       return (0);
+       return 0;
 
+ error4:
+       /*
+        * Free up the root inode.
+        */
+       VN_RELE(rvp);
+       vn_purge(rvp, &vmap);
  error3:
        xfs_log_unmount_dealloc(mp);
  error2:
@@ -1112,25 +1035,14 @@ int
 xfs_unmountfs(xfs_mount_t *mp, struct cred *cr)
 {
        struct vfs      *vfsp = XFS_MTOVFS(mp);
-       int             ndquots;
 #if defined(DEBUG) || defined(INDUCE_IO_ERROR)
        int64_t         fsid;
 #endif
 
        xfs_iflush_all(mp, XFS_FLUSH_ALL);
 
-       /*
-        * Purge the dquot cache.
-        * None of the dquots should really be busy at this point.
-        */
-       if (mp->m_quotainfo) {
-               while ((ndquots = xfs_qm_dqpurge_all(mp,
-                                                 XFS_QMOPT_UQUOTA|
-                                                 XFS_QMOPT_GQUOTA|
-                                                 XFS_QMOPT_UMOUNTING))) {
-                       delay(ndquots * 10);
-               }
-       }
+       XFS_QM_DQPURGEALL(mp,
+               XFS_QMOPT_UQUOTA | XFS_QMOPT_GQUOTA | XFS_QMOPT_UMOUNTING);
 
        /*
         * Flush out the log synchronously so that we know for sure
@@ -1645,47 +1557,6 @@ xfs_uuid_unmount(xfs_mount_t *mp)
        mutex_unlock(&xfs_uuidtabmon);
 }
 
-/*
- * When xfsquotas isn't installed and the superblock had quotas, we need to
- * clear the quotaflags from superblock.
- */
-STATIC void
-xfs_mount_reset_sbqflags(
-       xfs_mount_t     *mp)
-{
-       xfs_trans_t     *tp;
-       unsigned long           s;
-
-       mp->m_qflags = 0;
-       /*
-        * It is OK to look at sb_qflags here in mount path,
-        * without SB_LOCK.
-        */
-       if (mp->m_sb.sb_qflags == 0)
-               return;
-       s = XFS_SB_LOCK(mp);
-       mp->m_sb.sb_qflags = 0;
-       XFS_SB_UNLOCK(mp, s);
-
-       /*
-        * if the fs is readonly, let the incore superblock run
-        * with quotas off but don't flush the update out to disk
-        */
-       if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY)
-               return;
-#ifdef QUOTADEBUG
-       xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes");
-#endif
-       tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
-       if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
-                                     XFS_DEFAULT_LOG_COUNT)) {
-               xfs_trans_cancel(tp, 0);
-               return;
-       }
-       xfs_mod_sb(tp, XFS_SB_QFLAGS);
-       (void)xfs_trans_commit(tp, 0, NULL);
-}
-
 /*
  * Used to log changes to the superblock unit and width fields which could
  * be altered by the mount options. Only the first superblock is updated.
index da3067d233f166a4aa572ab51aeda2e0a041835b..62f598e4d5333f54bc44e13a49c69a397b2e92d7 100644 (file)
@@ -75,7 +75,6 @@ struct xfs_ihash;
 struct xfs_chash;
 struct xfs_inode;
 struct xfs_perag;
-struct xfs_quotainfo;
 struct xfs_iocore;
 struct xfs_bmbt_irec;
 struct xfs_bmap_free;
@@ -87,13 +86,118 @@ struct xfs_bmap_free;
 #define AIL_LOCK(mp,s)         s=mutex_spinlock(&(mp)->m_ail_lock)
 #define AIL_UNLOCK(mp,s)       mutex_spinunlock(&(mp)->m_ail_lock, s)
 
+
+/*
+ * Prototypes and functions for the Data Migration subsystem.
+ */
+
+typedef int    (*xfs_send_data_t)(int, struct bhv_desc *,
+                       xfs_off_t, size_t, int, vrwlock_t *);
+typedef int    (*xfs_send_mmap_t)(struct vm_area_struct *, uint);
+typedef int    (*xfs_send_destroy_t)(struct bhv_desc *, dm_right_t);
+typedef int    (*xfs_send_namesp_t)(dm_eventtype_t, struct bhv_desc *,
+                       dm_right_t, struct bhv_desc *, dm_right_t,
+                       char *, char *, mode_t, int, int);
+typedef void   (*xfs_send_unmount_t)(struct vfs *, struct vnode *,
+                       dm_right_t, mode_t, int, int);
+
+typedef struct xfs_dmops {
+       xfs_send_data_t         xfs_send_data;
+       xfs_send_mmap_t         xfs_send_mmap;
+       xfs_send_destroy_t      xfs_send_destroy;
+       xfs_send_namesp_t       xfs_send_namesp;
+       xfs_send_unmount_t      xfs_send_unmount;
+} xfs_dmops_t;
+
+#define XFS_SEND_DATA(mp, ev,bdp,off,len,fl,lock) \
+       (*(mp)->m_dm_ops.xfs_send_data)(ev,bdp,off,len,fl,lock)
+#define XFS_SEND_MMAP(mp, vma,fl) \
+       (*(mp)->m_dm_ops.xfs_send_mmap)(vma,fl)
+#define XFS_SEND_DESTROY(mp, bdp,right) \
+       (*(mp)->m_dm_ops.xfs_send_destroy)(bdp,right)
+#define XFS_SEND_NAMESP(mp, ev,b1,r1,b2,r2,n1,n2,mode,rval,fl) \
+       (*(mp)->m_dm_ops.xfs_send_namesp)(ev,b1,r1,b2,r2,n1,n2,mode,rval,fl)
+#define XFS_SEND_UNMOUNT(mp, vfsp,vp,right,mode,rval,fl) \
+       (*(mp)->m_dm_ops.xfs_send_unmount)(vfsp,vp,right,mode,rval,fl)
+
+
+/*
+ * Prototypes and functions for the Quota Management subsystem.
+ */
+
+struct xfs_dquot;
+struct xfs_dqtrxops;
+struct xfs_quotainfo;
+
+typedef int    (*xfs_qminit_t)(struct xfs_mount *, uint *, uint *);
+typedef int    (*xfs_qmmount_t)(struct xfs_mount *, uint, uint);
+typedef int    (*xfs_qmunmount_t)(struct xfs_mount *);
+typedef void   (*xfs_qmdone_t)(struct xfs_mount *);
+typedef void   (*xfs_dqrele_t)(struct xfs_dquot *);
+typedef int    (*xfs_dqattach_t)(struct xfs_inode *, uint);
+typedef void   (*xfs_dqdetach_t)(struct xfs_inode *);
+typedef int    (*xfs_dqpurgeall_t)(struct xfs_mount *, uint);
+typedef int    (*xfs_dqvopalloc_t)(struct xfs_mount *,
+                       struct xfs_inode *, uid_t, gid_t, uint,
+                       struct xfs_dquot **, struct xfs_dquot **);
+typedef void   (*xfs_dqvopcreate_t)(struct xfs_trans *, struct xfs_inode *,
+                       struct xfs_dquot *, struct xfs_dquot *);
+typedef int    (*xfs_dqvoprename_t)(struct xfs_inode **);
+typedef struct xfs_dquot * (*xfs_dqvopchown_t)(
+                       struct xfs_trans *, struct xfs_inode *,
+                       struct xfs_dquot **, struct xfs_dquot *);
+typedef int    (*xfs_dqvopchownresv_t)(struct xfs_trans *, struct xfs_inode *,
+                       struct xfs_dquot *, struct xfs_dquot *, uint);
+
+typedef struct xfs_qmops {
+       xfs_qminit_t            xfs_qminit;
+       xfs_qmdone_t            xfs_qmdone;
+       xfs_qmmount_t           xfs_qmmount;
+       xfs_qmunmount_t         xfs_qmunmount;
+       xfs_dqrele_t            xfs_dqrele;
+       xfs_dqattach_t          xfs_dqattach;
+       xfs_dqdetach_t          xfs_dqdetach;
+       xfs_dqpurgeall_t        xfs_dqpurgeall;
+       xfs_dqvopalloc_t        xfs_dqvopalloc;
+       xfs_dqvopcreate_t       xfs_dqvopcreate;
+       xfs_dqvoprename_t       xfs_dqvoprename;
+       xfs_dqvopchown_t        xfs_dqvopchown;
+       xfs_dqvopchownresv_t    xfs_dqvopchownresv;
+       struct xfs_dqtrxops     *xfs_dqtrxops;
+} xfs_qmops_t;
+
+#define XFS_QM_INIT(mp, mnt, fl) \
+       (*(mp)->m_qm_ops.xfs_qminit)(mp, mnt, fl)
+#define XFS_QM_MOUNT(mp, mnt, fl) \
+       (*(mp)->m_qm_ops.xfs_qmmount)(mp, mnt, fl)
+#define XFS_QM_UNMOUNT(mp) \
+       (*(mp)->m_qm_ops.xfs_qmunmount)(mp)
+#define XFS_QM_DONE(mp) \
+       (*(mp)->m_qm_ops.xfs_qmdone)(mp)
+#define XFS_QM_DQRELE(mp, dq) \
+       (*(mp)->m_qm_ops.xfs_dqrele)(dq)
+#define XFS_QM_DQATTACH(mp, ip, fl) \
+       (*(mp)->m_qm_ops.xfs_dqattach)(ip, fl)
+#define XFS_QM_DQDETACH(mp, ip) \
+       (*(mp)->m_qm_ops.xfs_dqdetach)(ip)
+#define XFS_QM_DQPURGEALL(mp, fl) \
+       (*(mp)->m_qm_ops.xfs_dqpurgeall)(mp, fl)
+#define XFS_QM_DQVOPALLOC(mp, ip, uid, gid, fl, dq1, dq2) \
+       (*(mp)->m_qm_ops.xfs_dqvopalloc)(mp, ip, uid, gid, fl, dq1, dq2)
+#define XFS_QM_DQVOPCREATE(mp, tp, ip, dq1, dq2) \
+       (*(mp)->m_qm_ops.xfs_dqvopcreate)(tp, ip, dq1, dq2)
+#define XFS_QM_DQVOPRENAME(mp, ip) \
+       (*(mp)->m_qm_ops.xfs_dqvoprename)(ip)
+#define XFS_QM_DQVOPCHOWN(mp, tp, ip, dqp, dq) \
+       (*(mp)->m_qm_ops.xfs_dqvopchown)(tp, ip, dqp, dq)
+#define XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, dq1, dq2, fl) \
+       (*(mp)->m_qm_ops.xfs_dqvopchownresv)(tp, ip, dq1, dq2, fl)
+
+
 /*
  * Prototypes and functions for I/O core modularization.
  */
  
-struct flid;
-struct buf;
-
 typedef int            (*xfs_ioinit_t)(struct vfs *,
                                struct xfs_mount_args *, int);
 typedef int            (*xfs_bmapi_t)(struct xfs_trans *, void *,
@@ -137,52 +241,38 @@ typedef struct xfs_ioops {
        xfs_iodone_t                    xfs_iodone;
 } xfs_ioops_t;
 
-
 #define XFS_IOINIT(vfsp, args, flags) \
        (*(mp)->m_io_ops.xfs_ioinit)(vfsp, args, flags)
-
 #define XFS_BMAPI(mp, trans,io,bno,len,f,first,tot,mval,nmap,flist)    \
        (*(mp)->m_io_ops.xfs_bmapi_func) \
                (trans,(io)->io_obj,bno,len,f,first,tot,mval,nmap,flist)
-
 #define XFS_BMAP_EOF(mp, io, endoff, whichfork, eof) \
        (*(mp)->m_io_ops.xfs_bmap_eof_func) \
                ((io)->io_obj, endoff, whichfork, eof)
-
 #define XFS_IOMAP_WRITE_DIRECT(mp, io, offset, count, flags, mval, nmap, found)\
        (*(mp)->m_io_ops.xfs_iomap_write_direct) \
                ((io)->io_obj, offset, count, flags, mval, nmap, found)
-
 #define XFS_IOMAP_WRITE_DELAY(mp, io, offset, count, flags, mval, nmap) \
        (*(mp)->m_io_ops.xfs_iomap_write_delay) \
                ((io)->io_obj, offset, count, flags, mval, nmap)
-
 #define XFS_IOMAP_WRITE_ALLOCATE(mp, io, mval, nmap) \
        (*(mp)->m_io_ops.xfs_iomap_write_allocate) \
                ((io)->io_obj, mval, nmap)
-
 #define XFS_IOMAP_WRITE_UNWRITTEN(mp, io, offset, count) \
        (*(mp)->m_io_ops.xfs_iomap_write_unwritten) \
                ((io)->io_obj, offset, count)
-
 #define XFS_LCK_MAP_SHARED(mp, io) \
        (*(mp)->m_io_ops.xfs_lck_map_shared)((io)->io_obj)
-
 #define XFS_ILOCK(mp, io, mode) \
        (*(mp)->m_io_ops.xfs_ilock)((io)->io_obj, mode)
-
 #define XFS_ILOCK_NOWAIT(mp, io, mode) \
        (*(mp)->m_io_ops.xfs_ilock_nowait)((io)->io_obj, mode)
-
 #define XFS_IUNLOCK(mp, io, mode) \
        (*(mp)->m_io_ops.xfs_unlock)((io)->io_obj, mode)
-
 #define XFS_ILOCK_DEMOTE(mp, io, mode) \
        (*(mp)->m_io_ops.xfs_ilock_demote)((io)->io_obj, mode)
-
 #define XFS_SIZE(mp, io) \
        (*(mp)->m_io_ops.xfs_size_func)((io)->io_obj)
-
 #define XFS_IODONE(vfsp) \
        (*(mp)->m_io_ops.xfs_iodone)(vfsp)
 
@@ -284,13 +374,9 @@ typedef struct xfs_mount {
        int                     m_chsize;       /* size of next field */
        struct xfs_chash        *m_chash;       /* fs private inode per-cluster
                                                 * hash table */
+       struct xfs_dmops        m_dm_ops;       /* vector of DMI ops */
+       struct xfs_qmops        m_qm_ops;       /* vector of XQM ops */
        struct xfs_ioops        m_io_ops;       /* vector of I/O ops */
-       struct xfs_expinfo      *m_expinfo;     /* info to export to other
-                                                  cells. */
-       uint64_t                m_shadow_pinmask;
-                                               /* which bits matter in rpc
-                                                  log item pin masks */
-       uint                    m_cxfstype;     /* mounted shared, etc. */
        lock_t                  m_freeze_lock;  /* Lock for m_frozen */
        uint                    m_frozen;       /* FS frozen for shutdown or
                                                 * snapshot */
@@ -482,11 +568,10 @@ extern void       xfs_check_frozen(xfs_mount_t *, bhv_desc_t *, int);
 extern struct vfsops xfs_vfsops;
 extern struct vnodeops xfs_vnodeops;
 
+extern struct xfs_dmops xfs_dmcore_xfs;
+extern struct xfs_qmops xfs_qmcore_xfs;
 extern struct xfs_ioops xfs_iocore_xfs;
 
-extern struct vfsops xfs_qmops_xfs;
-extern struct vfsops xfs_dmops_xfs;
-
 extern int     xfs_init(void);
 extern void    xfs_cleanup(void);
 
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
deleted file mode 100644 (file)
index 5971def..0000000
+++ /dev/null
@@ -1,2810 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.         Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include <xfs.h>
-#include <xfs_quota_priv.h>
-
-
-kmem_zone_t    *qm_dqzone;
-kmem_zone_t    *qm_dqtrxzone;
-
-STATIC void    xfs_qm_list_init(xfs_dqlist_t *, char *, int);
-STATIC void    xfs_qm_list_destroy(xfs_dqlist_t *);
-STATIC int     xfs_qm_quotacheck(xfs_mount_t *);
-
-STATIC int     xfs_qm_init_quotainos(xfs_mount_t *);
-STATIC void    xfs_qm_shake(void);
-
-#ifdef DEBUG
-extern mutex_t qcheck_lock;
-#endif
-
-#ifdef QUOTADEBUG
-#define XQM_LIST_PRINT(l, NXT, title) \
-{ \
-         xfs_dquot_t   *dqp; int i = 0;\
-         printk("%s (#%d)\n", title, (int) (l)->qh_nelems); \
-         for (dqp = (l)->qh_next; dqp != NULL; dqp = dqp->NXT) { \
-           printk("\t%d.\t\"%d (%s)\"\t bcnt = %d, icnt = %d refs = %d\n", \
-                        ++i, (int) INT_GET(dqp->q_core.d_id, ARCH_CONVERT), \
-                        DQFLAGTO_TYPESTR(dqp),      \
-                        (int) INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), \
-                        (int) INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), \
-                        (int) dqp->q_nrefs);  } \
-}
-#endif
-
-/*
- * Initialize the XQM structure.
- * Note that there is not one quota manager per file system.
- */
-struct xfs_qm *
-xfs_qm_init(void)
-{
-       xfs_qm_t                *xqm;
-       int                     hsize, i;
-
-       xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP);
-       ASSERT(xqm);
-
-       /*
-        * Initialize the dquot hash tables.
-        */
-       hsize = (DQUOT_HASH_HEURISTIC < XFS_QM_NCSIZE_THRESHOLD) ?
-               XFS_QM_HASHSIZE_LOW : XFS_QM_HASHSIZE_HIGH;
-       xqm->qm_dqhashmask = hsize - 1;
-
-       /*
-        * XXXsup We could keep reference counts on usr and grp quotas
-        * inside XQM separately, and avoid having two hashtables even
-        * when only one 'type' is active in the system.
-        */
-       xqm->qm_usr_dqhtable = (xfs_dqhash_t *)kmem_zalloc(hsize *
-                                                     sizeof(xfs_dqhash_t),
-                                                     KM_SLEEP);
-       xqm->qm_grp_dqhtable = (xfs_dqhash_t *)kmem_zalloc(hsize *
-                                                     sizeof(xfs_dqhash_t),
-                                                     KM_SLEEP);
-       ASSERT(xqm->qm_usr_dqhtable != NULL);
-       ASSERT(xqm->qm_grp_dqhtable != NULL);
-
-       for (i = 0; i < hsize; i++) {
-               xfs_qm_list_init(&(xqm->qm_usr_dqhtable[i]), "uxdqh", i);
-               xfs_qm_list_init(&(xqm->qm_grp_dqhtable[i]), "gxdqh", i);
-       }
-
-       /*
-        * Freelist of all dquots of all file systems
-        */
-       xfs_qm_freelist_init(&(xqm->qm_dqfreelist));
-
-       /*
-        * dquot zone. we register our own low-memory callback.
-        */
-       if (!qm_dqzone) {
-               xqm->qm_dqzone = kmem_zone_init(sizeof(xfs_dquot_t),
-                                               "xfs_dquots");
-               qm_dqzone = xqm->qm_dqzone;
-       } else
-               xqm->qm_dqzone = qm_dqzone;
-
-       kmem_shake_register(xfs_qm_shake);
-
-       /*
-        * The t_dqinfo portion of transactions.
-        */
-       if (!qm_dqtrxzone) {
-               xqm->qm_dqtrxzone = kmem_zone_init(sizeof(xfs_dquot_acct_t),
-                                                  "xfs_dqtrx");
-               qm_dqtrxzone = xqm->qm_dqtrxzone;
-       } else
-               xqm->qm_dqtrxzone = qm_dqtrxzone;
-
-       atomic_set(&xqm->qm_totaldquots, 0);
-       xqm->qm_dqfree_ratio = XFS_QM_DQFREE_RATIO;
-       xqm->qm_nrefs = 0;
-#ifdef DEBUG
-       mutex_init(&qcheck_lock, MUTEX_DEFAULT, "qchk");
-#endif
-       return (xqm);
-}
-
-/*
- * Destroy the global quota manager when its reference count goes to zero.
- */
-void
-xfs_qm_destroy(
-       struct xfs_qm *xqm)
-{
-       int     hsize, i;
-
-       ASSERT(xqm != NULL);
-       ASSERT(xqm->qm_nrefs == 0);
-       kmem_shake_deregister(xfs_qm_shake);
-       hsize = xqm->qm_dqhashmask + 1;
-       for (i = 0; i < hsize; i++) {
-               xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
-               xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i]));
-       }
-       kmem_free(xqm->qm_usr_dqhtable, hsize * sizeof(xfs_dqhash_t));
-       kmem_free(xqm->qm_grp_dqhtable, hsize * sizeof(xfs_dqhash_t));
-       xqm->qm_usr_dqhtable = NULL;
-       xqm->qm_grp_dqhtable = NULL;
-       xqm->qm_dqhashmask = 0;
-       xfs_qm_freelist_destroy(&(xqm->qm_dqfreelist));
-#ifdef DEBUG
-       mutex_destroy(&qcheck_lock);
-#endif
-       kmem_free(xqm, sizeof(xfs_qm_t));
-}
-
-/*
- * Called at mount time to let XQM know that another file system is
- * starting quotas. This isn't crucial information as the individual mount
- * structures are pretty independent, but it helps the XQM keep a
- * global view of what's going on.
- */
-/* ARGSUSED */
-STATIC int
-xfs_qm_hold_quotafs_ref(
-       struct xfs_mount *mp)
-{
-       /*
-        * Need to lock the xfs_Gqm structure for things like this. For example,
-        * the structure could disappear between the entry to this routine and
-        * a HOLD operation if not locked.
-        */
-       XFS_QM_LOCK(xfs_Gqm);
-
-       if (xfs_Gqm == NULL) {
-               if ((xfs_Gqm = xfs_qm_init()) == NULL) {
-                       return (XFS_ERROR(EINVAL));
-               }
-       }
-       /*
-        * We can keep a list of all filesystems with quotas mounted for
-        * debugging and statistical purposes, but ...
-        * Just take a reference and get out.
-        */
-       XFS_QM_HOLD(xfs_Gqm);
-       XFS_QM_UNLOCK(xfs_Gqm);
-
-       return 0;
-}
-
-
-/*
- * Release the reference that a filesystem took at mount time,
- * so that we know when we need to destroy the entire quota manager.
- */
-/* ARGSUSED */
-STATIC void
-xfs_qm_rele_quotafs_ref(
-       struct xfs_mount *mp)
-{
-       xfs_dquot_t     *dqp, *nextdqp;
-
-       ASSERT(xfs_Gqm);
-       ASSERT(xfs_Gqm->qm_nrefs > 0);
-
-       /*
-        * Go thru the freelist and destroy all inactive dquots.
-        */
-       xfs_qm_freelist_lock(xfs_Gqm);
-
-       for (dqp = xfs_Gqm->qm_dqfreelist.qh_next;
-            dqp != (xfs_dquot_t *)&(xfs_Gqm->qm_dqfreelist); ) {
-               xfs_dqlock(dqp);
-               nextdqp = dqp->dq_flnext;
-               if (dqp->dq_flags & XFS_DQ_INACTIVE) {
-                       ASSERT(dqp->q_mount == NULL);
-                       ASSERT(! XFS_DQ_IS_DIRTY(dqp));
-                       ASSERT(dqp->HL_PREVP == NULL);
-                       ASSERT(dqp->MPL_PREVP == NULL);
-                       XQM_FREELIST_REMOVE(dqp);
-                       xfs_dqunlock(dqp);
-                       xfs_qm_dqdestroy(dqp);
-               } else {
-                       xfs_dqunlock(dqp);
-               }
-               dqp = nextdqp;
-       }
-       xfs_qm_freelist_unlock(xfs_Gqm);
-
-       /*
-        * Destroy the entire XQM. If somebody mounts with quotaon, this'll
-        * be restarted.
-        */
-       XFS_QM_LOCK(xfs_Gqm);
-       XFS_QM_RELE(xfs_Gqm);
-       if (xfs_Gqm->qm_nrefs == 0) {
-               xfs_qm_destroy(xfs_Gqm);
-               xfs_Gqm = NULL;
-       }
-       XFS_QM_UNLOCK(xfs_Gqm);
-}
-
-/*
- * This is called at mount time from xfs_mountfs to initialize the quotainfo
- * structure and start the global quotamanager (xfs_Gqm) if it hasn't done
- * so already. Note that the superblock has not been read in yet.
- */
-void
-xfs_qm_mount_quotainit(
-       xfs_mount_t     *mp,
-       uint            flags)
-{
-       /*
-        * User or group quotas has to be on.
-        */
-       ASSERT(flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA));
-
-       /*
-        * Initialize the flags in the mount structure. From this point
-        * onwards we look at m_qflags to figure out if quotas's ON/OFF, etc.
-        * Note that we enforce nothing if accounting is off.
-        * ie.  XFSMNT_*QUOTA must be ON for XFSMNT_*QUOTAENF.
-        * It isn't necessary to take the quotaoff lock to do this; this is
-        * called from mount.
-        */
-       if (flags & XFSMNT_UQUOTA) {
-               mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE);
-               if (flags & XFSMNT_UQUOTAENF)
-                       mp->m_qflags |= XFS_UQUOTA_ENFD;
-       }
-       if (flags & XFSMNT_GQUOTA) {
-               mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
-               if (flags & XFSMNT_GQUOTAENF)
-                       mp->m_qflags |= XFS_GQUOTA_ENFD;
-       }
-}
-
-/*
- * Just destroy the quotainfo structure.
- */
-void
-xfs_qm_unmount_quotadestroy(
-       xfs_mount_t     *mp)
-{
-       xfs_qm_destroy_quotainfo(mp);
-}
-
-
-/*
- * This is called from xfs_mountfs to start quotas and initialize all
- * necessary data structures like quotainfo.  This is also responsible for
- * running a quotacheck as necessary.  We are guaranteed that the superblock
- * is consistently read in at this point.
- */
-int
-xfs_qm_mount_quotas(
-       xfs_mount_t     *mp)
-{
-       unsigned long   s;
-       int             error = 0;
-       uint            sbf;
-
-       /*
-        * If a file system had quotas running earlier, but decided to
-        * mount without -o quota/uquota/gquota options, revoke the
-        * quotachecked license, and bail out.
-        */
-       if (! XFS_IS_QUOTA_ON(mp) &&
-           (mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT))) {
-               mp->m_qflags = 0;
-               goto write_changes;
-       }
-
-       /*
-        * If quotas on realtime volumes is not supported, we disable
-        * quotas immediately.
-        */
-       if (mp->m_sb.sb_rextents) {
-               cmn_err(CE_NOTE,
-                       "Cannot turn on quotas for realtime filesystem %s",
-                       mp->m_fsname);
-               mp->m_qflags = 0;
-               goto write_changes;
-       }
-
-#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
-       cmn_err(CE_NOTE, "Attempting to turn on disk quotas.");
-#endif
-
-       ASSERT(XFS_IS_QUOTA_RUNNING(mp));
-       /*
-        * Allocate the quotainfo structure inside the mount struct, and
-        * create quotainode(s), and change/rev superblock if necessary.
-        */
-       if ((error = xfs_qm_init_quotainfo(mp))) {
-               /*
-                * We must turn off quotas.
-                */
-               ASSERT(mp->m_quotainfo == NULL);
-               mp->m_qflags = 0;
-               goto write_changes;
-       }
-       /*
-        * If any of the quotas are not consistent, do a quotacheck.
-        */
-       if (XFS_QM_NEED_QUOTACHECK(mp)) {
-#ifdef DEBUG
-               cmn_err(CE_NOTE, "Doing a quotacheck. Please wait.");
-#endif
-               if ((error = xfs_qm_quotacheck(mp))) {
-                       cmn_err(CE_WARN, "Quotacheck unsuccessful (Error %d): "
-                               "Disabling quotas.",
-                               error);
-                       /*
-                        * We must turn off quotas.
-                        */
-                       ASSERT(mp->m_quotainfo != NULL);
-                       ASSERT(xfs_Gqm != NULL);
-                       xfs_qm_destroy_quotainfo(mp);
-                       mp->m_qflags = 0;
-                       goto write_changes;
-               }
-#ifdef DEBUG
-               cmn_err(CE_NOTE, "Done quotacheck.");
-#endif
-       }
- write_changes:
-       /*
-        * We actually don't have to acquire the SB_LOCK at all.
-        * This can only be called from mount, and that's single threaded. XXX
-        */
-       s = XFS_SB_LOCK(mp);
-       sbf = mp->m_sb.sb_qflags;
-       mp->m_sb.sb_qflags = mp->m_qflags & XFS_MOUNT_QUOTA_ALL;
-       XFS_SB_UNLOCK(mp, s);
-
-       if (sbf != (mp->m_qflags & XFS_MOUNT_QUOTA_ALL)) {
-               if (xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS)) {
-                       /*
-                        * We could only have been turning quotas off.
-                        * We aren't in very good shape actually because
-                        * the incore structures are convinced that quotas are
-                        * off, but the on disk superblock doesn't know that !
-                        */
-                       ASSERT(!(XFS_IS_QUOTA_RUNNING(mp)));
-                       xfs_fs_cmn_err(CE_ALERT, mp,
-                               "XFS mount_quotas: Superblock update failed!");
-               }
-       }
-
-       if (error) {
-               xfs_fs_cmn_err(CE_WARN, mp,
-                       "Failed to initialize disk quotas.");
-       }
-       return XFS_ERROR(error);
-}
-
-/*
- * Called from the vfsops layer.
- */
-int
-xfs_qm_unmount_quotas(
-       xfs_mount_t     *mp)
-{
-       xfs_inode_t     *uqp, *gqp;
-       int             error;
-
-       error = 0;
-
-       /*
-        * Release the dquots that root inode, et al might be holding,
-        * before we flush quotas and blow away the quotainfo structure.
-        */
-       ASSERT(mp->m_rootip);
-       if (mp->m_rootip->i_udquot || mp->m_rootip->i_gdquot)
-               xfs_qm_dqdettach_inode(mp->m_rootip);
-       if (mp->m_rbmip &&
-           (mp->m_rbmip->i_udquot || mp->m_rbmip->i_gdquot))
-               xfs_qm_dqdettach_inode(mp->m_rbmip);
-       if (mp->m_rsumip &&
-           (mp->m_rsumip->i_udquot || mp->m_rsumip->i_gdquot))
-               xfs_qm_dqdettach_inode(mp->m_rsumip);
-
-       /*
-        * Flush out the quota inodes.
-        */
-       uqp = gqp = NULL;
-       if (mp->m_quotainfo) {
-               if ((uqp = mp->m_quotainfo->qi_uquotaip) != NULL) {
-                       xfs_ilock(uqp, XFS_ILOCK_EXCL);
-                       xfs_iflock(uqp);
-                       error = xfs_iflush(uqp, XFS_IFLUSH_SYNC);
-                       xfs_iunlock(uqp, XFS_ILOCK_EXCL);
-                       if (unlikely(error == EFSCORRUPTED)) {
-                               XFS_ERROR_REPORT("xfs_qm_unmount_quotas(1)",
-                                                XFS_ERRLEVEL_LOW, mp);
-                               goto out;
-                       }
-               }
-               if ((gqp = mp->m_quotainfo->qi_gquotaip) != NULL) {
-                       xfs_ilock(gqp, XFS_ILOCK_EXCL);
-                       xfs_iflock(gqp);
-                       error = xfs_iflush(gqp, XFS_IFLUSH_SYNC);
-                       xfs_iunlock(gqp, XFS_ILOCK_EXCL);
-                       if (unlikely(error == EFSCORRUPTED)) {
-                               XFS_ERROR_REPORT("xfs_qm_unmount_quotas(2)",
-                                                XFS_ERRLEVEL_LOW, mp);
-                               goto out;
-                       }
-               }
-       }
-       if (uqp) {
-                XFS_PURGE_INODE(uqp);
-                mp->m_quotainfo->qi_uquotaip = NULL;
-       }
-       if (gqp) {
-               XFS_PURGE_INODE(gqp);
-               mp->m_quotainfo->qi_gquotaip = NULL;
-       }
-out:
-       return XFS_ERROR(error);
-}
-
-/*
- * Flush all dquots of the given file system to disk. The dquots are
- * _not_ purged from memory here, just their data written to disk.
- */
-int
-xfs_qm_dqflush_all(
-       xfs_mount_t     *mp,
-       int             flags)
-{
-       int             recl;
-       xfs_dquot_t     *dqp;
-       int             niters;
-       int             error;
-
-       if (mp->m_quotainfo == NULL)
-               return (0);
-       niters = 0;
-again:
-       xfs_qm_mplist_lock(mp);
-       FOREACH_DQUOT_IN_MP(dqp, mp) {
-               xfs_dqlock(dqp);
-               if (! XFS_DQ_IS_DIRTY(dqp)) {
-                       xfs_dqunlock(dqp);
-                       continue;
-               }
-               xfs_dqtrace_entry(dqp, "FLUSHALL: DQDIRTY");
-               /* XXX a sentinel would be better */
-               recl = XFS_QI_MPLRECLAIMS(mp);
-               if (! xfs_qm_dqflock_nowait(dqp)) {
-                       /*
-                        * If we can't grab the flush lock then check
-                        * to see if the dquot has been flushed delayed
-                        * write.  If so, grab its buffer and send it
-                        * out immediately.  We'll be able to acquire
-                        * the flush lock when the I/O completes.
-                        */
-                       xfs_qm_dqflock_pushbuf_wait(dqp);
-               }
-               /*
-                * Let go of the mplist lock. We don't want to hold it
-                * across a disk write.
-                */
-               xfs_qm_mplist_unlock(mp);
-               error = xfs_qm_dqflush(dqp, flags);
-               xfs_dqunlock(dqp);
-               if (error)
-                       return (error);
-
-               xfs_qm_mplist_lock(mp);
-               if (recl != XFS_QI_MPLRECLAIMS(mp)) {
-                       xfs_qm_mplist_unlock(mp);
-                       /* XXX restart limit */
-                       goto again;
-               }
-       }
-
-       xfs_qm_mplist_unlock(mp);
-       /* return ! busy */
-       return (0);
-}
-/*
- * Release the group dquot pointers the user dquots may be
- * carrying around as a hint. mplist is locked on entry and exit.
- */
-STATIC void
-xfs_qm_detach_gdquots(
-       xfs_mount_t     *mp)
-{
-       xfs_dquot_t     *dqp, *gdqp;
-       int             nrecl;
-
- again:
-       ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
-       dqp = XFS_QI_MPLNEXT(mp);
-       while (dqp) {
-               xfs_dqlock(dqp);
-               if ((gdqp = dqp->q_gdquot)) {
-                       xfs_dqlock(gdqp);
-                       dqp->q_gdquot = NULL;
-               }
-               xfs_dqunlock(dqp);
-
-               if (gdqp) {
-                       /*
-                        * Can't hold the mplist lock across a dqput.
-                        * XXXmust convert to marker based iterations here.
-                        */
-                       nrecl = XFS_QI_MPLRECLAIMS(mp);
-                       xfs_qm_mplist_unlock(mp);
-                       xfs_qm_dqput(gdqp);
-
-                       xfs_qm_mplist_lock(mp);
-                       if (nrecl != XFS_QI_MPLRECLAIMS(mp))
-                               goto again;
-               }
-               dqp = dqp->MPL_NEXT;
-       }
-}
-
-/*
- * Go through all the incore dquots of this file system and take them
- * off the mplist and hashlist, if the dquot type matches the dqtype
- * parameter. This is used when turning off quota accounting for
- * users and/or groups, as well as when the filesystem is unmounting.
- */
-int
-xfs_qm_dqpurge_all(
-                  xfs_mount_t  *mp,
-                  uint         flags) /* QUOTAOFF/UMOUNTING/UQUOTA/GQUOTA */
-{
-       xfs_dquot_t     *dqp;
-       uint            dqtype;
-       int             nrecl;
-       xfs_dquot_t     *nextdqp;
-       int             nmisses;
-
-       if (mp->m_quotainfo == NULL)
-               return (0);
-
-       dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0;
-       dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0;
-
-       xfs_qm_mplist_lock(mp);
-
-       /*
-        * In the first pass through all incore dquots of this filesystem,
-        * we release the group dquot pointers the user dquots may be
-        * carrying around as a hint. We need to do this irrespective of
-        * what's being turned off.
-        */
-       xfs_qm_detach_gdquots(mp);
-
-      again:
-       nmisses = 0;
-       ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp));
-       /*
-        * Try to get rid of all of the unwanted dquots. The idea is to
-        * get them off mplist and hashlist, but leave them on freelist.
-        */
-       dqp = XFS_QI_MPLNEXT(mp);
-       while (dqp) {
-               /*
-                * It's OK to look at the type without taking dqlock here.
-                * We're holding the mplist lock here, and that's needed for
-                * a dqreclaim.
-                */
-               if ((dqp->dq_flags & dqtype) == 0) {
-                       dqp = dqp->MPL_NEXT;
-                       continue;
-               }
-
-               if (! xfs_qm_dqhashlock_nowait(dqp)) {
-                       nrecl = XFS_QI_MPLRECLAIMS(mp);
-                       xfs_qm_mplist_unlock(mp);
-                       XFS_DQ_HASH_LOCK(dqp->q_hash);
-                       xfs_qm_mplist_lock(mp);
-
-                       /*
-                        * XXXTheoretically, we can get into a very long
-                        * ping pong game here.
-                        * No one can be adding dquots to the mplist at
-                        * this point, but somebody might be taking things off.
-                        */
-                       if (nrecl != XFS_QI_MPLRECLAIMS(mp)) {
-                               XFS_DQ_HASH_UNLOCK(dqp->q_hash);
-                               goto again;
-                       }
-               }
-
-               /*
-                * Take the dquot off the mplist and hashlist. It may remain on
-                * freelist in INACTIVE state.
-                */
-               nextdqp = dqp->MPL_NEXT;
-               nmisses += xfs_qm_dqpurge(dqp, flags);
-               dqp = nextdqp;
-       }
-       xfs_qm_mplist_unlock(mp);
-       return (nmisses);
-}
-
-STATIC int
-xfs_qm_dqattach_one(
-       xfs_inode_t     *ip,
-       xfs_dqid_t      id,
-       uint            type,
-       uint            doalloc,
-       uint            dolock,
-       xfs_dquot_t     *udqhint, /* hint */
-       xfs_dquot_t     **IO_idqpp)
-{
-       xfs_dquot_t     *dqp;
-       int             error;
-
-       ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-       error = 0;
-       /*
-        * See if we already have it in the inode itself. IO_idqpp is
-        * &i_udquot or &i_gdquot. This made the code look weird, but
-        * made the logic a lot simpler.
-        */
-       if ((dqp = *IO_idqpp)) {
-               if (dolock)
-                       xfs_dqlock(dqp);
-               xfs_dqtrace_entry(dqp, "DQATTACH: found in ip");
-               goto done;
-       }
-
-       /*
-        * udqhint is the i_udquot field in inode, and is non-NULL only
-        * when the type arg is XFS_DQ_GROUP. Its purpose is to save a
-        * lookup by dqid (xfs_qm_dqget) by caching a group dquot inside
-        * the user dquot.
-        */
-       ASSERT(!udqhint || type == XFS_DQ_GROUP);
-       if (udqhint && !dolock)
-               xfs_dqlock(udqhint);
-
-       /*
-        * No need to take dqlock to look at the id.
-        * The ID can't change until it gets reclaimed, and it won't
-        * be reclaimed as long as we have a ref from inode and we hold
-        * the ilock.
-        */
-       if (udqhint &&
-           (dqp = udqhint->q_gdquot) &&
-           (INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id)) {
-               ASSERT(XFS_DQ_IS_LOCKED(udqhint));
-               xfs_dqlock(dqp);
-               XFS_DQHOLD(dqp);
-               ASSERT(*IO_idqpp == NULL);
-               *IO_idqpp = dqp;
-               if (!dolock) {
-                       xfs_dqunlock(dqp);
-                       xfs_dqunlock(udqhint);
-               }
-               /* XXX XFS_STATS */
-               goto done;
-       }
-       /*
-        * We can't hold a dquot lock when we call the dqget code.
-        * We'll deadlock in no time, because of (not conforming to)
-        * lock ordering - the inodelock comes before any dquot lock,
-        * and we may drop and reacquire the ilock in xfs_qm_dqget().
-        */
-       if (udqhint)
-               xfs_dqunlock(udqhint);
-       /*
-        * Find the dquot from somewhere. This bumps the
-        * reference count of dquot and returns it locked.
-        * This can return ENOENT if dquot didn't exist on
-        * disk and we didn't ask it to allocate;
-        * ESRCH if quotas got turned off suddenly.
-        */
-       if ((error = xfs_qm_dqget(ip->i_mount, ip, id, type,
-                                doalloc|XFS_QMOPT_DOWARN, &dqp))) {
-               if (udqhint && dolock)
-                       xfs_dqlock(udqhint);
-               goto done;
-       }
-
-       xfs_dqtrace_entry(dqp, "DQATTACH: found by dqget");
-       /*
-        * dqget may have dropped and re-acquired the ilock, but it guarantees
-        * that the dquot returned is the one that should go in the inode.
-        */
-       *IO_idqpp = dqp;
-       ASSERT(dqp);
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-       if (! dolock) {
-               xfs_dqunlock(dqp);
-               ASSERT(!udqhint || !XFS_DQ_IS_LOCKED(udqhint));
-               goto done;
-       }
-       if (! udqhint)
-               goto done;
-
-       ASSERT(udqhint);
-       ASSERT(dolock);
-       ASSERT(! XFS_DQ_IS_LOCKED(udqhint));
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-       if (! xfs_qm_dqlock_nowait(udqhint)) {
-               xfs_dqunlock(dqp);
-               xfs_dqlock(udqhint);
-               xfs_dqlock(dqp);
-       }
-      done:
-#ifdef QUOTADEBUG
-       if (udqhint) {
-               if (dolock)
-                       ASSERT(XFS_DQ_IS_LOCKED(udqhint));
-               else
-                       ASSERT(! XFS_DQ_IS_LOCKED(udqhint));
-       }
-       if (! error) {
-               if (dolock)
-                       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-               else
-                       ASSERT(! XFS_DQ_IS_LOCKED(dqp));
-       }
-#endif
-       return (error);
-}
-
-
-/*
- * Given a udquot and gdquot, attach a ptr to the group dquot in the
- * udquot as a hint for future lookups. The idea sounds simple, but the
- * execution isn't, because the udquot might have a group dquot attached
- * already and getting rid of that gets us into lock ordering contraints.
- * The process is complicated more by the fact that the dquots may or may not
- * be locked on entry.
- */
-STATIC void
-xfs_qm_dqattach_grouphint(
-       xfs_dquot_t     *udq,
-       xfs_dquot_t     *gdq,
-       uint            locked)
-{
-       xfs_dquot_t     *tmp;
-
-#ifdef QUOTADEBUG
-       if (locked) {
-               ASSERT(XFS_DQ_IS_LOCKED(udq));
-               ASSERT(XFS_DQ_IS_LOCKED(gdq));
-       } else {
-               ASSERT(! XFS_DQ_IS_LOCKED(udq));
-               ASSERT(! XFS_DQ_IS_LOCKED(gdq));
-       }
-#endif
-       if (! locked)
-               xfs_dqlock(udq);
-
-       if ((tmp = udq->q_gdquot)) {
-               if (tmp == gdq) {
-                       if (! locked)
-                               xfs_dqunlock(udq);
-                       return;
-               }
-
-               udq->q_gdquot = NULL;
-               /*
-                * We can't keep any dqlocks when calling dqrele,
-                * because the freelist lock comes before dqlocks.
-                */
-               xfs_dqunlock(udq);
-               if (locked)
-                       xfs_dqunlock(gdq);
-               /*
-                * we took a hard reference once upon a time in dqget,
-                * so give it back when the udquot no longer points at it
-                * dqput() does the unlocking of the dquot.
-                */
-               xfs_qm_dqrele(tmp);
-
-               ASSERT(! XFS_DQ_IS_LOCKED(udq));
-               ASSERT(! XFS_DQ_IS_LOCKED(gdq));
-               xfs_dqlock(udq);
-               xfs_dqlock(gdq);
-
-       } else {
-               ASSERT(XFS_DQ_IS_LOCKED(udq));
-               if (! locked) {
-                       ASSERT(! XFS_DQ_IS_LOCKED(gdq));
-                       xfs_dqlock(gdq);
-               }
-       }
-
-       ASSERT(XFS_DQ_IS_LOCKED(udq));
-       ASSERT(XFS_DQ_IS_LOCKED(gdq));
-       /*
-        * Somebody could have attached a gdquot here,
-        * when we dropped the uqlock. If so, just do nothing.
-        */
-       if (udq->q_gdquot == NULL) {
-               XFS_DQHOLD(gdq);
-               udq->q_gdquot = gdq;
-       }
-       if (! locked) {
-               xfs_dqunlock(gdq);
-               xfs_dqunlock(udq);
-       }
-}
-
-
-/*
- * Given a locked inode, attach dquot(s) to it, taking UQUOTAON / GQUOTAON
- * in to account.
- * If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed.
- * If XFS_QMOPT_DQLOCK, the dquot(s) will be returned locked. This option pretty
- * much made this code a complete mess, but it has been pretty useful.
- * If XFS_QMOPT_ILOCKED, then inode sent is already locked EXCL.
- * Inode may get unlocked and relocked in here, and the caller must deal with
- * the consequences.
- */
-int
-xfs_qm_dqattach(
-               xfs_inode_t     *ip,
-               uint            flags)
-{
-       int             error;
-       xfs_mount_t     *mp;
-       uint            nquotas;
-
-       mp = ip->i_mount;
-       ASSERT(ip->i_ino != mp->m_sb.sb_uquotino &&
-              ip->i_ino != mp->m_sb.sb_gquotino);
-
-       ASSERT((flags & XFS_QMOPT_ILOCKED) == 0 ||
-              XFS_ISLOCKED_INODE_EXCL(ip));
-
-       nquotas = 0;
-       error = 0;
-       if (! (flags & XFS_QMOPT_ILOCKED))
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-
-       if (XFS_IS_UQUOTA_ON(mp)) {
-               if ((error = xfs_qm_dqattach_one(ip, ip->i_d.di_uid, XFS_DQ_USER,
-                                               flags & XFS_QMOPT_DQALLOC,
-                                               flags & XFS_QMOPT_DQLOCK,
-                                               NULL, &ip->i_udquot)))
-                       goto done;
-               nquotas++;
-       }
-       ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-       if (XFS_IS_GQUOTA_ON(mp)) {
-               if ((error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
-                                               flags & XFS_QMOPT_DQALLOC,
-                                               flags & XFS_QMOPT_DQLOCK,
-                                               ip->i_udquot, &ip->i_gdquot)))
-                       /*
-                        * Don't worry about the udquot that we may have
-                        * attached above. It'll get dettached, if not already.
-                        */
-                       goto done;
-               nquotas++;
-       }
-
-       /*
-        * Attach this group quota to the user quota as a hint.
-        * This WON'T, in general, result in a thrash.
-        */
-       if (nquotas == 2) {
-               ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-               ASSERT(ip->i_udquot);
-               ASSERT(ip->i_gdquot);
-
-               /*
-                * We may or may not have the i_udquot locked at this point,
-                * but this check is OK since we don't depend on the i_gdquot to
-                * be accurate 100% all the time. It is just a hint, and this
-                * will succeed in general.
-                */
-               if (ip->i_udquot->q_gdquot == ip->i_gdquot)
-                       goto done;
-               /*
-                * Attach i_gdquot to the gdquot hint inside the i_udquot.
-                */
-               xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot,
-                                        flags & XFS_QMOPT_DQLOCK);
-       }
-
-      done:
-
-#ifdef QUOTADEBUG
-       if (! error) {
-               if (ip->i_udquot) {
-                       if (flags & XFS_QMOPT_DQLOCK)
-                               ASSERT(XFS_DQ_IS_LOCKED(ip->i_udquot));
-                       else
-                               ASSERT(! XFS_DQ_IS_LOCKED(ip->i_udquot));
-               }
-               if (ip->i_gdquot) {
-                       if (flags & XFS_QMOPT_DQLOCK)
-                               ASSERT(XFS_DQ_IS_LOCKED(ip->i_gdquot));
-                       else
-                               ASSERT(! XFS_DQ_IS_LOCKED(ip->i_gdquot));
-               }
-               if (XFS_IS_UQUOTA_ON(mp))
-                       ASSERT(ip->i_udquot);
-               if (XFS_IS_GQUOTA_ON(mp))
-                       ASSERT(ip->i_gdquot);
-       }
-#endif
-
-       if (! (flags & XFS_QMOPT_ILOCKED))
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-
-#ifdef QUOTADEBUG
-       else
-               ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-#endif
-       return (error);
-}
-
-/*
- * Release dquots (and their references) if any.
- * The inode should be locked EXCL except when this's called by
- * xfs_ireclaim.
- */
-void
-xfs_qm_dqdettach_inode(
-       xfs_inode_t     *ip)
-{
-       ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino);
-       ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino);
-       if (ip->i_udquot)
-               xfs_dqtrace_entry_ino(ip->i_udquot, "DQDETTACH", ip);
-       if (ip->i_udquot) {
-               xfs_qm_dqrele(ip->i_udquot);
-               ip->i_udquot = NULL;
-       }
-       if (ip->i_gdquot) {
-               xfs_qm_dqrele(ip->i_gdquot);
-               ip->i_gdquot = NULL;
-       }
-}
-
-int
-xfs_qm_unmount(
-       xfs_mount_t     *mp)
-{
-       vnode_t         *vp;
-
-       if (XFS_IS_UQUOTA_ON(mp)) {
-               vp = XFS_ITOV(XFS_QI_UQIP(mp));
-               VN_RELE(vp);
-               if (vn_count(vp) > 1)
-                       cmn_err(CE_WARN, "UQUOTA busy vp=0x%x count=%d",
-                               vp, vn_count(vp));
-       }
-       if (XFS_IS_GQUOTA_ON(mp)) {
-               vp = XFS_ITOV(XFS_QI_GQIP(mp));
-               VN_RELE(vp);
-               if (vn_count(vp) > 1)
-                       cmn_err(CE_WARN, "GQUOTA busy vp=0x%x count=%d",
-                               vp, vn_count(vp));
-       }
-
-       return (0);
-}
-
-
-/*
- * This is called by xfs_sync and flags arg determines the caller,
- * and its motives, as done in xfs_sync.
- *
- * vfs_sync: SYNC_FSDATA|SYNC_ATTR|SYNC_BDFLUSH 0x31
- * syscall sync: SYNC_FSDATA|SYNC_ATTR|SYNC_DELWRI 0x25
- * umountroot : SYNC_WAIT | SYNC_CLOSE | SYNC_ATTR | SYNC_FSDATA
- */
-
-int
-xfs_qm_sync(
-       xfs_mount_t     *mp,
-       short           flags)
-{
-       int             recl, restarts;
-       xfs_dquot_t     *dqp;
-       uint            flush_flags;
-       boolean_t       nowait;
-       int             error;
-
-       restarts = 0;
-       /*
-        * We won't block unless we are asked to.
-        */
-       nowait = (boolean_t)(flags & SYNC_BDFLUSH || (flags & SYNC_WAIT) == 0);
-
-  again:
-       xfs_qm_mplist_lock(mp);
-       /*
-        * dqpurge_all() also takes the mplist lock and iterate thru all dquots
-        * in quotaoff. However, if the QUOTA_ACTIVE bits are not cleared
-        * when we have the mplist lock, we know that dquots will be consistent
-        * as long as we have it locked.
-        */
-       if (! XFS_IS_QUOTA_ON(mp)) {
-               xfs_qm_mplist_unlock(mp);
-               return (0);
-       }
-       FOREACH_DQUOT_IN_MP(dqp, mp) {
-               /*
-                * If this is vfs_sync calling, then skip the dquots that
-                * don't 'seem' to be dirty. ie. don't acquire dqlock.
-                * This is very similar to what xfs_sync does with inodes.
-                */
-               if (flags & SYNC_BDFLUSH) {
-                       if (! XFS_DQ_IS_DIRTY(dqp))
-                               continue;
-               }
-
-               if (nowait) {
-                       /*
-                        * Try to acquire the dquot lock. We are NOT out of
-                        * lock order, but we just don't want to wait for this
-                        * lock, unless somebody wanted us to.
-                        */
-                       if (! xfs_qm_dqlock_nowait(dqp))
-                               continue;
-               } else {
-                       xfs_dqlock(dqp);
-               }
-
-               /*
-                * Now, find out for sure if this dquot is dirty or not.
-                */
-               if (! XFS_DQ_IS_DIRTY(dqp)) {
-                       xfs_dqunlock(dqp);
-                       continue;
-               }
-
-               /* XXX a sentinel would be better */
-               recl = XFS_QI_MPLRECLAIMS(mp);
-               if (! xfs_qm_dqflock_nowait(dqp)) {
-                       if (nowait) {
-                               xfs_dqunlock(dqp);
-                               continue;
-                       }
-                       /*
-                        * If we can't grab the flush lock then if the caller
-                        * really wanted us to give this our best shot,
-                        * see if we can give a push to the buffer before we wait
-                        * on the flush lock. At this point, we know that
-                        * eventhough the dquot is being flushed,
-                        * it has (new) dirty data.
-                        */
-                       xfs_qm_dqflock_pushbuf_wait(dqp);
-               }
-               /*
-                * Let go of the mplist lock. We don't want to hold it
-                * across a disk write
-                */
-               flush_flags = (nowait) ? XFS_QMOPT_DELWRI : XFS_QMOPT_SYNC;
-               xfs_qm_mplist_unlock(mp);
-               xfs_dqtrace_entry(dqp, "XQM_SYNC: DQFLUSH");
-               error = xfs_qm_dqflush(dqp, flush_flags);
-               xfs_dqunlock(dqp);
-               if (error && XFS_FORCED_SHUTDOWN(mp))
-                       return(0);      /* Need to prevent umount failure */
-               else if (error)
-                       return (error);
-
-               xfs_qm_mplist_lock(mp);
-               if (recl != XFS_QI_MPLRECLAIMS(mp)) {
-                       if (++restarts >= XFS_QM_SYNC_MAX_RESTARTS)
-                               break;
-
-                       xfs_qm_mplist_unlock(mp);
-                       goto again;
-               }
-       }
-
-       xfs_qm_mplist_unlock(mp);
-       return (0);
-}
-
-
-/*
- * This initializes all the quota information that's kept in the
- * mount structure
- */
-int
-xfs_qm_init_quotainfo(
-       xfs_mount_t     *mp)
-{
-       xfs_quotainfo_t *qinf;
-       int             error;
-       xfs_dquot_t     *dqp;
-
-       ASSERT(XFS_IS_QUOTA_RUNNING(mp));
-
-       /*
-        * Tell XQM that we exist as soon as possible.
-        */
-       if ((error = xfs_qm_hold_quotafs_ref(mp))) {
-               return (error);
-       }
-
-       qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), KM_SLEEP);
-
-       /*
-        * See if quotainodes are setup, and if not, allocate them,
-        * and change the superblock accordingly.
-        */
-       if ((error = xfs_qm_init_quotainos(mp))) {
-               kmem_free(qinf, sizeof(xfs_quotainfo_t));
-               mp->m_quotainfo = NULL;
-               return (error);
-       }
-
-       spinlock_init(&qinf->qi_pinlock, "xfs_qinf_pin");
-       xfs_qm_list_init(&qinf->qi_dqlist, "mpdqlist", 0);
-       qinf->qi_dqreclaims = 0;
-
-       /* mutex used to serialize quotaoffs */
-       mutex_init(&qinf->qi_quotaofflock, MUTEX_DEFAULT, "qoff");
-
-       /* Precalc some constants */
-       qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
-       ASSERT(qinf->qi_dqchunklen);
-       qinf->qi_dqperchunk = BBTOB(qinf->qi_dqchunklen);
-       do_div(qinf->qi_dqperchunk, sizeof(xfs_dqblk_t));
-
-       mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
-
-       /*
-        * We try to get the limits from the superuser's limits fields.
-        * This is quite hacky, but it is standard quota practice.
-        * We look at the USR dquot with id == 0 first, but if user quotas
-        * are not enabled we goto the GRP dquot with id == 0.
-        * We don't really care to keep separate default limits for user
-        * and group quotas, at least not at this point.
-        */
-       error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)0,
-                            (XFS_IS_UQUOTA_RUNNING(mp)) ?
-                            XFS_DQ_USER : XFS_DQ_GROUP,
-                            XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN,
-                            &dqp);
-       if (! error) {
-               /*
-                * The warnings and timers set the grace period given to
-                * a user or group before he or she can not perform any
-                * more writing. If it is zero, a default is used.
-                */
-               qinf->qi_btimelimit = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) ?
-                       INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) : XFS_QM_BTIMELIMIT;
-               qinf->qi_itimelimit = INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) ?
-                       INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) : XFS_QM_ITIMELIMIT;
-               qinf->qi_rtbtimelimit = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) ?
-                       INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) : XFS_QM_RTBTIMELIMIT;
-               qinf->qi_bwarnlimit = INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) ?
-                       INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) : XFS_QM_BWARNLIMIT;
-               qinf->qi_iwarnlimit = INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) ?
-                       INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) : XFS_QM_IWARNLIMIT;
-
-               /*
-                * We sent the XFS_QMOPT_DQSUSER flag to dqget because
-                * we don't want this dquot cached. We haven't done a
-                * quotacheck yet, and quotacheck doesn't like incore dquots.
-                */
-               xfs_qm_dqdestroy(dqp);
-       } else {
-               qinf->qi_btimelimit = XFS_QM_BTIMELIMIT;
-               qinf->qi_itimelimit = XFS_QM_ITIMELIMIT;
-               qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT;
-               qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT;
-               qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT;
-       }
-
-       return (0);
-}
-
-
-/*
- * Gets called when unmounting a filesystem or when all quotas get
- * turned off.
- * This purges the quota inodes, destroys locks and frees itself.
- */
-void
-xfs_qm_destroy_quotainfo(
-       xfs_mount_t     *mp)
-{
-       xfs_quotainfo_t *qi;
-
-       qi = mp->m_quotainfo;
-       ASSERT(qi != NULL);
-       ASSERT(xfs_Gqm != NULL);
-
-       /*
-        * Release the reference that XQM kept, so that we know
-        * when the XQM structure should be freed. We cannot assume
-        * that xfs_Gqm is non-null after this point.
-        */
-       xfs_qm_rele_quotafs_ref(mp);
-
-       spinlock_destroy(&qi->qi_pinlock);
-       xfs_qm_list_destroy(&qi->qi_dqlist);
-
-       if (qi->qi_uquotaip) {
-               XFS_PURGE_INODE(qi->qi_uquotaip);
-               qi->qi_uquotaip = NULL; /* paranoia */
-       }
-       if (qi->qi_gquotaip) {
-               XFS_PURGE_INODE(qi->qi_gquotaip);
-               qi->qi_gquotaip = NULL;
-       }
-       mutex_destroy(&qi->qi_quotaofflock);
-       kmem_free(qi, sizeof(xfs_quotainfo_t));
-       mp->m_quotainfo = NULL;
-}
-
-
-
-/* ------------------- PRIVATE STATIC FUNCTIONS ----------------------- */
-
-/* ARGSUSED */
-STATIC void
-xfs_qm_list_init(
-       xfs_dqlist_t    *list,
-       char            *str,
-       int             n)
-{
-       mutex_init(&list->qh_lock, MUTEX_DEFAULT, str);
-       list->qh_next = NULL;
-       list->qh_version = 0;
-       list->qh_nelems = 0;
-}
-
-STATIC void
-xfs_qm_list_destroy(
-       xfs_dqlist_t    *list)
-{
-       mutex_destroy(&(list->qh_lock));
-}
-
-
-/*
- * Stripped down version of dqattach. This doesn't attach, or even look at the
- * dquots attached to the inode. The rationale is that there won't be any
- * attached at the time this is called from quotacheck.
- */
-STATIC int
-xfs_qm_dqget_noattach(
-       xfs_inode_t     *ip,
-       xfs_dquot_t     **O_udqpp,
-       xfs_dquot_t     **O_gdqpp)
-{
-       int             error;
-       xfs_mount_t     *mp;
-       xfs_dquot_t     *udqp, *gdqp;
-
-       ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-       mp = ip->i_mount;
-       udqp = NULL;
-       gdqp = NULL;
-
-       if (XFS_IS_UQUOTA_ON(mp)) {
-               ASSERT(ip->i_udquot == NULL);
-               /*
-                * We want the dquot allocated if it doesn't exist.
-                */
-               if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_uid, XFS_DQ_USER,
-                                        XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN,
-                                        &udqp))) {
-                       /*
-                        * Shouldn't be able to turn off quotas here.
-                        */
-                       ASSERT(error != ESRCH);
-                       ASSERT(error != ENOENT);
-                       return (error);
-               }
-               ASSERT(udqp);
-       }
-
-       if (XFS_IS_GQUOTA_ON(mp)) {
-               ASSERT(ip->i_gdquot == NULL);
-               if (udqp)
-                       xfs_dqunlock(udqp);
-               if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_gid, XFS_DQ_GROUP,
-                                        XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN,
-                                        &gdqp))) {
-                       if (udqp)
-                               xfs_qm_dqrele(udqp);
-                       ASSERT(error != ESRCH);
-                       ASSERT(error != ENOENT);
-                       return (error);
-               }
-               ASSERT(gdqp);
-
-               /* Reacquire the locks in the right order */
-               if (udqp) {
-                       if (! xfs_qm_dqlock_nowait(udqp)) {
-                               xfs_dqunlock(gdqp);
-                               xfs_dqlock(udqp);
-                               xfs_dqlock(gdqp);
-                       }
-               }
-       }
-
-       *O_udqpp = udqp;
-       *O_gdqpp = gdqp;
-
-#ifdef QUOTADEBUG
-       if (udqp) ASSERT(XFS_DQ_IS_LOCKED(udqp));
-       if (gdqp) ASSERT(XFS_DQ_IS_LOCKED(gdqp));
-#endif
-       return (0);
-}
-
-/*
- * Create an inode and return with a reference already taken, but unlocked
- * This is how we create quota inodes
- */
-STATIC int
-xfs_qm_qino_alloc(
-       xfs_mount_t     *mp,
-       xfs_inode_t     **ip,
-       __int64_t       sbfields,
-       uint            flags)
-{
-       xfs_trans_t     *tp;
-       int             error;
-       unsigned long s;
-       cred_t          zerocr;
-       int             committed;
-
-       tp = xfs_trans_alloc(mp,XFS_TRANS_QM_QINOCREATE);
-       if ((error = xfs_trans_reserve(tp,
-                                     XFS_QM_QINOCREATE_SPACE_RES(mp),
-                                     XFS_CREATE_LOG_RES(mp), 0,
-                                     XFS_TRANS_PERM_LOG_RES,
-                                     XFS_CREATE_LOG_COUNT))) {
-               xfs_trans_cancel(tp, 0);
-               return (error);
-       }
-       memset(&zerocr, 0, sizeof(zerocr));
-
-       if ((error = xfs_dir_ialloc(&tp, mp->m_rootip, IFREG, 1, 0,
-                                  &zerocr, 0, 1, ip, &committed))) {
-               xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
-                                XFS_TRANS_ABORT);
-               return (error);
-       }
-
-       /*
-        * Keep an extra reference to this quota inode. This inode is
-        * locked exclusively and joined to the transaction already.
-        */
-       ASSERT(XFS_ISLOCKED_INODE_EXCL(*ip));
-       VN_HOLD(XFS_ITOV((*ip)));
-
-       /*
-        * Make the changes in the superblock, and log those too.
-        * sbfields arg may contain fields other than *QUOTINO;
-        * VERSIONNUM for example.
-        */
-       s = XFS_SB_LOCK(mp);
-       if (flags & XFS_QMOPT_SBVERSION) {
-#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
-               unsigned oldv = mp->m_sb.sb_versionnum;
-#endif
-               ASSERT(!XFS_SB_VERSION_HASQUOTA(&mp->m_sb));
-               ASSERT((sbfields & (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-                                  XFS_SB_GQUOTINO | XFS_SB_QFLAGS)) ==
-                      (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-                       XFS_SB_GQUOTINO | XFS_SB_QFLAGS));
-
-               XFS_SB_VERSION_ADDQUOTA(&mp->m_sb);
-               mp->m_sb.sb_uquotino = NULLFSINO;
-               mp->m_sb.sb_gquotino = NULLFSINO;
-
-               /* qflags will get updated _after_ quotacheck */
-               mp->m_sb.sb_qflags = 0;
-#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
-               cmn_err(CE_NOTE,
-                       "Old superblock version %x, converting to %x.",
-                       oldv, mp->m_sb.sb_versionnum);
-#endif
-       }
-       if (flags & XFS_QMOPT_UQUOTA)
-               mp->m_sb.sb_uquotino = (*ip)->i_ino;
-       else
-               mp->m_sb.sb_gquotino = (*ip)->i_ino;
-       XFS_SB_UNLOCK(mp, s);
-       xfs_mod_sb(tp, sbfields);
-
-       if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
-                                    NULL))) {
-               xfs_fs_cmn_err(CE_ALERT, mp, "XFS qino_alloc failed!");
-               return (error);
-       }
-       return (0);
-}
-
-
-STATIC int
-xfs_qm_reset_dqcounts(
-       xfs_mount_t     *mp,
-       xfs_buf_t       *bp,
-       xfs_dqid_t      id,
-       uint            type)
-{
-       xfs_disk_dquot_t        *ddq;
-       int                     j;
-
-       xfs_buftrace("RESET DQUOTS", bp);
-       /*
-        * Reset all counters and timers. They'll be
-        * started afresh by xfs_qm_quotacheck.
-        */
-#ifdef DEBUG
-       j = XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
-       do_div(j, sizeof(xfs_dqblk_t));
-       ASSERT(XFS_QM_DQPERBLK(mp) == j);
-#endif
-       ddq = (xfs_disk_dquot_t *)XFS_BUF_PTR(bp);
-       for (j = 0; j < XFS_QM_DQPERBLK(mp); j++) {
-               /*
-                * Do a sanity check, and if needed, repair the dqblk. Don't
-                * output any warnings because it's perfectly possible to
-                * find unitialized dquot blks. See comment in xfs_qm_dqcheck.
-                */
-               (void) xfs_qm_dqcheck(ddq, id+j, type, XFS_QMOPT_DQREPAIR,
-                                     "xfs_quotacheck");
-               INT_SET(ddq->d_bcount, ARCH_CONVERT, 0ULL);
-               INT_SET(ddq->d_icount, ARCH_CONVERT, 0ULL);
-               INT_SET(ddq->d_rtbcount, ARCH_CONVERT, 0ULL);
-               INT_SET(ddq->d_btimer, ARCH_CONVERT, (time_t)0);
-               INT_SET(ddq->d_itimer, ARCH_CONVERT, (time_t)0);
-               INT_SET(ddq->d_bwarns, ARCH_CONVERT, 0UL);
-               INT_SET(ddq->d_iwarns, ARCH_CONVERT, 0UL);
-               ddq = (xfs_disk_dquot_t *) ((xfs_dqblk_t *)ddq + 1);
-       }
-
-       return (0);
-}
-
-STATIC int
-xfs_qm_dqiter_bufs(
-       xfs_mount_t     *mp,
-       xfs_dqid_t      firstid,
-       xfs_fsblock_t   bno,
-       xfs_filblks_t   blkcnt,
-       uint            flags)
-{
-       xfs_buf_t       *bp;
-       int             error;
-       int             notcommitted;
-       int             incr;
-
-       ASSERT(blkcnt > 0);
-       notcommitted = 0;
-       incr = (blkcnt > XFS_QM_MAX_DQCLUSTER_LOGSZ) ?
-               XFS_QM_MAX_DQCLUSTER_LOGSZ : blkcnt;
-       error = 0;
-
-       /*
-        * Blkcnt arg can be a very big number, and might even be
-        * larger than the log itself. So, we have to break it up into
-        * manageable-sized transactions.
-        * Note that we don't start a permanent transaction here; we might
-        * not be able to get a log reservation for the whole thing up front,
-        * and we don't really care to either, because we just discard
-        * everything if we were to crash in the middle of this loop.
-        */
-       while (blkcnt--) {
-               error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
-                             XFS_FSB_TO_DADDR(mp, bno),
-                             (int)XFS_QI_DQCHUNKLEN(mp), 0, &bp);
-               if (error)
-                       break;
-
-               (void) xfs_qm_reset_dqcounts(mp, bp, firstid,
-                                            flags & XFS_QMOPT_UQUOTA ?
-                                            XFS_DQ_USER : XFS_DQ_GROUP);
-               xfs_bdwrite(mp, bp);
-               /*
-                * goto the next block.
-                */
-               bno++;
-               firstid += XFS_QM_DQPERBLK(mp);
-       }
-       return (error);
-}
-
-/*
- * Iterate over all allocated USR/GRP dquots in the system, calling a
- * caller supplied function for every chunk of dquots that we find.
- */
-STATIC int
-xfs_qm_dqiterate(
-       xfs_mount_t     *mp,
-       xfs_inode_t     *qip,
-       uint            flags)
-{
-       xfs_bmbt_irec_t         *map;
-       int                     i, nmaps;       /* number of map entries */
-       int                     error;          /* return value */
-       xfs_fileoff_t           lblkno;
-       xfs_filblks_t           maxlblkcnt;
-       xfs_dqid_t              firstid;
-       xfs_fsblock_t           rablkno;
-       xfs_filblks_t           rablkcnt;
-
-       error = 0;
-       /*
-        * This looks racey, but we can't keep an inode lock across a
-        * trans_reserve. But, this gets called during quotacheck, and that
-        * happens only at mount time which is single threaded.
-        */
-       if (qip->i_d.di_nblocks == 0)
-               return (0);
-
-       map = kmem_alloc(XFS_DQITER_MAP_SIZE * sizeof(*map), KM_SLEEP);
-
-       lblkno = 0;
-       maxlblkcnt = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAX_FILE_OFFSET);
-       do {
-               nmaps = XFS_DQITER_MAP_SIZE;
-               /*
-                * We aren't changing the inode itself. Just changing
-                * some of its data. No new blocks are added here, and
-                * the inode is never added to the transaction.
-                */
-               xfs_ilock(qip, XFS_ILOCK_SHARED);
-               error = xfs_bmapi(NULL, qip, lblkno,
-                                 maxlblkcnt - lblkno,
-                                 XFS_BMAPI_METADATA,
-                                 NULL,
-                                 0, map, &nmaps, NULL);
-               xfs_iunlock(qip, XFS_ILOCK_SHARED);
-               if (error)
-                       break;
-
-               ASSERT(nmaps <= XFS_DQITER_MAP_SIZE);
-               for (i = 0; i < nmaps; i++) {
-                       ASSERT(map[i].br_startblock != DELAYSTARTBLOCK);
-                       ASSERT(map[i].br_blockcount);
-
-
-                       lblkno += map[i].br_blockcount;
-
-                       if (map[i].br_startblock == HOLESTARTBLOCK)
-                               continue;
-
-                       firstid = (xfs_dqid_t) map[i].br_startoff *
-                               XFS_QM_DQPERBLK(mp);
-                       /*
-                        * Do a read-ahead on the next extent.
-                        */
-                       if ((i+1 < nmaps) &&
-                           (map[i+1].br_startblock != HOLESTARTBLOCK)) {
-                               rablkcnt =  map[i+1].br_blockcount;
-                               rablkno = map[i+1].br_startblock;
-                               while (rablkcnt--) {
-                                       xfs_baread(mp->m_ddev_targp,
-                                              XFS_FSB_TO_DADDR(mp, rablkno),
-                                              (int)XFS_QI_DQCHUNKLEN(mp));
-                                       rablkno++;
-                               }
-                       }
-                       /*
-                        * Iterate thru all the blks in the extent and
-                        * reset the counters of all the dquots inside them.
-                        */
-                       if ((error = xfs_qm_dqiter_bufs(mp,
-                                                      firstid,
-                                                      map[i].br_startblock,
-                                                      map[i].br_blockcount,
-                                                      flags))) {
-                               break;
-                       }
-               }
-
-               if (error)
-                       break;
-       } while (nmaps > 0);
-
-       kmem_free(map, XFS_DQITER_MAP_SIZE * sizeof(*map));
-
-       return (error);
-}
-
-/*
- * Called by dqusage_adjust in doing a quotacheck.
- * Given the inode, and a dquot (either USR or GRP, doesn't matter),
- * this updates its incore copy as well as the buffer copy. This is
- * so that once the quotacheck is done, we can just log all the buffers,
- * as opposed to logging numerous updates to individual dquots.
- */
-STATIC void
-xfs_qm_quotacheck_dqadjust(
-       xfs_dquot_t             *dqp,
-       xfs_qcnt_t              nblks,
-       xfs_qcnt_t              rtblks)
-{
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-       xfs_dqtrace_entry(dqp, "QCHECK DQADJUST");
-       /*
-        * Adjust the inode count and the block count to reflect this inode's
-        * resource usage.
-        */
-       INT_MOD(dqp->q_core.d_icount, ARCH_CONVERT, +1);
-       dqp->q_res_icount++;
-       if (nblks) {
-               INT_MOD(dqp->q_core.d_bcount, ARCH_CONVERT, nblks);
-               dqp->q_res_bcount += nblks;
-       }
-       if (rtblks) {
-               INT_MOD(dqp->q_core.d_rtbcount, ARCH_CONVERT, rtblks);
-               dqp->q_res_rtbcount += rtblks;
-       }
-
-       /*
-        * Adjust the timers since we just changed usages
-        */
-       if (! XFS_IS_SUSER_DQUOT(dqp))
-               xfs_qm_adjust_dqtimers(dqp->q_mount, &dqp->q_core);
-
-       dqp->dq_flags |= XFS_DQ_DIRTY;
-}
-
-STATIC int
-xfs_qm_get_rtblks(
-       xfs_inode_t     *ip,
-       xfs_qcnt_t      *O_rtblks)
-{
-       xfs_filblks_t   rtblks;                 /* total rt blks */
-       xfs_ifork_t     *ifp;                   /* inode fork pointer */
-       xfs_extnum_t    nextents;               /* number of extent entries */
-       xfs_bmbt_rec_t  *base;                  /* base of extent array */
-       xfs_bmbt_rec_t  *ep;                    /* pointer to an extent entry */
-       int             error;
-
-       ASSERT(XFS_IS_REALTIME_INODE(ip));
-       ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
-       if (!(ifp->if_flags & XFS_IFEXTENTS)) {
-               if ((error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK)))
-                       return (error);
-       }
-       rtblks = 0;
-       nextents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t);
-       base = &ifp->if_u1.if_extents[0];
-       for (ep = base; ep < &base[nextents]; ep++)
-               rtblks += xfs_bmbt_get_blockcount(ep);
-       *O_rtblks = (xfs_qcnt_t)rtblks;
-       return (0);
-}
-
-/*
- * callback routine supplied to bulkstat(). Given an inumber, find its
- * dquots and update them to account for resources taken by that inode.
- */
-/* ARGSUSED */
-STATIC int
-xfs_qm_dqusage_adjust(
-       xfs_mount_t     *mp,            /* mount point for filesystem */
-       xfs_trans_t     *tp,            /* transaction pointer - NULL */
-       xfs_ino_t       ino,            /* inode number to get data for */
-       void            *buffer,        /* not used */
-       xfs_daddr_t     bno,            /* starting block of inode cluster */
-       void            *dip,           /* on-disk inode pointer (not used) */
-       int             *res)           /* result code value */
-{
-       xfs_inode_t     *ip;
-       xfs_dquot_t     *udqp, *gdqp;
-       xfs_qcnt_t      nblks, rtblks;
-       int             error;
-
-       ASSERT(XFS_IS_QUOTA_RUNNING(mp));
-
-       /*
-        * rootino must have its resources accounted for, not so with the quota
-        * inodes.
-        */
-       if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
-               *res = BULKSTAT_RV_NOTHING;
-               return XFS_ERROR(EINVAL);
-       }
-
-       /*
-        * We don't _need_ to take the ilock EXCL. However, the xfs_qm_dqget
-        * interface expects the inode to be exclusively locked because that's
-        * the case in all other instances. It's OK that we do this because
-        * quotacheck is done only at mount time.
-        */
-       if ((error = xfs_iget(mp, tp, ino, XFS_ILOCK_EXCL, &ip, bno))) {
-               *res = BULKSTAT_RV_NOTHING;
-               return (error);
-       }
-
-       if (ip->i_d.di_mode == 0) {
-               xfs_iput_new(ip, XFS_ILOCK_EXCL);
-               *res = BULKSTAT_RV_NOTHING;
-               return XFS_ERROR(ENOENT);
-       }
-
-       /*
-        * Obtain the locked dquots. In case of an error (eg. allocation
-        * fails for ENOSPC), we return the negative of the error number
-        * to bulkstat, so that it can get propagated to quotacheck() and
-        * making us disable quotas for the file system.
-        */
-       if ((error = xfs_qm_dqget_noattach(ip, &udqp, &gdqp))) {
-               xfs_iput(ip, XFS_ILOCK_EXCL);
-               *res = BULKSTAT_RV_GIVEUP;
-               return (error);
-       }
-
-       rtblks = 0;
-       if (! XFS_IS_REALTIME_INODE(ip)) {
-               nblks = (xfs_qcnt_t)ip->i_d.di_nblocks;
-       } else {
-               /*
-                * Walk thru the extent list and count the realtime blocks.
-                */
-               if ((error = xfs_qm_get_rtblks(ip, &rtblks))) {
-                       xfs_iput(ip, XFS_ILOCK_EXCL);
-                       if (udqp)
-                               xfs_qm_dqput(udqp);
-                       if (gdqp)
-                               xfs_qm_dqput(gdqp);
-                       *res = BULKSTAT_RV_GIVEUP;
-                       return (error);
-               }
-               nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks;
-       }
-       ASSERT(ip->i_delayed_blks == 0);
-
-       /*
-        * We can't release the inode while holding its dquot locks.
-        * The inode can go into inactive and might try to acquire the dquotlocks.
-        * So, just unlock here and do a vn_rele at the end.
-        */
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-
-       /*
-        * Add the (disk blocks and inode) resources occupied by this
-        * inode to its dquots. We do this adjustment in the incore dquot,
-        * and also copy the changes to its buffer.
-        * We don't care about putting these changes in a transaction
-        * envelope because if we crash in the middle of a 'quotacheck'
-        * we have to start from the beginning anyway.
-        * Once we're done, we'll log all the dquot bufs.
-        *
-        * The *QUOTA_ON checks below may look pretty racey, but quotachecks
-        * and quotaoffs don't race. (Quotachecks happen at mount time only).
-        */
-       if (XFS_IS_UQUOTA_ON(mp)) {
-               ASSERT(udqp);
-               xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks);
-               xfs_qm_dqput(udqp);
-       }
-       if (XFS_IS_GQUOTA_ON(mp)) {
-               ASSERT(gdqp);
-               xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks);
-               xfs_qm_dqput(gdqp);
-       }
-       /*
-        * Now release the inode. This will send it to 'inactive', and
-        * possibly even free blocks.
-        */
-       VN_RELE(XFS_ITOV(ip));
-
-       /*
-        * Goto next inode.
-        */
-       *res = BULKSTAT_RV_DIDONE;
-       return (0);
-}
-
-/*
- * Walk thru all the filesystem inodes and construct a consistent view
- * of the disk quota world.
- */
-STATIC int
-xfs_qm_quotacheck(
-       xfs_mount_t     *mp)
-{
-       int             done, count, error;
-       xfs_ino_t       lastino;
-       size_t          structsz;
-       xfs_inode_t     *uip, *gip;
-       uint            flags;
-
-       count = INT_MAX;
-       structsz = 1;
-       lastino = 0;
-       flags = 0;
-
-       ASSERT(XFS_QI_UQIP(mp) || XFS_QI_GQIP(mp));
-       ASSERT(XFS_IS_QUOTA_RUNNING(mp));
-
-       /*
-        * There should be no cached dquots. The (simplistic) quotacheck
-        * algorithm doesn't like that.
-        */
-       ASSERT(XFS_QI_MPLNDQUOTS(mp) == 0);
-
-       cmn_err(CE_NOTE, "XFS quotacheck %s: Please wait.", mp->m_fsname);
-
-       /*
-        * First we go thru all the dquots on disk, USR and GRP, and reset
-        * their counters to zero. We need a clean slate.
-        * We don't log our changes till later.
-        */
-       if ((uip = XFS_QI_UQIP(mp))) {
-               if ((error = xfs_qm_dqiterate(mp, uip, XFS_QMOPT_UQUOTA)))
-                       goto error_return;
-               flags |= XFS_UQUOTA_CHKD;
-       }
-
-       if ((gip = XFS_QI_GQIP(mp))) {
-               if ((error = xfs_qm_dqiterate(mp, gip, XFS_QMOPT_GQUOTA)))
-                       goto error_return;
-               flags |= XFS_GQUOTA_CHKD;
-       }
-
-       do {
-               /*
-                * Iterate thru all the inodes in the file system,
-                * adjusting the corresponding dquot counters in core.
-                */
-               if ((error = xfs_bulkstat(mp, NULL, &lastino, &count,
-                                    xfs_qm_dqusage_adjust,
-                                    structsz, NULL,
-                                    BULKSTAT_FG_IGET|BULKSTAT_FG_VFSLOCKED,
-                                    &done)))
-                       break;
-
-       } while (! done);
-
-       /*
-        * We can get this error if we couldn't do a dquot allocation inside
-        * xfs_qm_dqusage_adjust (via bulkstat). We don't care about the
-        * dirty dquots that might be cached, we just want to get rid of them
-        * and turn quotaoff. The dquots won't be attached to any of the inodes
-        * at this point (because we intentionally didn't in dqget_noattach).
-        */
-       if (error) {
-               xfs_qm_dqpurge_all(mp,
-                                  XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA|
-                                  XFS_QMOPT_QUOTAOFF);
-               goto error_return;
-       }
-       /*
-        * We've made all the changes that we need to make incore.
-        * Now flush_them down to disk buffers.
-        */
-       xfs_qm_dqflush_all(mp, XFS_QMOPT_DELWRI);
-
-       /*
-        * We didn't log anything, because if we crashed, we'll have to
-        * start the quotacheck from scratch anyway. However, we must make
-        * sure that our dquot changes are secure before we put the
-        * quotacheck'd stamp on the superblock. So, here we do a synchronous
-        * flush.
-        */
-       XFS_bflush(mp->m_ddev_targp);
-
-       /*
-        * If one type of quotas is off, then it will lose its
-        * quotachecked status, since we won't be doing accounting for
-        * that type anymore.
-        */
-       mp->m_qflags &= ~(XFS_GQUOTA_CHKD | XFS_UQUOTA_CHKD);
-       mp->m_qflags |= flags;
-
-#ifdef QUOTADEBUG
-       XQM_LIST_PRINT(&(XFS_QI_MPL_LIST(mp)), MPL_NEXT, "++++ Mp list +++");
-#endif
-
- error_return:
-       cmn_err(CE_NOTE, "XFS quotacheck %s: Done.", mp->m_fsname);
-       return (error);
-}
-
-/*
- * This is called after the superblock has been read in and we're ready to
- * iget the quota inodes.
- */
-STATIC int
-xfs_qm_init_quotainos(
-       xfs_mount_t     *mp)
-{
-       xfs_inode_t     *uip, *gip;
-       int             error;
-       __int64_t       sbflags;
-       uint            flags;
-
-       ASSERT(mp->m_quotainfo);
-       uip = gip = NULL;
-       sbflags = 0;
-       flags = 0;
-
-       /*
-        * Get the uquota and gquota inodes
-        */
-       if (XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) {
-               if (XFS_IS_UQUOTA_ON(mp) &&
-                   mp->m_sb.sb_uquotino != NULLFSINO) {
-                       ASSERT(mp->m_sb.sb_uquotino > 0);
-                       if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
-                                            0, &uip, 0)))
-                               return XFS_ERROR(error);
-               }
-               if (XFS_IS_GQUOTA_ON(mp) &&
-                   mp->m_sb.sb_gquotino != NULLFSINO) {
-                       ASSERT(mp->m_sb.sb_gquotino > 0);
-                       if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
-                                            0, &gip, 0))) {
-                               if (uip)
-                                       VN_RELE(XFS_ITOV(uip));
-                               return XFS_ERROR(error);
-                       }
-               }
-       } else {
-               flags |= XFS_QMOPT_SBVERSION;
-               sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-                           XFS_SB_GQUOTINO | XFS_SB_QFLAGS);
-       }
-
-       /*
-        * Create the two inodes, if they don't exist already. The changes
-        * made above will get added to a transaction and logged in one of
-        * the qino_alloc calls below.  If the device is readonly,
-        * temporarily switch to read-write to do this.
-        */
-       if (XFS_IS_UQUOTA_ON(mp) && uip == NULL) {
-               if ((error = xfs_qm_qino_alloc(mp, &uip,
-                                             sbflags | XFS_SB_UQUOTINO,
-                                             flags | XFS_QMOPT_UQUOTA)))
-                       return XFS_ERROR(error);
-
-               flags &= ~XFS_QMOPT_SBVERSION;
-       }
-       if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) {
-               if ((error = xfs_qm_qino_alloc(mp, &gip,
-                                             sbflags | XFS_SB_GQUOTINO,
-                                             flags | XFS_QMOPT_GQUOTA))) {
-                       if (uip)
-                               VN_RELE(XFS_ITOV(uip));
-
-                       return XFS_ERROR(error);
-               }
-       }
-
-       XFS_QI_UQIP(mp) = uip;
-       XFS_QI_GQIP(mp) = gip;
-
-       return (0);
-}
-
-
-/*
- * Traverse the freelist of dquots and attempt to reclaim a maximum of
- * 'howmany' dquots. This operation races with dqlookup(), and attempts to
- * favor the lookup function ...
- * XXXsup merge this with qm_reclaim_one().
- */
-STATIC int
-xfs_qm_shake_freelist(
-       int howmany)
-{
-       int             nreclaimed;
-       xfs_dqhash_t    *hash;
-       xfs_dquot_t     *dqp, *nextdqp;
-       int             restarts;
-       int             nflushes;
-
-       if (howmany <= 0)
-               return (0);
-
-       nreclaimed = 0;
-       restarts = 0;
-       nflushes = 0;
-
-#ifdef QUOTADEBUG
-       printk("Shake free 0x%x\n", howmany);
-#endif
-       /* lock order is : hashchainlock, freelistlock, mplistlock */
- tryagain:
-       xfs_qm_freelist_lock(xfs_Gqm);
-
-       for (dqp = xfs_Gqm->qm_dqfreelist.qh_next;
-            ((dqp != (xfs_dquot_t *) &xfs_Gqm->qm_dqfreelist) &&
-             nreclaimed < howmany); ) {
-               xfs_dqlock(dqp);
-
-               /*
-                * We are racing with dqlookup here. Naturally we don't
-                * want to reclaim a dquot that lookup wants.
-                */
-               if (dqp->dq_flags & XFS_DQ_WANT) {
-                       xfs_dqunlock(dqp);
-                       xfs_qm_freelist_unlock(xfs_Gqm);
-                       if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
-                               return (nreclaimed != howmany);
-                       XFS_STATS_INC(xfsstats.xs_qm_dqwants);
-                       goto tryagain;
-               }
-
-               /*
-                * If the dquot is inactive, we are assured that it is
-                * not on the mplist or the hashlist, and that makes our
-                * life easier.
-                */
-               if (dqp->dq_flags & XFS_DQ_INACTIVE) {
-                       ASSERT(dqp->q_mount == NULL);
-                       ASSERT(! XFS_DQ_IS_DIRTY(dqp));
-                       ASSERT(dqp->HL_PREVP == NULL);
-                       ASSERT(dqp->MPL_PREVP == NULL);
-                       XFS_STATS_INC(xfsstats.xs_qm_dqinact_reclaims);
-                       nextdqp = dqp->dq_flnext;
-                       goto off_freelist;
-               }
-
-               ASSERT(dqp->MPL_PREVP);
-               /*
-                * Try to grab the flush lock. If this dquot is in the process of
-                * getting flushed to disk, we don't want to reclaim it.
-                */
-               if (! xfs_qm_dqflock_nowait(dqp)) {
-                       xfs_dqunlock(dqp);
-                       dqp = dqp->dq_flnext;
-                       continue;
-               }
-
-               /*
-                * We have the flush lock so we know that this is not in the
-                * process of being flushed. So, if this is dirty, flush it
-                * DELWRI so that we don't get a freelist infested with
-                * dirty dquots.
-                */
-               if (XFS_DQ_IS_DIRTY(dqp)) {
-                       xfs_dqtrace_entry(dqp, "DQSHAKE: DQDIRTY");
-                       /*
-                        * We flush it delayed write, so don't bother
-                        * releasing the mplock.
-                        */
-                       (void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI);
-                       xfs_dqunlock(dqp); /* dqflush unlocks dqflock */
-                       dqp = dqp->dq_flnext;
-                       continue;
-               }
-               /*
-                * We're trying to get the hashlock out of order. This races
-                * with dqlookup; so, we giveup and goto the next dquot if
-                * we couldn't get the hashlock. This way, we won't starve
-                * a dqlookup process that holds the hashlock that is
-                * waiting for the freelist lock.
-                */
-               if (! xfs_qm_dqhashlock_nowait(dqp)) {
-                       xfs_dqfunlock(dqp);
-                       xfs_dqunlock(dqp);
-                       dqp = dqp->dq_flnext;
-                       continue;
-               }
-               /*
-                * This races with dquot allocation code as well as dqflush_all
-                * and reclaim code. So, if we failed to grab the mplist lock,
-                * giveup everything and start over.
-                */
-               hash = dqp->q_hash;
-               ASSERT(hash);
-               if (! xfs_qm_mplist_nowait(dqp->q_mount)) {
-                       /* XXX put a sentinel so that we can come back here */
-                       xfs_dqfunlock(dqp);
-                       xfs_dqunlock(dqp);
-                       XFS_DQ_HASH_UNLOCK(hash);
-                       xfs_qm_freelist_unlock(xfs_Gqm);
-                       if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
-                               return (nreclaimed != howmany);
-                       goto tryagain;
-               }
-               xfs_dqtrace_entry(dqp, "DQSHAKE: UNLINKING");
-#ifdef QUOTADEBUG
-               printk("Shake 0x%p, ID 0x%x\n", dqp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT));
-#endif
-               ASSERT(dqp->q_nrefs == 0);
-               nextdqp = dqp->dq_flnext;
-               XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp);
-               XQM_HASHLIST_REMOVE(hash, dqp);
-               xfs_dqfunlock(dqp);
-               xfs_qm_mplist_unlock(dqp->q_mount);
-               XFS_DQ_HASH_UNLOCK(hash);
-
- off_freelist:
-               XQM_FREELIST_REMOVE(dqp);
-               xfs_dqunlock(dqp);
-               nreclaimed++;
-               XFS_STATS_INC(xfsstats.xs_qm_dqshake_reclaims);
-               xfs_qm_dqdestroy(dqp);
-               dqp = nextdqp;
-       }
-       xfs_qm_freelist_unlock(xfs_Gqm);
-       return (nreclaimed != howmany);
-}
-
-
-/*
- * The shake manager routine called by shaked() when memory is
- * running low.
- */
-/* ARGSUSED */
-STATIC void
-xfs_qm_shake(void)
-{
-       int     ndqused, nfree, n;
-
-       if (!xfs_Gqm)
-               return;
-
-       nfree = xfs_Gqm->qm_dqfreelist.qh_nelems; /* free dquots */
-       /* incore dquots in all f/s's */
-       ndqused = atomic_read(&xfs_Gqm->qm_totaldquots) - nfree;
-
-       ASSERT(ndqused >= 0);
-
-       if (nfree <= ndqused && nfree < ndquot)
-               return;
-
-       ndqused *= xfs_Gqm->qm_dqfree_ratio;    /* target # of free dquots */
-       n = nfree - ndqused - ndquot;           /* # over target */
-
-       (void) xfs_qm_shake_freelist(MAX(nfree, n));
-}
-
-
-/*
- * Just pop the least recently used dquot off the freelist and
- * recycle it. The returned dquot is locked.
- */
-STATIC xfs_dquot_t *
-xfs_qm_dqreclaim_one(void)
-{
-       xfs_dquot_t     *dqpout;
-       xfs_dquot_t     *dqp;
-       int             restarts;
-       int             nflushes;
-
-       restarts = 0;
-       dqpout = NULL;
-       nflushes = 0;
-
-       /* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */
- startagain:
-       xfs_qm_freelist_lock(xfs_Gqm);
-
-       FOREACH_DQUOT_IN_FREELIST(dqp, &(xfs_Gqm->qm_dqfreelist)) {
-               xfs_dqlock(dqp);
-
-               /*
-                * We are racing with dqlookup here. Naturally we don't
-                * want to reclaim a dquot that lookup wants. We release the
-                * freelist lock and start over, so that lookup will grab
-                * both the dquot and the freelistlock.
-                */
-               if (dqp->dq_flags & XFS_DQ_WANT) {
-                       ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE));
-                       xfs_dqtrace_entry(dqp, "DQRECLAIM: DQWANT");
-                       xfs_dqunlock(dqp);
-                       xfs_qm_freelist_unlock(xfs_Gqm);
-                       if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
-                               return (NULL);
-                       XFS_STATS_INC(xfsstats.xs_qm_dqwants);
-                       goto startagain;
-               }
-
-               /*
-                * If the dquot is inactive, we are assured that it is
-                * not on the mplist or the hashlist, and that makes our
-                * life easier.
-                */
-               if (dqp->dq_flags & XFS_DQ_INACTIVE) {
-                       ASSERT(dqp->q_mount == NULL);
-                       ASSERT(! XFS_DQ_IS_DIRTY(dqp));
-                       ASSERT(dqp->HL_PREVP == NULL);
-                       ASSERT(dqp->MPL_PREVP == NULL);
-                       XQM_FREELIST_REMOVE(dqp);
-                       xfs_dqunlock(dqp);
-                       dqpout = dqp;
-                       XFS_STATS_INC(xfsstats.xs_qm_dqinact_reclaims);
-                       break;
-               }
-
-               ASSERT(dqp->q_hash);
-               ASSERT(dqp->MPL_PREVP);
-
-               /*
-                * Try to grab the flush lock. If this dquot is in the process of
-                * getting flushed to disk, we don't want to reclaim it.
-                */
-               if (! xfs_qm_dqflock_nowait(dqp)) {
-                       xfs_dqunlock(dqp);
-                       continue;
-               }
-
-               /*
-                * We have the flush lock so we know that this is not in the
-                * process of being flushed. So, if this is dirty, flush it
-                * DELWRI so that we don't get a freelist infested with
-                * dirty dquots.
-                */
-               if (XFS_DQ_IS_DIRTY(dqp)) {
-                       xfs_dqtrace_entry(dqp, "DQRECLAIM: DQDIRTY");
-                       /*
-                        * We flush it delayed write, so don't bother
-                        * releasing the freelist lock.
-                        */
-                       (void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI);
-                       xfs_dqunlock(dqp); /* dqflush unlocks dqflock */
-                       continue;
-               }
-
-               if (! xfs_qm_mplist_nowait(dqp->q_mount)) {
-                       xfs_dqfunlock(dqp);
-                       xfs_dqunlock(dqp);
-                       continue;
-               }
-
-               if (! xfs_qm_dqhashlock_nowait(dqp))
-                       goto mplistunlock;
-
-               ASSERT(dqp->q_nrefs == 0);
-               xfs_dqtrace_entry(dqp, "DQRECLAIM: UNLINKING");
-               XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp);
-               XQM_HASHLIST_REMOVE(dqp->q_hash, dqp);
-               XQM_FREELIST_REMOVE(dqp);
-               dqpout = dqp;
-               XFS_DQ_HASH_UNLOCK(dqp->q_hash);
- mplistunlock:
-               xfs_qm_mplist_unlock(dqp->q_mount);
-               xfs_dqfunlock(dqp);
-               xfs_dqunlock(dqp);
-               if (dqpout)
-                       break;
-       }
-
-       xfs_qm_freelist_unlock(xfs_Gqm);
-       return (dqpout);
-}
-
-
-/*------------------------------------------------------------------*/
-
-/*
- * Return a new incore dquot. Depending on the number of
- * dquots in the system, we either allocate a new one on the kernel heap,
- * or reclaim a free one.
- * Return value is B_TRUE if we allocated a new dquot, B_FALSE if we managed
- * to reclaim an existing one from the freelist.
- */
-boolean_t
-xfs_qm_dqalloc_incore(
-       xfs_dquot_t **O_dqpp)
-{
-       xfs_dquot_t     *dqp;
-
-       /*
-        * Check against high water mark to see if we want to pop
-        * a nincompoop dquot off the freelist.
-        */
-       if (atomic_read(&xfs_Gqm->qm_totaldquots) >= ndquot) {
-               /*
-                * Try to recycle a dquot from the freelist.
-                */
-               if ((dqp = xfs_qm_dqreclaim_one())) {
-                       XFS_STATS_INC(xfsstats.xs_qm_dqreclaims);
-                       /*
-                        * Just zero the core here. The rest will get
-                        * reinitialized by caller. XXX we shouldn't even
-                        * do this zero ...
-                        */
-                       memset(&dqp->q_core, 0, sizeof(dqp->q_core));
-                       *O_dqpp = dqp;
-                       return (B_FALSE);
-               }
-               XFS_STATS_INC(xfsstats.xs_qm_dqreclaim_misses);
-       }
-
-       /*
-        * Allocate a brand new dquot on the kernel heap and return it
-        * to the caller to initialize.
-        */
-       ASSERT(xfs_Gqm->qm_dqzone != NULL);
-       *O_dqpp = kmem_zone_zalloc(xfs_Gqm->qm_dqzone, KM_SLEEP);
-       atomic_inc(&xfs_Gqm->qm_totaldquots);
-
-       return (B_TRUE);
-}
-
-
-/*
- * Start a transaction and write the incore superblock changes to
- * disk. flags parameter indicates which fields have changed.
- */
-int
-xfs_qm_write_sb_changes(
-       xfs_mount_t     *mp,
-       __int64_t       flags)
-{
-       xfs_trans_t     *tp;
-       int             error;
-
-#ifdef QUOTADEBUG
-       cmn_err(CE_NOTE,
-               "Writing superblock quota changes :%s",
-               mp->m_fsname);
-#endif
-       tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
-       if ((error = xfs_trans_reserve(tp, 0,
-                                     mp->m_sb.sb_sectsize + 128, 0,
-                                     0,
-                                     XFS_DEFAULT_LOG_COUNT))) {
-               xfs_trans_cancel(tp, 0);
-               return (error);
-       }
-
-       xfs_mod_sb(tp, flags);
-       (void) xfs_trans_commit(tp, 0, NULL);
-
-       return (0);
-}
-
-
-/* --------------- utility functions for vnodeops ---------------- */
-
-
-/*
- * Given an inode, a uid and gid (from cred_t) make sure that we have
- * allocated relevant dquot(s) on disk, and that we won't exceed inode
- * quotas by creating this file.
- * This also attaches dquot(s) to the given inode after locking it,
- * and returns the dquots corresponding to the uid and/or gid.
- *
- * in  : inode (unlocked)
- * out : udquot, gdquot with references taken and unlocked
- */
-int
-xfs_qm_vop_dqalloc(
-       xfs_mount_t     *mp,
-       xfs_inode_t     *ip,
-       uid_t           uid,
-       gid_t           gid,
-       uint            flags,
-       xfs_dquot_t     **O_udqpp,
-       xfs_dquot_t     **O_gdqpp)
-{
-       int             error;
-       xfs_dquot_t     *uq, *gq;
-       uint            lockflags;
-
-       lockflags = XFS_ILOCK_EXCL;
-       xfs_ilock(ip, lockflags);
-
-       if ((flags & XFS_QMOPT_INHERIT) &&
-           XFS_INHERIT_GID(ip, XFS_MTOVFS(mp)))
-               gid = ip->i_d.di_gid;
-
-       /*
-        * Attach the dquot(s) to this inode, doing a dquot allocation
-        * if necessary. The dquot(s) will not be locked.
-        */
-       if (XFS_NOT_DQATTACHED(mp, ip)) {
-               if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_DQALLOC |
-                                           XFS_QMOPT_ILOCKED))) {
-                       xfs_iunlock(ip, lockflags);
-                       return (error);
-               }
-       }
-
-       uq = gq = NULL;
-       if ((flags & XFS_QMOPT_UQUOTA) &&
-           XFS_IS_UQUOTA_ON(mp)) {
-               if (ip->i_d.di_uid != uid) {
-                       /*
-                        * What we need is the dquot that has this uid, and
-                        * if we send the inode to dqget, the uid of the inode
-                        * takes priority over what's sent in the uid argument.
-                        * We must unlock inode here before calling dqget if
-                        * we're not sending the inode, because otherwise
-                        * we'll deadlock by doing trans_reserve while
-                        * holding ilock.
-                        */
-                       xfs_iunlock(ip, lockflags);
-                       if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t) uid,
-                                                XFS_DQ_USER,
-                                                XFS_QMOPT_DQALLOC |
-                                                XFS_QMOPT_DOWARN,
-                                                &uq))) {
-                               ASSERT(error != ENOENT);
-                               return (error);
-                       }
-                       /*
-                        * Get the ilock in the right order.
-                        */
-                       xfs_dqunlock(uq);
-                       lockflags = XFS_ILOCK_SHARED;
-                       xfs_ilock(ip, lockflags);
-               } else {
-                       /*
-                        * Take an extra reference, because we'll return
-                        * this to caller
-                        */
-                       ASSERT(ip->i_udquot);
-                       uq = ip->i_udquot;
-                       xfs_dqlock(uq);
-                       XFS_DQHOLD(uq);
-                       xfs_dqunlock(uq);
-               }
-       }
-       if ((flags & XFS_QMOPT_GQUOTA) &&
-           XFS_IS_GQUOTA_ON(mp)) {
-               if (ip->i_d.di_gid != gid) {
-                       xfs_iunlock(ip, lockflags);
-                       if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid,
-                                                XFS_DQ_GROUP,
-                                                XFS_QMOPT_DQALLOC |
-                                                XFS_QMOPT_DOWARN,
-                                                &gq))) {
-                               if (uq)
-                                       xfs_qm_dqrele(uq);
-                               ASSERT(error != ENOENT);
-                               return (error);
-                       }
-                       xfs_dqunlock(gq);
-                       lockflags = XFS_ILOCK_SHARED;
-                       xfs_ilock(ip, lockflags);
-               } else {
-                       ASSERT(ip->i_gdquot);
-                       gq = ip->i_gdquot;
-                       xfs_dqlock(gq);
-                       XFS_DQHOLD(gq);
-                       xfs_dqunlock(gq);
-               }
-       }
-       if (uq)
-               xfs_dqtrace_entry_ino(uq, "DQALLOC", ip);
-
-       xfs_iunlock(ip, lockflags);
-       if (O_udqpp)
-               *O_udqpp = uq;
-       else if (uq)
-               xfs_qm_dqrele(uq);
-       if (O_gdqpp)
-               *O_gdqpp = gq;
-       else if (gq)
-               xfs_qm_dqrele(gq);
-       return (0);
-}
-
-/*
- * Actually transfer ownership, and do dquot modifications.
- * These were already reserved.
- */
-xfs_dquot_t *
-xfs_qm_vop_chown(
-       xfs_trans_t     *tp,
-       xfs_inode_t     *ip,
-       xfs_dquot_t     **IO_olddq,
-       xfs_dquot_t     *newdq)
-{
-       xfs_dquot_t     *prevdq;
-       ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-       ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
-
-       /* old dquot */
-       prevdq = *IO_olddq;
-       ASSERT(prevdq);
-       ASSERT(prevdq != newdq);
-
-       xfs_trans_mod_dquot(tp, prevdq,
-                           XFS_TRANS_DQ_BCOUNT,
-                           -(ip->i_d.di_nblocks));
-       xfs_trans_mod_dquot(tp, prevdq,
-                           XFS_TRANS_DQ_ICOUNT,
-                           -1);
-
-       /* the sparkling new dquot */
-       xfs_trans_mod_dquot(tp, newdq,
-                           XFS_TRANS_DQ_BCOUNT,
-                           ip->i_d.di_nblocks);
-       xfs_trans_mod_dquot(tp, newdq,
-                           XFS_TRANS_DQ_ICOUNT,
-                           1);
-
-       /*
-        * Take an extra reference, because the inode
-        * is going to keep this dquot pointer even
-        * after the trans_commit.
-        */
-       xfs_dqlock(newdq);
-       XFS_DQHOLD(newdq);
-       xfs_dqunlock(newdq);
-       *IO_olddq = newdq;
-
-       return (prevdq);
-}
-
-/*
- * Quota reservations for setattr(AT_UID|AT_GID).
- */
-int
-xfs_qm_vop_chown_reserve(
-       xfs_trans_t     *tp,
-       xfs_inode_t     *ip,
-       xfs_dquot_t     *udqp,
-       xfs_dquot_t     *gdqp,
-       uint            privileged)
-{
-       int             error;
-       xfs_mount_t     *mp;
-       uint            delblks;
-       xfs_dquot_t     *unresudq, *unresgdq, *delblksudq, *delblksgdq;
-
-       ASSERT(XFS_ISLOCKED_INODE(ip));
-       mp = ip->i_mount;
-       ASSERT(XFS_IS_QUOTA_RUNNING(mp));
-
-       delblks = ip->i_delayed_blks;
-       delblksudq = delblksgdq = unresudq = unresgdq = NULL;
-
-       if (XFS_IS_UQUOTA_ON(mp) && udqp &&
-           ip->i_d.di_uid != (uid_t)INT_GET(udqp->q_core.d_id, ARCH_CONVERT)) {
-               delblksudq = udqp;
-               /*
-                * If there are delayed allocation blocks, then we have to
-                * unreserve those from the old dquot, and add them to the
-                * new dquot.
-                */
-               if (delblks) {
-                       ASSERT(ip->i_udquot);
-                       unresudq = ip->i_udquot;
-               }
-       }
-       if (XFS_IS_GQUOTA_ON(ip->i_mount) && gdqp &&
-           ip->i_d.di_gid != INT_GET(gdqp->q_core.d_id, ARCH_CONVERT)) {
-               delblksgdq = gdqp;
-               if (delblks) {
-                       ASSERT(ip->i_gdquot);
-                       unresgdq = ip->i_gdquot;
-               }
-       }
-
-       if ((error = xfs_trans_reserve_quota(tp, delblksudq,
-                                           delblksgdq,
-                                           ip->i_d.di_nblocks, 1,
-                                           privileged)))
-               return (error);
-
-
-       /*
-        * Do the delayed blks reservations/unreservations now. Since, these
-        * are done without the help of a transaction, if a reservation fails
-        * its previous reservations won't be automatically undone by trans
-        * code. So, we have to do it manually here.
-        */
-       if (delblks) {
-               /*
-                * Do the reservations first. Unreservation can't fail.
-                */
-               ASSERT(delblksudq || delblksgdq);
-               ASSERT(unresudq || unresgdq);
-               if ((error = xfs_trans_reserve_quota(NULL,
-                                                   delblksudq, delblksgdq,
-                                                   (xfs_qcnt_t)delblks, 0,
-                                                   privileged)))
-                       return (error);
-               (void) xfs_trans_unreserve_quota(NULL,
-                                                unresudq, unresgdq,
-                                                (xfs_qcnt_t)delblks, 0,
-                                                0);
-       }
-
-       return (0);
-}
-
-int
-xfs_qm_vop_rename_dqattach(
-       xfs_inode_t     **i_tab)
-{
-       xfs_inode_t     *ip;
-       int             i;
-       int             error;
-
-       ip = i_tab[0];
-
-       if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
-               error = xfs_qm_dqattach(ip, 0);
-               if (error)
-                       return (error);
-       }
-       for (i = 1; (i < 4 && i_tab[i]); i++) {
-               /*
-                * Watch out for duplicate entries in the table.
-                */
-               if ((ip = i_tab[i]) != i_tab[i-1]) {
-                       if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
-                               error = xfs_qm_dqattach(ip, 0);
-                               if (error)
-                                       return (error);
-                       }
-               }
-       }
-       return (0);
-}
-
-void
-xfs_qm_vop_dqattach_and_dqmod_newinode(
-       xfs_trans_t     *tp,
-       xfs_inode_t     *ip,
-       xfs_dquot_t     *udqp,
-       xfs_dquot_t     *gdqp)
-{
-       ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-       ASSERT(XFS_IS_QUOTA_RUNNING(tp->t_mountp));
-
-       if (udqp) {
-               xfs_dqlock(udqp);
-               XFS_DQHOLD(udqp);
-               xfs_dqunlock(udqp);
-               ASSERT(ip->i_udquot == NULL);
-               ip->i_udquot = udqp;
-               ASSERT(ip->i_d.di_uid == INT_GET(udqp->q_core.d_id, ARCH_CONVERT));
-               xfs_trans_mod_dquot(tp, udqp, XFS_TRANS_DQ_ICOUNT, 1);
-       }
-       if (gdqp) {
-               xfs_dqlock(gdqp);
-               XFS_DQHOLD(gdqp);
-               xfs_dqunlock(gdqp);
-               ASSERT(ip->i_gdquot == NULL);
-               ip->i_gdquot = gdqp;
-               ASSERT(ip->i_d.di_gid == INT_GET(gdqp->q_core.d_id, ARCH_CONVERT));
-               xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1);
-       }
-}
-
-/* ------------- list stuff -----------------*/
-void
-xfs_qm_freelist_init(xfs_frlist_t *ql)
-{
-       ql->qh_next = ql->qh_prev = (xfs_dquot_t *) ql;
-       mutex_init(&ql->qh_lock, MUTEX_DEFAULT, "dqf");
-       ql->qh_version = 0;
-       ql->qh_nelems = 0;
-}
-
-void
-xfs_qm_freelist_destroy(xfs_frlist_t *ql)
-{
-       xfs_dquot_t     *dqp, *nextdqp;
-
-       mutex_lock(&ql->qh_lock, PINOD);
-       for (dqp = ql->qh_next;
-            dqp != (xfs_dquot_t *)ql; ) {
-               xfs_dqlock(dqp);
-               nextdqp = dqp->dq_flnext;
-#ifdef QUOTADEBUG
-               printk("FREELIST destroy 0x%p\n", dqp);
-#endif
-               XQM_FREELIST_REMOVE(dqp);
-               xfs_dqunlock(dqp);
-               xfs_qm_dqdestroy(dqp);
-               dqp = nextdqp;
-       }
-       /*
-        * Don't bother about unlocking.
-        */
-       mutex_destroy(&ql->qh_lock);
-
-       ASSERT(ql->qh_nelems == 0);
-}
-
-void
-xfs_qm_freelist_insert(xfs_frlist_t *ql, xfs_dquot_t *dq)
-{
-       dq->dq_flnext = ql->qh_next;
-       dq->dq_flprev = (xfs_dquot_t *)ql;
-       ql->qh_next = dq;
-       dq->dq_flnext->dq_flprev = dq;
-       xfs_Gqm->qm_dqfreelist.qh_nelems++;
-       xfs_Gqm->qm_dqfreelist.qh_version++;
-}
-
-void
-xfs_qm_freelist_unlink(xfs_dquot_t *dq)
-{
-       xfs_dquot_t *next = dq->dq_flnext;
-       xfs_dquot_t *prev = dq->dq_flprev;
-
-       next->dq_flprev = prev;
-       prev->dq_flnext = next;
-       dq->dq_flnext = dq->dq_flprev = dq;
-       xfs_Gqm->qm_dqfreelist.qh_nelems--;
-       xfs_Gqm->qm_dqfreelist.qh_version++;
-}
-
-#ifdef QUOTADEBUG
-void
-xfs_qm_freelist_print(xfs_frlist_t *qlist, char *title)
-{
-       xfs_dquot_t *dq;
-       int i = 0;
-       printk("%s (#%d)\n", title, (int) qlist->qh_nelems);
-       FOREACH_DQUOT_IN_FREELIST(dq, qlist) {
-               printk("\t%d.\t\"%d (%s:0x%p)\"\t bcnt = %d, icnt = %d "
-                      "refs = %d\n",
-                      ++i, INT_GET(dq->q_core.d_id, ARCH_CONVERT),
-                      DQFLAGTO_TYPESTR(dq), dq,
-                      (int) INT_GET(dq->q_core.d_bcount, ARCH_CONVERT),
-                      (int) INT_GET(dq->q_core.d_icount, ARCH_CONVERT),
-                      (int) dq->q_nrefs);
-       }
-}
-#endif
-
-void
-xfs_qm_freelist_append(xfs_frlist_t *ql, xfs_dquot_t *dq)
-{
-       xfs_qm_freelist_insert((xfs_frlist_t *)ql->qh_prev, dq);
-}
-
-int
-xfs_qm_dqhashlock_nowait(
-       xfs_dquot_t *dqp)
-{
-       int locked;
-
-       locked = mutex_trylock(&((dqp)->q_hash->qh_lock));
-       return (locked);
-}
-
-int
-xfs_qm_freelist_lock_nowait(
-       xfs_qm_t *xqm)
-{
-       int locked;
-
-       locked = mutex_trylock(&(xqm->qm_dqfreelist.qh_lock));
-       return (locked);
-}
-
-int
-xfs_qm_mplist_nowait(
-       xfs_mount_t     *mp)
-{
-       int locked;
-
-       ASSERT(mp->m_quotainfo);
-       locked = mutex_trylock(&(XFS_QI_MPLLOCK(mp)));
-       return (locked);
-}
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
deleted file mode 100644 (file)
index 9d69a6b..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.         Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-#ifndef __XFS_QM_H__
-#define __XFS_QM_H__
-
-struct xfs_dqhash;
-struct xfs_inode;
-struct xfs_dquot;
-
-extern kmem_zone_t     *qm_dqzone;
-extern kmem_zone_t     *qm_dqtrxzone;
-
-/*
- * Used in xfs_qm_sync called by xfs_sync to count the max times that it can
- * iterate over the mountpt's dquot list in one call.
- */
-#define XFS_QM_SYNC_MAX_RESTARTS       7
-
-/*
- * Ditto, for xfs_qm_dqreclaim_one.
- */
-#define XFS_QM_RECLAIM_MAX_RESTARTS    4
-
-/*
- * Ideal ratio of free to in use dquots. Quota manager makes an attempt
- * to keep this balance.
- */
-#define XFS_QM_DQFREE_RATIO            2
-
-/*
- * Dquot hashtable constants/threshold values.
- */
-#define XFS_QM_NCSIZE_THRESHOLD                5000
-#define XFS_QM_HASHSIZE_LOW            32
-#define XFS_QM_HASHSIZE_HIGH           64
-
-/*
- * We output a cmn_err when quotachecking a quota file with more than
- * this many fsbs.
- */
-#define XFS_QM_BIG_QCHECK_NBLKS                500
-
-/*
- * This defines the unit of allocation of dquots.
- * Currently, it is just one file system block, and a 4K blk contains 30
- * (136 * 30 = 4080) dquots. It's probably not worth trying to make
- * this more dynamic.
- * XXXsup However, if this number is changed, we have to make sure that we don't
- * implicitly assume that we do allocations in chunks of a single filesystem
- * block in the dquot/xqm code.
- */
-#define XFS_DQUOT_CLUSTER_SIZE_FSB     (xfs_filblks_t)1
-/*
- * When doing a quotacheck, we log dquot clusters of this many FSBs at most
- * in a single transaction. We don't want to ask for too huge a log reservation.
- */
-#define XFS_QM_MAX_DQCLUSTER_LOGSZ     3
-
-typedef xfs_dqhash_t   xfs_dqlist_t;
-/*
- * The freelist head. The first two fields match the first two in the
- * xfs_dquot_t structure (in xfs_dqmarker_t)
- */
-typedef struct xfs_frlist {
-       struct xfs_dquot *qh_next;
-       struct xfs_dquot *qh_prev;
-       mutex_t          qh_lock;
-       uint             qh_version;
-       uint             qh_nelems;
-} xfs_frlist_t;
-
-/*
- * Quota Manager (global) structure. Lives only in core.
- */
-typedef struct xfs_qm {
-       xfs_dqlist_t    *qm_usr_dqhtable;/* udquot hash table */
-       xfs_dqlist_t    *qm_grp_dqhtable;/* gdquot hash table */
-       uint             qm_dqhashmask;  /* # buckets in dq hashtab - 1 */
-       xfs_frlist_t     qm_dqfreelist;  /* freelist of dquots */
-       atomic_t         qm_totaldquots; /* total incore dquots */
-       uint             qm_nrefs;       /* file systems with quota on */
-       int              qm_dqfree_ratio;/* ratio of free to inuse dquots */
-       kmem_zone_t     *qm_dqzone;      /* dquot mem-alloc zone */
-       kmem_zone_t     *qm_dqtrxzone;   /* t_dqinfo of transactions */
-} xfs_qm_t;
-
-/*
- * Various quota information for individual filesystems.
- * The mount structure keeps a pointer to this.
- */
-typedef struct xfs_quotainfo {
-       xfs_inode_t     *qi_uquotaip;    /* user quota inode */
-       xfs_inode_t     *qi_gquotaip;    /* group quota inode */
-       lock_t           qi_pinlock;     /* dquot pinning mutex */
-       xfs_dqlist_t     qi_dqlist;      /* all dquots in filesys */
-       int              qi_dqreclaims;  /* a change here indicates
-                                           a removal in the dqlist */
-       time_t           qi_btimelimit;  /* limit for blks timer */
-       time_t           qi_itimelimit;  /* limit for inodes timer */
-       time_t           qi_rtbtimelimit;/* limit for rt blks timer */
-       xfs_qwarncnt_t   qi_bwarnlimit;  /* limit for num warnings */
-       xfs_qwarncnt_t   qi_iwarnlimit;  /* limit for num warnings */
-       mutex_t          qi_quotaofflock;/* to serialize quotaoff */
-       /* Some useful precalculated constants */
-       xfs_filblks_t    qi_dqchunklen;  /* # BBs in a chunk of dqs */
-       uint             qi_dqperchunk;  /* # ondisk dqs in above chunk */
-} xfs_quotainfo_t;
-
-
-/*
- * The structure kept inside the xfs_trans_t keep track of dquot changes
- * within a transaction and apply them later.
- */
-typedef struct xfs_dqtrx {
-       struct xfs_dquot *qt_dquot;       /* the dquot this refers to */
-       ulong           qt_blk_res;       /* blks reserved on a dquot */
-       ulong           qt_blk_res_used;  /* blks used from the reservation */
-       ulong           qt_ino_res;       /* inode reserved on a dquot */
-       ulong           qt_ino_res_used;  /* inodes used from the reservation */
-       long            qt_bcount_delta;  /* dquot blk count changes */
-       long            qt_delbcnt_delta; /* delayed dquot blk count changes */
-       long            qt_icount_delta;  /* dquot inode count changes */
-       ulong           qt_rtblk_res;     /* # blks reserved on a dquot */
-       ulong           qt_rtblk_res_used;/* # blks used from reservation */
-       long            qt_rtbcount_delta;/* dquot realtime blk changes */
-       long            qt_delrtb_delta;  /* delayed RT blk count changes */
-} xfs_dqtrx_t;
-
-/*
- * We keep the usr and grp dquots separately so that locking will be easier
- * to do at commit time. All transactions that we know of at this point
- * affect no more than two dquots of one type. Hence, the TRANS_MAXDQS value.
- */
-#define XFS_QM_TRANS_MAXDQS            2
-typedef struct xfs_dquot_acct {
-       xfs_dqtrx_t     dqa_usrdquots[XFS_QM_TRANS_MAXDQS];
-       xfs_dqtrx_t     dqa_grpdquots[XFS_QM_TRANS_MAXDQS];
-} xfs_dquot_acct_t;
-
-/*
- * Users are allowed to have a usage exceeding their softlimit for
- * a period this long.
- */
-#define XFS_QM_BTIMELIMIT      DQ_BTIMELIMIT
-#define XFS_QM_RTBTIMELIMIT    DQ_BTIMELIMIT
-#define XFS_QM_ITIMELIMIT      DQ_FTIMELIMIT
-
-#define XFS_QM_BWARNLIMIT      5
-#define XFS_QM_IWARNLIMIT      5
-
-#define XFS_QM_LOCK(xqm)       (mutex_lock(&xqm##_lock, PINOD))
-#define XFS_QM_UNLOCK(xqm)     (mutex_unlock(&xqm##_lock))
-#define XFS_QM_HOLD(xqm)       ((xqm)->qm_nrefs++)
-#define XFS_QM_RELE(xqm)       ((xqm)->qm_nrefs--)
-
-extern int             xfs_qm_init_quotainfo(xfs_mount_t *);
-extern void            xfs_qm_destroy_quotainfo(xfs_mount_t *);
-extern void            xfs_qm_dqunlink(xfs_dquot_t *);
-extern boolean_t       xfs_qm_dqalloc_incore(xfs_dquot_t **);
-extern int             xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t);
-
-/* list stuff */
-extern void            xfs_qm_freelist_init(xfs_frlist_t *);
-extern void            xfs_qm_freelist_destroy(xfs_frlist_t *);
-extern void            xfs_qm_freelist_insert(xfs_frlist_t *, xfs_dquot_t *);
-extern void            xfs_qm_freelist_append(xfs_frlist_t *, xfs_dquot_t *);
-extern void            xfs_qm_freelist_unlink(xfs_dquot_t *);
-extern int             xfs_qm_freelist_lock_nowait(xfs_qm_t *);
-extern int             xfs_qm_mplist_nowait(xfs_mount_t *);
-extern int             xfs_qm_dqhashlock_nowait(xfs_dquot_t *);
-
-/* system call interface */
-extern int             xfs_qm_quotactl(bhv_desc_t *, int, int, xfs_caddr_t);
-
-#ifdef DEBUG
-extern int             xfs_qm_internalqcheck(xfs_mount_t *);
-#else
-#define xfs_qm_internalqcheck(mp)      (0)
-#endif
-
-#ifdef QUOTADEBUG
-extern void            xfs_qm_freelist_print(xfs_frlist_t *, char *);
-#else
-#define xfs_qm_freelist_print(a, b)    do { } while (0)
-#endif
-
-#endif /* __XFS_QM_H__ */
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
deleted file mode 100644 (file)
index 6380571..0000000
+++ /dev/null
@@ -1,1410 +0,0 @@
-/*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.         Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include <xfs.h>
-#include <xfs_quota_priv.h>
-
-#ifdef DEBUG
-# define qdprintk(s, args...)  cmn_err(CE_DEBUG, s, ## args)
-#else
-# define qdprintk(s, args...)  do { } while (0)
-#endif
-
-STATIC int     xfs_qm_scall_trunc_qfiles(xfs_mount_t *, uint);
-STATIC int     xfs_qm_scall_getquota(xfs_mount_t *, xfs_dqid_t, uint,
-                                       fs_disk_quota_t *);
-STATIC int     xfs_qm_scall_getqstat(xfs_mount_t *, fs_quota_stat_t *);
-STATIC int     xfs_qm_scall_setqlim(xfs_mount_t *, xfs_dqid_t, uint,
-                                       fs_disk_quota_t *);
-STATIC int     xfs_qm_scall_quotaon(xfs_mount_t *, uint);
-STATIC int     xfs_qm_scall_quotaoff(xfs_mount_t *, uint, boolean_t);
-STATIC int     xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint);
-STATIC int     xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
-                                       uint);
-STATIC uint    xfs_qm_import_flags(uint);
-STATIC uint    xfs_qm_export_flags(uint);
-STATIC uint    xfs_qm_import_qtype_flags(uint);
-STATIC uint    xfs_qm_export_qtype_flags(uint);
-STATIC void    xfs_qm_export_dquot(xfs_mount_t *, xfs_disk_dquot_t *,
-                                       fs_disk_quota_t *);
-
-
-/*
- * The main distribution switch of all XFS quotactl system calls.
- */
-int
-xfs_qm_quotactl(
-       struct bhv_desc *bdp,
-       int             cmd,
-       int             id,
-       xfs_caddr_t     addr)
-{
-       xfs_mount_t     *mp;
-       int             error;
-       struct vfs      *vfsp;
-
-       vfsp = bhvtovfs(bdp);
-        mp = XFS_VFSTOM(vfsp);
-
-       if (addr == NULL && cmd != Q_SYNC)
-               return XFS_ERROR(EINVAL);
-       if (id < 0 && cmd != Q_SYNC)
-               return XFS_ERROR(EINVAL);
-
-       /*
-        * The following commands are valid even when quotaoff.
-        */
-       switch (cmd) {
-               /* 
-                * truncate quota files. quota must be off.
-                */
-             case Q_XQUOTARM:
-               if (XFS_IS_QUOTA_ON(mp) || addr == NULL)
-                       return XFS_ERROR(EINVAL);
-               if (vfsp->vfs_flag & VFS_RDONLY)
-                       return XFS_ERROR(EROFS);
-               return (xfs_qm_scall_trunc_qfiles(mp, 
-                              xfs_qm_import_qtype_flags(*(uint *)addr)));
-               /*
-                * Get quota status information.
-                */
-             case Q_XGETQSTAT:
-               return (xfs_qm_scall_getqstat(mp, (fs_quota_stat_t *)addr));
-
-               /*
-                * QUOTAON for root f/s and quota enforcement on others..
-                * Quota accounting for non-root f/s's must be turned on
-                * at mount time.
-                */
-             case Q_XQUOTAON:
-               if (addr == NULL)
-                       return XFS_ERROR(EINVAL);
-               if (vfsp->vfs_flag & VFS_RDONLY)
-                       return XFS_ERROR(EROFS);
-               return (xfs_qm_scall_quotaon(mp,
-                                         xfs_qm_import_flags(*(uint *)addr)));
-             case Q_XQUOTAOFF:
-               if (vfsp->vfs_flag & VFS_RDONLY)
-                       return XFS_ERROR(EROFS);
-               break;
-               
-             default:
-               break;
-       }
-
-       if (! XFS_IS_QUOTA_ON(mp))
-               return XFS_ERROR(ESRCH);
-
-       switch (cmd) {
-             case Q_XQUOTAOFF:
-               if (vfsp->vfs_flag & VFS_RDONLY)
-                       return XFS_ERROR(EROFS);
-               error = xfs_qm_scall_quotaoff(mp,
-                                           xfs_qm_import_flags(*(uint *)addr),
-                                           B_FALSE);
-               break;
-
-               /* 
-                * Defaults to XFS_GETUQUOTA. 
-                */
-             case Q_XGETQUOTA:
-               error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_USER, 
-                                       (fs_disk_quota_t *)addr);
-               break;
-               /*
-                * Set limits, both hard and soft. Defaults to Q_SETUQLIM.
-                */
-             case Q_XSETQLIM:
-               if (vfsp->vfs_flag & VFS_RDONLY)
-                       return XFS_ERROR(EROFS);
-               error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_USER,
-                                            (fs_disk_quota_t *)addr);
-               break;
-
-              case Q_XSETGQLIM:
-               if (vfsp->vfs_flag & VFS_RDONLY)
-                       return XFS_ERROR(EROFS);
-               error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_GROUP,
-                                            (fs_disk_quota_t *)addr);
-               break;
-
-                       
-             case Q_XGETGQUOTA:
-               error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_GROUP, 
-                                       (fs_disk_quota_t *)addr);
-               break;
-
-               /*
-                * Quotas are entirely undefined after quotaoff in XFS quotas.
-                * For instance, there's no way to set limits when quotaoff.
-                */
-
-             default:
-               error = XFS_ERROR(EINVAL);
-               break;
-       }
-
-       return (error);
-}
-
-/*
- * Turn off quota accounting and/or enforcement for all udquots and/or
- * gdquots. Called only at unmount time.
- *
- * This assumes that there are no dquots of this file system cached
- * incore, and modifies the ondisk dquot directly. Therefore, for example,
- * it is an error to call this twice, without purging the cache.
- */
-STATIC int
-xfs_qm_scall_quotaoff(
-       xfs_mount_t             *mp,
-       uint                    flags,
-       boolean_t               force)
-{
-       uint                    dqtype;
-       unsigned long   s;
-       int                     error;
-       uint                    inactivate_flags;
-       xfs_qoff_logitem_t      *qoffstart;
-       int                     nculprits;
-
-       if (!force && !capable(CAP_SYS_ADMIN))
-               return XFS_ERROR(EPERM);
-       /*
-        * No file system can have quotas enabled on disk but not in core.
-        * Note that quota utilities (like quotaoff) _expect_
-        * errno == EEXIST here.
-        */
-       if ((mp->m_qflags & flags) == 0)
-               return XFS_ERROR(EEXIST);
-       error = 0;
-
-       flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
-
-       /*
-        * We don't want to deal with two quotaoffs messing up each other,
-        * so we're going to serialize it. quotaoff isn't exactly a performance
-        * critical thing.
-        * If quotaoff, then we must be dealing with the root filesystem.
-        */
-       ASSERT(mp->m_quotainfo);
-       if (mp->m_quotainfo)
-               mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD);
-
-       ASSERT(mp->m_quotainfo);
-
-       /*
-        * If we're just turning off quota enforcement, change mp and go.
-        */
-       if ((flags & XFS_ALL_QUOTA_ACCT) == 0) {
-               mp->m_qflags &= ~(flags);
-
-               s = XFS_SB_LOCK(mp);
-               mp->m_sb.sb_qflags = mp->m_qflags;
-               XFS_SB_UNLOCK(mp, s);
-               mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
-
-               /* XXX what to do if error ? Revert back to old vals incore ? */
-               error = xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS);
-               return (error);
-       }
-
-       dqtype = 0;
-       inactivate_flags = 0;
-       /*
-        * If accounting is off, we must turn enforcement off, clear the
-        * quota 'CHKD' certificate to make it known that we have to
-        * do a quotacheck the next time this quota is turned on.
-        */
-       if (flags & XFS_UQUOTA_ACCT) {
-               dqtype |= XFS_QMOPT_UQUOTA;
-               flags |= (XFS_UQUOTA_CHKD | XFS_UQUOTA_ENFD);
-               inactivate_flags |= XFS_UQUOTA_ACTIVE;
-       }
-       if (flags & XFS_GQUOTA_ACCT) {
-               dqtype |= XFS_QMOPT_GQUOTA;
-               flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD);
-               inactivate_flags |= XFS_GQUOTA_ACTIVE;
-       }
-
-       /*
-        * Nothing to do?  Don't complain. This happens when we're just
-        * turning off quota enforcement.
-        */
-       if ((mp->m_qflags & flags) == 0) {
-               mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
-               return (0);
-       }
-
-       /*
-        * Write the LI_QUOTAOFF log record, and do SB changes atomically,
-        * and synchronously.
-        */
-       xfs_qm_log_quotaoff(mp, &qoffstart, flags);
-
-       /*
-        * Next we clear the XFS_MOUNT_*DQ_ACTIVE bit(s) in the mount struct
-        * to take care of the race between dqget and quotaoff. We don't take
-        * any special locks to reset these bits. All processes need to check
-        * these bits *after* taking inode lock(s) to see if the particular
-        * quota type is in the process of being turned off. If *ACTIVE, it is
-        * guaranteed that all dquot structures and all quotainode ptrs will all
-        * stay valid as long as that inode is kept locked.
-        *
-        * There is no turning back after this.
-        */
-       mp->m_qflags &= ~inactivate_flags;
-
-       /*
-        * Give back all the dquot reference(s) held by inodes.
-        * Here we go thru every single incore inode in this file system, and
-        * do a dqrele on the i_udquot/i_gdquot that it may have.
-        * Essentially, as long as somebody has an inode locked, this guarantees
-        * that quotas will not be turned off. This is handy because in a
-        * transaction once we lock the inode(s) and check for quotaon, we can
-        * depend on the quota inodes (and other things) being valid as long as
-        * we keep the lock(s).
-        */
-       xfs_qm_dqrele_all_inodes(mp, flags);
-
-       /*
-        * Next we make the changes in the quota flag in the mount struct.
-        * This isn't protected by a particular lock directly, because we
-        * don't want to take a mrlock everytime we depend on quotas being on.
-        */
-       mp->m_qflags &= ~(flags);
-
-       /*
-        * Go through all the dquots of this file system and purge them,
-        * according to what was turned off. We may not be able to get rid
-        * of all dquots, because dquots can have temporary references that
-        * are not attached to inodes. eg. xfs_setattr, xfs_create.
-        * So, if we couldn't purge all the dquots from the filesystem,
-        * we can't get rid of the incore data structures.
-        */
-       while ((nculprits = xfs_qm_dqpurge_all(mp, dqtype|XFS_QMOPT_QUOTAOFF)))
-               delay(10 * nculprits);
-
-       /*
-        * Transactions that had started before ACTIVE state bit was cleared
-        * could have logged many dquots, so they'd have higher LSNs than
-        * the first QUOTAOFF log record does. If we happen to crash when
-        * the tail of the log has gone past the QUOTAOFF record, but
-        * before the last dquot modification, those dquots __will__
-        * recover, and that's not good.
-        *
-        * So, we have QUOTAOFF start and end logitems; the start
-        * logitem won't get overwritten until the end logitem appears...
-        */
-       xfs_qm_log_quotaoff_end(mp, qoffstart, flags);
-
-       /*
-        * If quotas is completely disabled, close shop.
-        */
-       if ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_ALL) {
-               mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
-               xfs_qm_destroy_quotainfo(mp);
-               return (0);
-       }
-
-       /*
-        * Release our quotainode references, and vn_purge them,
-        * if we don't need them anymore.
-        */
-       if ((dqtype & XFS_QMOPT_UQUOTA) && XFS_QI_UQIP(mp)) {
-               XFS_PURGE_INODE(XFS_QI_UQIP(mp));
-               XFS_QI_UQIP(mp) = NULL;
-       }
-       if ((dqtype & XFS_QMOPT_GQUOTA) && XFS_QI_GQIP(mp)) {
-               XFS_PURGE_INODE(XFS_QI_GQIP(mp));
-               XFS_QI_GQIP(mp) = NULL;
-       }
-       mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
-
-       return (error);
-}
-
-STATIC int
-xfs_qm_scall_trunc_qfiles(
-       xfs_mount_t     *mp,
-       uint            flags)
-{
-       int             error;
-       xfs_inode_t     *qip;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return XFS_ERROR(EPERM);
-       error = 0;
-       if (!XFS_SB_VERSION_HASQUOTA(&mp->m_sb) || flags == 0) {
-               qdprintk("qtrunc flags=%x m_qflags=%x\n", flags, mp->m_qflags);
-               return XFS_ERROR(EINVAL);
-       }
-
-       if ((flags & XFS_DQ_USER) && mp->m_sb.sb_uquotino != NULLFSINO) {
-               error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &qip, 0);
-               if (! error) {
-                       (void) xfs_truncate_file(mp, qip);
-                       VN_RELE(XFS_ITOV(qip));
-               }
-       }
-
-       if ((flags & XFS_DQ_GROUP) && mp->m_sb.sb_gquotino != NULLFSINO) {
-               error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &qip, 0);
-               if (! error) {
-                       (void) xfs_truncate_file(mp, qip);
-                       VN_RELE(XFS_ITOV(qip));
-               }
-       }
-
-       return (error);
-}
-
-
-/*
- * Switch on (a given) quota enforcement for a filesystem.  This takes
- * effect immediately.
- * (Switching on quota accounting must be done at mount time.)
- */
-STATIC int
-xfs_qm_scall_quotaon(
-       xfs_mount_t     *mp,
-       uint            flags)
-{
-       int             error;
-       unsigned long s;
-       uint            qf;
-       uint            accflags;
-       __int64_t       sbflags;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return XFS_ERROR(EPERM);
-
-       flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
-       /*
-        * Switching on quota accounting must be done at mount time.
-        */
-       accflags = flags & XFS_ALL_QUOTA_ACCT;
-       flags &= ~(XFS_ALL_QUOTA_ACCT);
-
-       sbflags = 0;
-
-       if (flags == 0) {
-               qdprintk("quotaon: zero flags, m_qflags=%x\n", mp->m_qflags);
-               return XFS_ERROR(EINVAL);
-       }
-
-       /* No fs can turn on quotas with a delayed effect */
-       ASSERT((flags & XFS_ALL_QUOTA_ACCT) == 0);
-
-       /*
-        * Can't enforce without accounting. We check the superblock
-        * qflags here instead of m_qflags because rootfs can have
-        * quota acct on ondisk without m_qflags' knowing.
-        */
-       if (((flags & XFS_UQUOTA_ACCT) == 0 &&
-           (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
-           (flags & XFS_UQUOTA_ENFD))
-           ||
-           ((flags & XFS_GQUOTA_ACCT) == 0 &&
-           (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
-           (flags & XFS_GQUOTA_ENFD))) {
-               qdprintk("Can't enforce without acct, flags=%x sbflags=%x\n",
-                       flags, mp->m_sb.sb_qflags);
-               return XFS_ERROR(EINVAL);
-       }
-       /*
-        * If everything's upto-date incore, then don't waste time.
-        */
-       if ((mp->m_qflags & flags) == flags)
-               return XFS_ERROR(EEXIST);
-
-       /*
-        * Change sb_qflags on disk but not incore mp->qflags
-        * if this is the root filesystem.
-        */
-       s = XFS_SB_LOCK(mp);
-       qf = mp->m_sb.sb_qflags;
-       mp->m_sb.sb_qflags = qf | flags;
-       XFS_SB_UNLOCK(mp, s);
-
-       /*
-        * There's nothing to change if it's the same.
-        */
-       if ((qf & flags) == flags && sbflags == 0)
-               return XFS_ERROR(EEXIST);
-       sbflags |= XFS_SB_QFLAGS;
-
-       if ((error = xfs_qm_write_sb_changes(mp, sbflags)))
-               return (error);
-       /*
-        * If we aren't trying to switch on quota enforcement, we are done.
-        */
-       if  (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) !=
-            (mp->m_qflags & XFS_UQUOTA_ACCT)) ||
-           (flags & XFS_ALL_QUOTA_ENFD) == 0)
-               return (0);
-
-       if (! XFS_IS_QUOTA_RUNNING(mp))
-               return XFS_ERROR(ESRCH);
-
-       /*
-        * Switch on quota enforcement in core.
-        */
-       mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD);
-       mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD);
-       mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
-
-       return (0);
-}
-
-
-
-/*
- * Return quota status information, such as uquota-off, enforcements, etc.
- */
-STATIC int
-xfs_qm_scall_getqstat(
-       xfs_mount_t     *mp,
-       fs_quota_stat_t *out)
-{
-       xfs_inode_t     *uip, *gip;
-       boolean_t       tempuqip, tempgqip;
-
-       uip = gip = NULL;
-       tempuqip = tempgqip = B_FALSE;
-       memset(out, 0, sizeof(fs_quota_stat_t));
-
-       out->qs_version = FS_QSTAT_VERSION;
-       if (! XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) {
-               out->qs_uquota.qfs_ino = NULLFSINO;
-               out->qs_gquota.qfs_ino = NULLFSINO;
-               return (0);
-       }
-       out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
-                                                       (XFS_ALL_QUOTA_ACCT|
-                                                        XFS_ALL_QUOTA_ENFD));
-       out->qs_pad = 0;
-       out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
-       out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
-
-       if (mp->m_quotainfo) {
-               uip = mp->m_quotainfo->qi_uquotaip;
-               gip = mp->m_quotainfo->qi_gquotaip;
-       }
-       if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
-               if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &uip, 0) == 0)
-                       tempuqip = B_TRUE;
-       }
-       if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) {
-               if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &gip, 0) == 0)
-                       tempgqip = B_TRUE;
-       }
-       if (uip) {
-               out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
-               out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
-               if (tempuqip)
-                       VN_RELE(XFS_ITOV(uip));
-       }
-       if (gip) {
-               out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
-               out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
-               if (tempgqip)
-                       VN_RELE(XFS_ITOV(gip));
-       }
-       if (mp->m_quotainfo) {
-               out->qs_incoredqs = XFS_QI_MPLNDQUOTS(mp);
-               out->qs_btimelimit = XFS_QI_BTIMELIMIT(mp);
-               out->qs_itimelimit = XFS_QI_ITIMELIMIT(mp);
-               out->qs_rtbtimelimit = XFS_QI_RTBTIMELIMIT(mp);
-               out->qs_bwarnlimit = XFS_QI_BWARNLIMIT(mp);
-               out->qs_iwarnlimit = XFS_QI_IWARNLIMIT(mp);
-       }
-       return (0);
-}
-
-/*
- * Adjust quota limits, and start/stop timers accordingly.
- */
-STATIC int
-xfs_qm_scall_setqlim(
-       xfs_mount_t             *mp,
-       xfs_dqid_t              id,
-       uint                    type,
-       fs_disk_quota_t         *newlim)
-{
-       xfs_disk_dquot_t        *ddq;
-       xfs_dquot_t             *dqp;
-       xfs_trans_t             *tp;
-       int                     error;
-       xfs_qcnt_t              hard, soft;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return XFS_ERROR(EPERM);
-
-       if ((newlim->d_fieldmask & (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK)) == 0)
-               return (0);
-
-       tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM);
-       if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_disk_dquot_t) + 128,
-                                     0, 0, XFS_DEFAULT_LOG_COUNT))) {
-               xfs_trans_cancel(tp, 0);
-               return (error);
-       }
-
-       /*
-        * We don't want to race with a quotaoff so take the quotaoff lock.
-        * (We don't hold an inode lock, so there's nothing else to stop
-        * a quotaoff from happening). (XXXThis doesn't currently happen
-        * because we take the vfslock before calling xfs_qm_sysent).
-        */
-       mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD);
-
-       /*
-        * Get the dquot (locked), and join it to the transaction.
-        * Allocate the dquot if this doesn't exist.
-        */
-       if ((error = xfs_qm_dqget(mp, NULL, id, type, XFS_QMOPT_DQALLOC, &dqp))) {
-               xfs_trans_cancel(tp, XFS_TRANS_ABORT);
-               mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
-               ASSERT(error != ENOENT);
-               return (error);
-       }
-       xfs_dqtrace_entry(dqp, "Q_SETQLIM: AFT DQGET");
-       xfs_trans_dqjoin(tp, dqp);
-       ddq = &dqp->q_core;
-
-       /*
-        * Make sure that hardlimits are >= soft limits before changing.
-        */
-       hard = (newlim->d_fieldmask & FS_DQ_BHARD) ?
-               (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_hardlimit) :
-                       INT_GET(ddq->d_blk_hardlimit, ARCH_CONVERT);
-       soft = (newlim->d_fieldmask & FS_DQ_BSOFT) ?
-               (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_softlimit) :
-                       INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT);
-       if (hard == 0 || hard >= soft) {
-               INT_SET(ddq->d_blk_hardlimit, ARCH_CONVERT, hard);
-               INT_SET(ddq->d_blk_softlimit, ARCH_CONVERT, soft);
-       }
-       else {
-               qdprintk("blkhard %Ld < blksoft %Ld\n", hard, soft);
-       }
-       hard = (newlim->d_fieldmask & FS_DQ_RTBHARD) ?
-               (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_hardlimit) :
-                       INT_GET(ddq->d_rtb_hardlimit, ARCH_CONVERT);
-       soft = (newlim->d_fieldmask & FS_DQ_RTBSOFT) ?
-               (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_softlimit) :
-                       INT_GET(ddq->d_rtb_softlimit, ARCH_CONVERT);
-       if (hard == 0 || hard >= soft) {
-               INT_SET(ddq->d_rtb_hardlimit, ARCH_CONVERT, hard);
-               INT_SET(ddq->d_rtb_softlimit, ARCH_CONVERT, soft);
-       }
-       else
-               qdprintk("rtbhard %Ld < rtbsoft %Ld\n", hard, soft);
-
-       hard = (newlim->d_fieldmask & FS_DQ_IHARD) ?
-               (xfs_qcnt_t) newlim->d_ino_hardlimit :
-               INT_GET(ddq->d_ino_hardlimit, ARCH_CONVERT);
-       soft = (newlim->d_fieldmask & FS_DQ_ISOFT) ?
-               (xfs_qcnt_t) newlim->d_ino_softlimit :
-               INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT);
-       if (hard == 0 || hard >= soft) {
-               INT_SET(ddq->d_ino_hardlimit, ARCH_CONVERT, hard);
-               INT_SET(ddq->d_ino_softlimit, ARCH_CONVERT, soft);
-       }
-       else
-               qdprintk("ihard %Ld < isoft %Ld\n", hard, soft);
-
-       if (id == 0) {
-               /*
-                * Timelimits for the super user set the relative time
-                * the other users can be over quota for this file system.
-                * If it is zero a default is used.
-                */
-               if (newlim->d_fieldmask & FS_DQ_BTIMER) {
-                       mp->m_quotainfo->qi_btimelimit = newlim->d_btimer;
-                       INT_SET(dqp->q_core.d_btimer, ARCH_CONVERT, newlim->d_btimer);
-               }
-               if (newlim->d_fieldmask & FS_DQ_ITIMER) {
-                       mp->m_quotainfo->qi_itimelimit = newlim->d_itimer;
-                       INT_SET(dqp->q_core.d_itimer, ARCH_CONVERT, newlim->d_itimer);
-               }
-               if (newlim->d_fieldmask & FS_DQ_RTBTIMER) {
-                       mp->m_quotainfo->qi_rtbtimelimit = newlim->d_rtbtimer;
-                       INT_SET(dqp->q_core.d_rtbtimer, ARCH_CONVERT, newlim->d_rtbtimer);
-               }
-       } else /* if (XFS_IS_QUOTA_ENFORCED(mp)) */ {
-               /*
-                * If the user is now over quota, start the timelimit.
-                * The user will not be 'warned'.
-                * Note that we keep the timers ticking, whether enforcement
-                * is on or off. We don't really want to bother with iterating
-                * over all ondisk dquots and turning the timers on/off.
-                */
-               xfs_qm_adjust_dqtimers(mp, ddq);
-       }
-       dqp->dq_flags |= XFS_DQ_DIRTY;
-       xfs_trans_log_dquot(tp, dqp);
-
-       xfs_dqtrace_entry(dqp, "Q_SETQLIM: COMMIT");
-       xfs_trans_commit(tp, 0, NULL);
-       xfs_qm_dqprint(dqp);
-       xfs_qm_dqrele(dqp);
-       mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
-
-       return (0);
-}
-
-STATIC int
-xfs_qm_scall_getquota(
-       xfs_mount_t     *mp,
-       xfs_dqid_t      id,
-       uint            type,
-       fs_disk_quota_t *out)
-{
-       xfs_dquot_t     *dqp;
-       int             error;
-
-       /*
-        * Try to get the dquot. We don't want it allocated on disk, so
-        * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't
-        * exist, we'll get ENOENT back.
-        */
-       if ((error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp))) {
-               return (error);
-       }
-
-       xfs_dqtrace_entry(dqp, "Q_GETQUOTA SUCCESS");
-       /*
-        * If everything's NULL, this dquot doesn't quite exist as far as
-        * our utility programs are concerned.
-        */
-       if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
-               xfs_qm_dqput(dqp);
-               return XFS_ERROR(ENOENT);
-       }
-       /* xfs_qm_dqprint(dqp); */
-       /*
-        * Convert the disk dquot to the exportable format
-        */
-       xfs_qm_export_dquot(mp, &dqp->q_core, out);
-       xfs_qm_dqput(dqp);
-       return (error ? XFS_ERROR(EFAULT) : 0);
-}
-
-
-STATIC int
-xfs_qm_log_quotaoff_end(
-       xfs_mount_t             *mp,
-       xfs_qoff_logitem_t      *startqoff,
-       uint                    flags)
-{
-       xfs_trans_t            *tp;
-       int                     error;
-       xfs_qoff_logitem_t     *qoffi;
-
-       tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END);
-
-       if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_qoff_logitem_t) * 2,
-                                     0, 0, XFS_DEFAULT_LOG_COUNT))) {
-               xfs_trans_cancel(tp, 0);
-               return (error);
-       }
-
-       qoffi = xfs_trans_get_qoff_item(tp, startqoff,
-                                       flags & XFS_ALL_QUOTA_ACCT);
-       xfs_trans_log_quotaoff_item(tp, qoffi);
-
-       /*
-        * We have to make sure that the transaction is secure on disk before we
-        * return and actually stop quota accounting. So, make it synchronous.
-        * We don't care about quotoff's performance.
-        */
-       xfs_trans_set_sync(tp);
-       error = xfs_trans_commit(tp, 0, NULL);
-       return (error);
-}
-
-
-STATIC int
-xfs_qm_log_quotaoff(
-       xfs_mount_t            *mp,
-       xfs_qoff_logitem_t     **qoffstartp,
-       uint                   flags)
-{
-       xfs_trans_t            *tp;
-       int                     error;
-       unsigned long   s;
-       xfs_qoff_logitem_t     *qoffi=NULL;
-       uint                    oldsbqflag=0;
-
-       tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF);
-       if ((error = xfs_trans_reserve(tp, 0,
-                                     sizeof(xfs_qoff_logitem_t) * 2 +
-                                     mp->m_sb.sb_sectsize + 128,
-                                     0,
-                                     0,
-                                     XFS_DEFAULT_LOG_COUNT))) {
-               goto error0;
-       }
-
-       qoffi = xfs_trans_get_qoff_item(tp, NULL, flags & XFS_ALL_QUOTA_ACCT);
-       xfs_trans_log_quotaoff_item(tp, qoffi);
-
-       s = XFS_SB_LOCK(mp);
-       oldsbqflag = mp->m_sb.sb_qflags;
-       mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL;
-       XFS_SB_UNLOCK(mp, s);
-
-       xfs_mod_sb(tp, XFS_SB_QFLAGS);
-
-       /*
-        * We have to make sure that the transaction is secure on disk before we
-        * return and actually stop quota accounting. So, make it synchronous.
-        * We don't care about quotoff's performance.
-        */
-       xfs_trans_set_sync(tp);
-       error = xfs_trans_commit(tp, 0, NULL);
-
-error0:
-       if (error) {
-               xfs_trans_cancel(tp, 0);
-               /*
-                * No one else is modifying sb_qflags, so this is OK.
-                * We still hold the quotaofflock.
-                */
-               s = XFS_SB_LOCK(mp);
-               mp->m_sb.sb_qflags = oldsbqflag;
-               XFS_SB_UNLOCK(mp, s);
-       }
-       *qoffstartp = qoffi;
-       return (error);
-}
-
-
-/*
- * Translate an internal style on-disk-dquot to the exportable format.
- * The main differences are that the counters/limits are all in Basic
- * Blocks (BBs) instead of the internal FSBs, and all on-disk data has
- * to be converted to the native endianness.
- */
-STATIC void
-xfs_qm_export_dquot(
-       xfs_mount_t             *mp,
-       xfs_disk_dquot_t        *src,
-       struct fs_disk_quota    *dst)
-{
-       memset(dst, 0, sizeof(*dst));
-       dst->d_version = FS_DQUOT_VERSION;  /* different from src->d_version */
-       dst->d_flags =
-               xfs_qm_export_qtype_flags(INT_GET(src->d_flags, ARCH_CONVERT));
-       dst->d_id = INT_GET(src->d_id, ARCH_CONVERT);
-       dst->d_blk_hardlimit = (__uint64_t)
-               XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_hardlimit, ARCH_CONVERT));
-       dst->d_blk_softlimit = (__uint64_t)
-               XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_softlimit, ARCH_CONVERT));
-       dst->d_ino_hardlimit = (__uint64_t)
-               INT_GET(src->d_ino_hardlimit, ARCH_CONVERT);
-       dst->d_ino_softlimit = (__uint64_t)
-               INT_GET(src->d_ino_softlimit, ARCH_CONVERT);
-       dst->d_bcount = (__uint64_t)
-               XFS_FSB_TO_BB(mp, INT_GET(src->d_bcount, ARCH_CONVERT));
-       dst->d_icount = (__uint64_t) INT_GET(src->d_icount, ARCH_CONVERT);
-       dst->d_btimer = (__uint32_t) INT_GET(src->d_btimer, ARCH_CONVERT);
-       dst->d_itimer = (__uint32_t) INT_GET(src->d_itimer, ARCH_CONVERT);
-       dst->d_iwarns = INT_GET(src->d_iwarns, ARCH_CONVERT);
-       dst->d_bwarns = INT_GET(src->d_bwarns, ARCH_CONVERT);
-
-       dst->d_rtb_hardlimit = (__uint64_t)
-               XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_hardlimit, ARCH_CONVERT));
-       dst->d_rtb_softlimit = (__uint64_t)
-               XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_softlimit, ARCH_CONVERT));
-       dst->d_rtbcount = (__uint64_t)
-               XFS_FSB_TO_BB(mp, INT_GET(src->d_rtbcount, ARCH_CONVERT));
-       dst->d_rtbtimer = (__uint32_t) INT_GET(src->d_rtbtimer, ARCH_CONVERT);
-       dst->d_rtbwarns = INT_GET(src->d_rtbwarns, ARCH_CONVERT);
-
-       /*
-        * Internally, we don't reset all the timers when quota enforcement
-        * gets turned off. No need to confuse the userlevel code,
-        * so return zeroes in that case.
-        */
-       if (! XFS_IS_QUOTA_ENFORCED(mp)) {
-               dst->d_btimer = 0;
-               dst->d_itimer = 0;
-               dst->d_rtbtimer = 0;
-       }
-
-#ifdef DEBUG
-       if (XFS_IS_QUOTA_ENFORCED(mp) && dst->d_id != 0) {
-               if (((int) dst->d_bcount >= (int) dst->d_blk_softlimit) &&
-                   (dst->d_blk_softlimit > 0)) {
-                       ASSERT(dst->d_btimer != 0);
-               }
-               if (((int) dst->d_icount >= (int) dst->d_ino_softlimit) &&
-                   (dst->d_ino_softlimit > 0)) {
-                       ASSERT(dst->d_itimer != 0);
-               }
-       }
-#endif
-}
-
-STATIC uint
-xfs_qm_import_qtype_flags(
-       uint uflags)
-{
-       /*
-        * Can't be both at the same time.
-        */
-       if (((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) ==
-            (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) ||
-           ((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == 0))
-               return (0);
-
-       return (uflags & XFS_USER_QUOTA) ?
-               XFS_DQ_USER : XFS_DQ_GROUP;
-}
-
-STATIC uint
-xfs_qm_export_qtype_flags(
-       uint flags)
-{
-       /*
-        * Can't be both at the same time.
-        */
-       ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) !=
-               (XFS_GROUP_QUOTA | XFS_USER_QUOTA));
-       ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) != 0);
-
-       return (flags & XFS_DQ_USER) ?
-               XFS_USER_QUOTA : XFS_GROUP_QUOTA;
-}
-
-STATIC uint
-xfs_qm_import_flags(
-       uint uflags)
-{
-       uint flags = 0;
-
-       if (uflags & XFS_QUOTA_UDQ_ACCT)
-               flags |= XFS_UQUOTA_ACCT;
-       if (uflags & XFS_QUOTA_GDQ_ACCT)
-               flags |= XFS_GQUOTA_ACCT;
-       if (uflags & XFS_QUOTA_UDQ_ENFD)
-               flags |= XFS_UQUOTA_ENFD;
-       if (uflags & XFS_QUOTA_GDQ_ENFD)
-               flags |= XFS_GQUOTA_ENFD;
-       return (flags);
-}
-
-
-STATIC uint
-xfs_qm_export_flags(
-       uint flags)
-{
-       uint uflags;
-
-       uflags = 0;
-       if (flags & XFS_UQUOTA_ACCT)
-               uflags |= XFS_QUOTA_UDQ_ACCT;
-       if (flags & XFS_GQUOTA_ACCT)
-               uflags |= XFS_QUOTA_GDQ_ACCT;
-       if (flags & XFS_UQUOTA_ENFD)
-               uflags |= XFS_QUOTA_UDQ_ENFD;
-       if (flags & XFS_GQUOTA_ENFD)
-               uflags |= XFS_QUOTA_GDQ_ENFD;
-       return (uflags);
-}
-
-
-/*
- * Go thru all the inodes in the file system, releasing their dquots.
- * Note that the mount structure gets modified to indicate that quotas are off
- * AFTER this, in the case of quotaoff. This also gets called from
- * xfs_rootumount.
- */
-void
-xfs_qm_dqrele_all_inodes(
-       struct xfs_mount *mp,
-       uint             flags)
-{
-       vmap_t          vmap;
-       xfs_inode_t     *ip, *topino;
-       uint            ireclaims;
-       vnode_t         *vp;
-       boolean_t       vnode_refd;
-
-       ASSERT(mp->m_quotainfo);
-
-again:
-       XFS_MOUNT_ILOCK(mp);
-       ip = mp->m_inodes;
-       if (ip == NULL) {
-               XFS_MOUNT_IUNLOCK(mp);
-               return;
-       }
-       do {
-               /* Skip markers inserted by xfs_sync */
-               if (ip->i_mount == NULL) {
-                       ip = ip->i_mnext;
-                       continue;
-               }
-               /* Root inode, rbmip and rsumip have associated blocks */
-               if (ip == XFS_QI_UQIP(mp) || ip == XFS_QI_GQIP(mp)) {
-                       ASSERT(ip->i_udquot == NULL);
-                       ASSERT(ip->i_gdquot == NULL);
-                       ip = ip->i_mnext;
-                       continue;
-               }
-               vp = XFS_ITOV_NULL(ip);
-               if (!vp) {
-                       ASSERT(ip->i_udquot == NULL);
-                       ASSERT(ip->i_gdquot == NULL);
-                       ip = ip->i_mnext;
-                       continue;
-               }
-               vnode_refd = B_FALSE;
-               if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) {
-                       /*
-                        * Sample vp mapping while holding the mplock, lest
-                        * we come across a non-existent vnode.
-                        */
-                       VMAP(vp, vmap);
-                       ireclaims = mp->m_ireclaims;
-                       topino = mp->m_inodes;
-                       XFS_MOUNT_IUNLOCK(mp);
-
-                       /* XXX restart limit ? */
-                       if ( ! (vp = vn_get(vp, &vmap)))
-                               goto again;
-                       xfs_ilock(ip, XFS_ILOCK_EXCL);
-                       vnode_refd = B_TRUE;
-               } else {
-                       ireclaims = mp->m_ireclaims;
-                       topino = mp->m_inodes;
-                       XFS_MOUNT_IUNLOCK(mp);
-               }
-
-               /*
-                * We don't keep the mountlock across the dqrele() call,
-                * since it can take a while..
-                */
-               if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) {
-                       xfs_qm_dqrele(ip->i_udquot);
-                       ip->i_udquot = NULL;
-               }
-               if ((flags & XFS_GQUOTA_ACCT) && ip->i_gdquot) {
-                       xfs_qm_dqrele(ip->i_gdquot);
-                       ip->i_gdquot = NULL;
-               }
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-               /*
-                * Wait until we've dropped the ilock and mountlock to
-                * do the vn_rele. Or be condemned to an eternity in the
-                * inactive code in hell.
-                */
-               if (vnode_refd)
-                       VN_RELE(vp);
-               XFS_MOUNT_ILOCK(mp);
-               /*
-                * If an inode was inserted or removed, we gotta
-                * start over again.
-                */
-               if (topino != mp->m_inodes || mp->m_ireclaims != ireclaims) {
-                       /* XXX use a sentinel */
-                       XFS_MOUNT_IUNLOCK(mp);
-                       goto again;
-               }
-               ip = ip->i_mnext;
-       } while (ip != mp->m_inodes);
-
-       XFS_MOUNT_IUNLOCK(mp);
-}
-
-/*------------------------------------------------------------------------*/
-#ifdef DEBUG
-/*
- * This contains all the test functions for XFS disk quotas.
- * Currently it does a quota accounting check. ie. it walks through
- * all inodes in the file system, calculating the dquot accounting fields,
- * and prints out any inconsistencies.
- */
-xfs_dqhash_t *qmtest_udqtab;
-xfs_dqhash_t *qmtest_gdqtab;
-int          qmtest_hashmask;
-int          qmtest_nfails;
-mutex_t              qcheck_lock;
-
-#define DQTEST_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \
-                                (__psunsigned_t)(id)) & \
-                               (qmtest_hashmask - 1))
-
-#define DQTEST_HASH(mp, id, type)   ((type & XFS_DQ_USER) ? \
-                                    (qmtest_udqtab + \
-                                     DQTEST_HASHVAL(mp, id)) : \
-                                    (qmtest_gdqtab + \
-                                     DQTEST_HASHVAL(mp, id)))
-
-#define DQTEST_LIST_PRINT(l, NXT, title) \
-{ \
-         xfs_dqtest_t  *dqp; int i = 0;\
-         cmn_err(CE_DEBUG, "%s (#%d)", title, (int) (l)->qh_nelems); \
-         for (dqp = (xfs_dqtest_t *)(l)->qh_next; dqp != NULL; \
-              dqp = (xfs_dqtest_t *)dqp->NXT) { \
-               cmn_err(CE_DEBUG, "  %d\. \"%d (%s)\"  bcnt = %d, icnt = %d", \
-                        ++i, dqp->d_id, DQFLAGTO_TYPESTR(dqp),      \
-                        dqp->d_bcount, dqp->d_icount); } \
-}
-
-typedef struct dqtest {
-       xfs_dqmarker_t  q_lists;
-       xfs_dqhash_t    *q_hash;        /* the hashchain header */
-       xfs_mount_t     *q_mount;       /* filesystem this relates to */
-       xfs_dqid_t      d_id;           /* user id or group id */
-       xfs_qcnt_t      d_bcount;       /* # disk blocks owned by the user */
-       xfs_qcnt_t      d_icount;       /* # inodes owned by the user */
-} xfs_dqtest_t;
-
-STATIC void
-xfs_qm_hashinsert(xfs_dqhash_t *h, xfs_dqtest_t *dqp)
-{
-       xfs_dquot_t *d;
-       if (((d) = (h)->qh_next))
-               (d)->HL_PREVP = &((dqp)->HL_NEXT);
-       (dqp)->HL_NEXT = d;
-       (dqp)->HL_PREVP = &((h)->qh_next);
-       (h)->qh_next = (xfs_dquot_t *)dqp;
-       (h)->qh_version++;
-       (h)->qh_nelems++;
-}
-STATIC void
-xfs_qm_dqtest_print(
-       xfs_dqtest_t    *d)
-{
-       cmn_err(CE_DEBUG, "-----------DQTEST DQUOT----------------");
-       cmn_err(CE_DEBUG, "---- dquot ID = %d", d->d_id);
-       cmn_err(CE_DEBUG, "---- type     = %s", XFS_QM_ISUDQ(d)? "USR" : "GRP");
-       cmn_err(CE_DEBUG, "---- fs       = 0x%p", d->q_mount);
-       cmn_err(CE_DEBUG, "---- bcount   = %Lu (0x%x)",
-               d->d_bcount, (int)d->d_bcount);
-       cmn_err(CE_DEBUG, "---- icount   = %Lu (0x%x)",
-               d->d_icount, (int)d->d_icount);
-       cmn_err(CE_DEBUG, "---------------------------");
-}
-
-STATIC void
-xfs_qm_dqtest_failed(
-       xfs_dqtest_t    *d,
-       xfs_dquot_t     *dqp,
-       char            *reason,
-       xfs_qcnt_t      a,
-       xfs_qcnt_t      b,
-       int             error)
-{
-       qmtest_nfails++;
-       if (error)
-               cmn_err(CE_DEBUG, "quotacheck failed id=%d, err=%d\nreason: %s",
-                      INT_GET(d->d_id, ARCH_CONVERT), error, reason);
-       else
-               cmn_err(CE_DEBUG, "quotacheck failed id=%d (%s) [%d != %d]",
-                      INT_GET(d->d_id, ARCH_CONVERT), reason, (int)a, (int)b);
-       xfs_qm_dqtest_print(d);
-       if (dqp)
-               xfs_qm_dqprint(dqp);
-}
-
-STATIC int
-xfs_dqtest_cmp2(
-       xfs_dqtest_t    *d,
-       xfs_dquot_t     *dqp)
-{
-       int err = 0;
-       if (INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) != d->d_icount) {
-               xfs_qm_dqtest_failed(d, dqp, "icount mismatch",
-                       INT_GET(dqp->q_core.d_icount, ARCH_CONVERT),
-                       d->d_icount, 0);
-               err++;
-       }
-       if (INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) != d->d_bcount) {
-               xfs_qm_dqtest_failed(d, dqp, "bcount mismatch",
-                       INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT),
-                       d->d_bcount, 0);
-               err++;
-       }
-       if (INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT) &&
-           INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) >=
-           INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT)) {
-               if (INT_ISZERO(dqp->q_core.d_btimer, ARCH_CONVERT) &&
-                   !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT)) {
-                       cmn_err(CE_DEBUG,
-                               "%d [%s] [0x%p] BLK TIMER NOT STARTED",
-                               d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
-                       err++;
-               }
-       }
-       if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) &&
-           INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >=
-           INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) {
-               if (INT_ISZERO(dqp->q_core.d_itimer, ARCH_CONVERT) &&
-                   !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT)) {
-                       cmn_err(CE_DEBUG,
-                               "%d [%s] [0x%p] INO TIMER NOT STARTED",
-                               d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
-                       err++;
-               }
-       }
-#ifdef QUOTADEBUG
-       if (!err) {
-               cmn_err(CE_DEBUG, "%d [%s] [0x%p] qchecked",
-                       d->d_id, XFS_QM_ISUDQ(d) ? "USR" : "GRP", d->q_mount);
-       }
-#endif
-       return (err);
-}
-
-STATIC void
-xfs_dqtest_cmp(
-       xfs_dqtest_t    *d)
-{
-       xfs_dquot_t     *dqp;
-       int             error;
-
-       /* xfs_qm_dqtest_print(d); */
-       if ((error = xfs_qm_dqget(d->q_mount, NULL, d->d_id, d->dq_flags, 0,
-                                &dqp))) {
-               xfs_qm_dqtest_failed(d, NULL, "dqget failed", 0, 0, error);
-               return;
-       }
-       xfs_dqtest_cmp2(d, dqp);
-       xfs_qm_dqput(dqp);
-}
-
-STATIC int
-xfs_qm_internalqcheck_dqget(
-       xfs_mount_t     *mp,
-       xfs_dqid_t      id,
-       uint            type,
-       xfs_dqtest_t    **O_dq)
-{
-       xfs_dqtest_t    *d;
-       xfs_dqhash_t    *h;
-
-       h = DQTEST_HASH(mp, id, type);
-       for (d = (xfs_dqtest_t *) h->qh_next; d != NULL;
-            d = (xfs_dqtest_t *) d->HL_NEXT) {
-               /* DQTEST_LIST_PRINT(h, HL_NEXT, "@@@@@ dqtestlist @@@@@"); */
-               if (d->d_id == id && mp == d->q_mount) {
-                       *O_dq = d;
-                       return (0);
-               }
-       }
-       d = kmem_zalloc(sizeof(xfs_dqtest_t), KM_SLEEP);
-       d->dq_flags = type;
-       d->d_id = id;
-       d->q_mount = mp;
-       d->q_hash = h;
-       xfs_qm_hashinsert(h, d);
-       *O_dq = d;
-       return (0);
-}
-
-STATIC void
-xfs_qm_internalqcheck_get_dquots(
-       xfs_mount_t     *mp,
-       xfs_dqid_t      uid,
-       xfs_dqid_t      gid,
-       xfs_dqtest_t    **ud,
-       xfs_dqtest_t    **gd)
-{
-       if (XFS_IS_UQUOTA_ON(mp))
-               xfs_qm_internalqcheck_dqget(mp, uid, XFS_DQ_USER, ud);
-       if (XFS_IS_GQUOTA_ON(mp))
-               xfs_qm_internalqcheck_dqget(mp, gid, XFS_DQ_GROUP, gd);
-}
-
-
-STATIC void
-xfs_qm_internalqcheck_dqadjust(
-       xfs_inode_t             *ip,
-       xfs_dqtest_t            *d)
-{
-       d->d_icount++;
-       d->d_bcount += (xfs_qcnt_t)ip->i_d.di_nblocks;
-}
-
-STATIC int
-xfs_qm_internalqcheck_adjust(
-       xfs_mount_t     *mp,            /* mount point for filesystem */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_ino_t       ino,            /* inode number to get data for */
-       void            *buffer,        /* not used */
-       xfs_daddr_t     bno,            /* starting block of inode cluster */
-       void            *dip,           /* not used */
-       int             *res)           /* bulkstat result code */
-{
-       xfs_inode_t             *ip;
-       xfs_dqtest_t            *ud, *gd;
-       uint                    lock_flags;
-       boolean_t               ipreleased;
-       int                     error;
-
-       ASSERT(XFS_IS_QUOTA_RUNNING(mp));
-
-       if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
-               *res = BULKSTAT_RV_NOTHING;
-               qdprintk("internalqcheck: ino=%llu, uqino=%llu, gqino=%llu\n",
-                       (unsigned long long) ino,
-                       (unsigned long long) mp->m_sb.sb_uquotino,
-                       (unsigned long long) mp->m_sb.sb_gquotino);
-               return XFS_ERROR(EINVAL);
-       }
-       ipreleased = B_FALSE;
- again:
-       lock_flags = XFS_ILOCK_SHARED;
-       if ((error = xfs_iget(mp, tp, ino, lock_flags, &ip, bno))) {
-               *res = BULKSTAT_RV_NOTHING;
-               return (error);
-       }
-
-       if (ip->i_d.di_mode == 0) {
-               xfs_iput_new(ip, lock_flags);
-               *res = BULKSTAT_RV_NOTHING;
-               return XFS_ERROR(ENOENT);
-       }
-
-       /*
-        * This inode can have blocks after eof which can get released
-        * when we send it to inactive. Since we don't check the dquot
-        * until the after all our calculations are done, we must get rid
-        * of those now.
-        */
-       if (! ipreleased) {
-               xfs_iput(ip, lock_flags);
-               ipreleased = B_TRUE;
-               goto again;
-       }
-       xfs_qm_internalqcheck_get_dquots(mp,
-                                       (xfs_dqid_t) ip->i_d.di_uid,
-                                       (xfs_dqid_t) ip->i_d.di_gid,
-                                       &ud, &gd);
-       if (XFS_IS_UQUOTA_ON(mp)) {
-               ASSERT(ud);
-               xfs_qm_internalqcheck_dqadjust(ip, ud);
-       }
-       if (XFS_IS_GQUOTA_ON(mp)) {
-               ASSERT(gd);
-               xfs_qm_internalqcheck_dqadjust(ip, gd);
-       }
-       xfs_iput(ip, lock_flags);
-       *res = BULKSTAT_RV_DIDONE;
-       return (0);
-}
-
-
-/* PRIVATE, debugging */
-int
-xfs_qm_internalqcheck(
-       xfs_mount_t     *mp)
-{
-       xfs_ino_t       lastino;
-       int             done, count;
-       int             i;
-       xfs_dqtest_t    *d, *e;
-       xfs_dqhash_t    *h1;
-       int             error;
-
-       lastino = 0;
-       qmtest_hashmask = 32;
-       count = 5;
-       done = 0;
-       qmtest_nfails = 0;
-
-       if (! XFS_IS_QUOTA_ON(mp))
-               return XFS_ERROR(ESRCH);
-
-       xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
-       XFS_bflush(mp->m_ddev_targp);
-       xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
-       XFS_bflush(mp->m_ddev_targp);
-
-       mutex_lock(&qcheck_lock, PINOD);
-       /* There should be absolutely no quota activity while this
-          is going on. */
-       qmtest_udqtab = kmem_zalloc(qmtest_hashmask *
-                                   sizeof(xfs_dqhash_t), KM_SLEEP);
-       qmtest_gdqtab = kmem_zalloc(qmtest_hashmask *
-                                   sizeof(xfs_dqhash_t), KM_SLEEP);
-       do {
-               /*
-                * Iterate thru all the inodes in the file system,
-                * adjusting the corresponding dquot counters
-                */
-               if ((error = xfs_bulkstat(mp, NULL, &lastino, &count,
-                                xfs_qm_internalqcheck_adjust,
-                                0, NULL, BULKSTAT_FG_IGET, &done))) {
-                       break;
-               }
-       } while (! done);
-       if (error) {
-               cmn_err(CE_DEBUG, "Bulkstat returned error 0x%x", error);
-       }
-       cmn_err(CE_DEBUG, "Checking results against system dquots");
-       for (i = 0; i < qmtest_hashmask; i++) {
-               h1 = &qmtest_udqtab[i];
-               for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) {
-                       xfs_dqtest_cmp(d);
-                       e = (xfs_dqtest_t *) d->HL_NEXT;
-                       kmem_free(d, sizeof(xfs_dqtest_t));
-                       d = e;
-               }
-               h1 = &qmtest_gdqtab[i];
-               for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) {
-                       xfs_dqtest_cmp(d);
-                       e = (xfs_dqtest_t *) d->HL_NEXT;
-                       kmem_free(d, sizeof(xfs_dqtest_t));
-                       d = e;
-               }
-       }
-
-       if (qmtest_nfails) {
-               cmn_err(CE_DEBUG, "******** quotacheck failed  ********");
-               cmn_err(CE_DEBUG, "failures = %d", qmtest_nfails);
-       } else {
-               cmn_err(CE_DEBUG, "******** quotacheck successful! ********");
-       }
-       kmem_free(qmtest_udqtab, qmtest_hashmask * sizeof(xfs_dqhash_t));
-       kmem_free(qmtest_gdqtab, qmtest_hashmask * sizeof(xfs_dqhash_t));
-       mutex_unlock(&qcheck_lock);
-       return (qmtest_nfails);
-}
-
-#endif /* DEBUG */
index 063511f20f448d9f0f5542ac1e61617ee16b0fdc..75d1029ceb7701964a73ff0cad57c8336721dc2e 100644 (file)
  *
  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  */
-
 #include <xfs.h>
 
-#define MNTOPT_QUOTA   "quota"         /* disk quotas (user) */
-#define MNTOPT_NOQUOTA "noquota"       /* no quotas */
-#define MNTOPT_USRQUOTA        "usrquota"      /* user quota enabled */
-#define MNTOPT_GRPQUOTA        "grpquota"      /* group quota enabled */
-#define MNTOPT_UQUOTA  "uquota"        /* user quota (IRIX variant) */
-#define MNTOPT_GQUOTA  "gquota"        /* group quota (IRIX variant) */
-#define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */
-#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
-#define MNTOPT_QUOTANOENF  "qnoenforce"        /* same as uqnoenforce */
-
-STATIC int
-xfs_qm_parseargs(
-       struct bhv_desc         *bhv,
-       char                    *options,
-       struct xfs_mount_args   *args,
-       int                     update)
-{
-       size_t                  length;
-       char                    *local_options = options;
-       char                    *this_char;
-       int                     error;
-       int                     referenced = update;
-
-       while ((this_char = strsep(&local_options, ",")) != NULL) {
-               length = strlen(this_char);
-               if (local_options)
-                       length++;
-
-               if (!strcmp(this_char, MNTOPT_NOQUOTA)) {
-                       args->flags &= ~(XFSMNT_UQUOTAENF|XFSMNT_UQUOTA);
-                       args->flags &= ~(XFSMNT_GQUOTAENF|XFSMNT_GQUOTA);
-                       referenced = update;
-               } else if (!strcmp(this_char, MNTOPT_QUOTA) ||
-                          !strcmp(this_char, MNTOPT_UQUOTA) ||
-                          !strcmp(this_char, MNTOPT_USRQUOTA)) {
-                       args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF;
-                       referenced = 1;
-               } else if (!strcmp(this_char, MNTOPT_QUOTANOENF) ||
-                          !strcmp(this_char, MNTOPT_UQUOTANOENF)) {
-                       args->flags |= XFSMNT_UQUOTA;
-                       args->flags &= ~XFSMNT_UQUOTAENF;
-                       referenced = 1;
-               } else if (!strcmp(this_char, MNTOPT_GQUOTA) ||
-                          !strcmp(this_char, MNTOPT_GRPQUOTA)) {
-                       args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF;
-                       referenced = 1;
-               } else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
-                       args->flags |= XFSMNT_GQUOTA;
-                       args->flags &= ~XFSMNT_GQUOTAENF;
-                       referenced = 1;
-               } else {
-                       if (local_options)
-                               *(local_options-1) = ',';
-                       continue;
-               }
-
-               while (length--)
-                       *this_char++ = ',';
-       }
-
-       PVFS_PARSEARGS(BHV_NEXT(bhv), options, args, update, error);
-       if (!error && !referenced)
-               bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_QM);
-       return error;
-}
-
-STATIC int
-xfs_qm_showargs(
-       struct bhv_desc         *bhv,
-       struct seq_file         *m)
-{
-       struct vfs              *vfsp = bhvtovfs(bhv);
-       struct xfs_mount        *mp = XFS_VFSTOM(vfsp);
-       int                     error;
-
-       if (mp->m_qflags & XFS_UQUOTA_ACCT) {
-               (mp->m_qflags & XFS_UQUOTA_ENFD) ?
-                       seq_puts(m, "," MNTOPT_USRQUOTA) :
-                       seq_puts(m, "," MNTOPT_UQUOTANOENF);
-       }
-
-       if (mp->m_qflags & XFS_GQUOTA_ACCT) {
-               (mp->m_qflags & XFS_GQUOTA_ENFD) ?
-                       seq_puts(m, "," MNTOPT_GRPQUOTA) :
-                       seq_puts(m, "," MNTOPT_GQUOTANOENF);
-       }
-
-       if (!(mp->m_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT)))
-               seq_puts(m, "," MNTOPT_NOQUOTA);
-
-       PVFS_SHOWARGS(BHV_NEXT(bhv), m, error);
-       return error;
-}
-
-STATIC int
-xfs_qm_mount(
-       struct bhv_desc         *bhv,
-       struct xfs_mount_args   *args,
-       struct cred             *cr)
+#ifndef CONFIG_XFS_QUOTA
+STATIC struct xfs_dquot *
+xfs_dqvopchown_default(
+       struct xfs_trans        *tp,
+       struct xfs_inode        *ip,
+       struct xfs_dquot        **dqp,
+       struct xfs_dquot        *dq)
 {
-       struct vfs              *vfsp = bhvtovfs(bhv);
-       struct xfs_mount        *mp = XFS_VFSTOM(vfsp);
-       int                     error;
-
-       if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA))
-               xfs_qm_mount_quotainit(mp, args->flags);
-       PVFS_MOUNT(BHV_NEXT(bhv), args, cr, error);
-       return error;
+       return NULL;
 }
 
-STATIC int
-xfs_qm_syncall(
-       struct bhv_desc         *bhv,
-       int                     flags,
-       cred_t                  *credp)
-{
-       struct vfs              *vfsp = bhvtovfs(bhv);
-       struct xfs_mount        *mp = XFS_VFSTOM(vfsp);
-       int                     error;
-
-       /*
-        * Get the Quota Manager to flush the dquots.
-        */
-       if (XFS_IS_QUOTA_ON(mp)) {
-               if ((error = xfs_qm_sync(mp, flags))) {
-                       /*
-                        * If we got an IO error, we will be shutting down.
-                        * So, there's nothing more for us to do here.
-                        */
-                       ASSERT(error != EIO || XFS_FORCED_SHUTDOWN(mp));
-                       if (XFS_FORCED_SHUTDOWN(mp)) {
-                               return XFS_ERROR(error);
-                       }
-               }
-       }
-       PVFS_SYNC(BHV_NEXT(bhv), flags, credp, error);
-       return error;
-}
-
-
-vfsops_t xfs_qmops_xfs = {
-       BHV_IDENTITY_INIT(VFS_BHV_QM, VFS_POSITION_QM),
-       .vfs_parseargs          = xfs_qm_parseargs,
-       .vfs_showargs           = xfs_qm_showargs,
-       .vfs_mount              = xfs_qm_mount,
-       .vfs_sync               = xfs_qm_syncall,
-       .vfs_quotactl           = xfs_qm_quotactl,
+xfs_qmops_t    xfs_qmcore_xfs = {
+       .xfs_qminit             = (xfs_qminit_t) fs_noerr,
+       .xfs_qmdone             = (xfs_qmdone_t) fs_noerr,
+       .xfs_qmmount            = (xfs_qmmount_t) fs_noerr,
+       .xfs_qmunmount          = (xfs_qmunmount_t) fs_noerr,
+       .xfs_dqrele             = (xfs_dqrele_t) fs_noerr,
+       .xfs_dqattach           = (xfs_dqattach_t) fs_noerr,
+       .xfs_dqdetach           = (xfs_dqdetach_t) fs_noerr,
+       .xfs_dqpurgeall         = (xfs_dqpurgeall_t) fs_noerr,
+       .xfs_dqvopalloc         = (xfs_dqvopalloc_t) fs_noerr,
+       .xfs_dqvopcreate        = (xfs_dqvopcreate_t) fs_noerr,
+       .xfs_dqvoprename        = (xfs_dqvoprename_t) fs_noerr,
+       .xfs_dqvopchown         = xfs_dqvopchown_default,
+       .xfs_dqvopchownresv     = (xfs_dqvopchownresv_t) fs_noerr,
 };
+#endif /* CONFIG_XFS_QUOTA */
index 37639212e07d7ea9824bd660ee6e6233cafc9eff..c951c90e9083248daf5c916438f0d0068f3a36bf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
 #ifndef __XFS_QUOTA_H__
 #define __XFS_QUOTA_H__
 
+/*
+ * The ondisk form of a dquot structure.
+ */
+#define XFS_DQUOT_MAGIC                0x4451          /* 'DQ' */
+#define XFS_DQUOT_VERSION      (u_int8_t)0x01  /* latest version number */
+
 /*
  * uid_t and gid_t are hard-coded to 32 bits in the inode.
  * Hence, an 'id' in a dquot is 32 bits..
@@ -46,6 +52,100 @@ typedef __int32_t   xfs_dqid_t;
 typedef __uint64_t     xfs_qcnt_t;
 typedef __uint16_t     xfs_qwarncnt_t;
 
+/*
+ * This is the main portion of the on-disk representation of quota
+ * information for a user. This is the q_core of the xfs_dquot_t that
+ * is kept in kernel memory. We pad this with some more expansion room
+ * to construct the on disk structure.
+ */
+typedef struct xfs_disk_dquot {
+/*16*/ u_int16_t       d_magic;        /* dquot magic = XFS_DQUOT_MAGIC */
+/*8 */ u_int8_t        d_version;      /* dquot version */
+/*8 */ u_int8_t        d_flags;        /* XFS_DQ_USER/PROJ/GROUP */
+/*32*/ xfs_dqid_t      d_id;           /* user,project,group id */
+/*64*/ xfs_qcnt_t      d_blk_hardlimit;/* absolute limit on disk blks */
+/*64*/ xfs_qcnt_t      d_blk_softlimit;/* preferred limit on disk blks */
+/*64*/ xfs_qcnt_t      d_ino_hardlimit;/* maximum # allocated inodes */
+/*64*/ xfs_qcnt_t      d_ino_softlimit;/* preferred inode limit */
+/*64*/ xfs_qcnt_t      d_bcount;       /* disk blocks owned by the user */
+/*64*/ xfs_qcnt_t      d_icount;       /* inodes owned by the user */
+/*32*/ __int32_t       d_itimer;       /* zero if within inode limits if not,
+                                          this is when we refuse service */
+/*32*/ __int32_t       d_btimer;       /* similar to above; for disk blocks */
+/*16*/ xfs_qwarncnt_t  d_iwarns;       /* warnings issued wrt num inodes */
+/*16*/ xfs_qwarncnt_t  d_bwarns;       /* warnings issued wrt disk blocks */
+/*32*/ __int32_t       d_pad0;         /* 64 bit align */
+/*64*/ xfs_qcnt_t      d_rtb_hardlimit;/* absolute limit on realtime blks */
+/*64*/ xfs_qcnt_t      d_rtb_softlimit;/* preferred limit on RT disk blks */
+/*64*/ xfs_qcnt_t      d_rtbcount;     /* realtime blocks owned */
+/*32*/ __int32_t       d_rtbtimer;     /* similar to above; for RT disk blocks */
+/*16*/ xfs_qwarncnt_t  d_rtbwarns;     /* warnings issued wrt RT disk blocks */
+/*16*/ __uint16_t      d_pad;
+} xfs_disk_dquot_t;
+
+/*
+ * This is what goes on disk. This is separated from the xfs_disk_dquot because
+ * carrying the unnecessary padding would be a waste of memory.
+ */
+typedef struct xfs_dqblk {
+       xfs_disk_dquot_t  dd_diskdq;    /* portion that lives incore as well */
+       char              dd_fill[32];  /* filling for posterity */
+} xfs_dqblk_t;
+
+/*
+ * flags for q_flags field in the dquot.
+ */
+#define XFS_DQ_USER            0x0001          /* a user quota */
+/* #define XFS_DQ_PROJ         0x0002          -- project quota (IRIX) */
+#define XFS_DQ_GROUP           0x0004          /* a group quota */
+#define XFS_DQ_FLOCKED         0x0008          /* flush lock taken */
+#define XFS_DQ_DIRTY           0x0010          /* dquot is dirty */
+#define XFS_DQ_WANT            0x0020          /* for lookup/reclaim race */
+#define XFS_DQ_INACTIVE                0x0040          /* dq off mplist & hashlist */
+#define XFS_DQ_MARKER          0x0080          /* sentinel */
+
+/*
+ * In the worst case, when both user and group quotas are on,
+ * we can have a max of three dquots changing in a single transaction.
+ */
+#define XFS_DQUOT_LOGRES(mp)   (sizeof(xfs_disk_dquot_t) * 3)
+
+
+/*
+ * These are the structures used to lay out dquots and quotaoff
+ * records on the log. Quite similar to those of inodes.
+ */
+
+/*
+ * log format struct for dquots.
+ * The first two fields must be the type and size fitting into
+ * 32 bits : log_recovery code assumes that.
+ */
+typedef struct xfs_dq_logformat {
+       __uint16_t              qlf_type;      /* dquot log item type */
+       __uint16_t              qlf_size;      /* size of this item */
+       xfs_dqid_t              qlf_id;        /* usr/grp id number : 32 bits */
+       __int64_t               qlf_blkno;     /* blkno of dquot buffer */
+       __int32_t               qlf_len;       /* len of dquot buffer */
+       __uint32_t              qlf_boffset;   /* off of dquot in buffer */
+} xfs_dq_logformat_t;
+
+/*
+ * log format struct for QUOTAOFF records.
+ * The first two fields must be the type and size fitting into
+ * 32 bits : log_recovery code assumes that.
+ * We write two LI_QUOTAOFF logitems per quotaoff, the last one keeps a pointer
+ * to the first and ensures that the first logitem is taken out of the AIL
+ * only when the last one is securely committed.
+ */
+typedef struct xfs_qoff_logformat {
+       unsigned short          qf_type;        /* quotaoff log item type */
+       unsigned short          qf_size;        /* size of this item */
+       unsigned int            qf_flags;       /* USR and/or GRP */
+       char                    qf_pad[12];     /* padding for future */
+} xfs_qoff_logformat_t;
+
+
 /*
  * Disk quotas status in m_qflags, and also sb_qflags. 16 bits.
  */
@@ -140,7 +240,7 @@ typedef __uint16_t  xfs_qwarncnt_t;
  * The inode cannot go inactive as long a reference is kept, and
  * therefore if dquot(s) were attached, they'll stay consistent.
  * If, for example, the ownership of the inode changes while
- * we didnt have the inode locked, the appropriate dquot(s) will be
+ * we didn't have the inode locked, the appropriate dquot(s) will be
  * attached atomically.
  */
 #define XFS_NOT_DQATTACHED(mp, ip) ((XFS_IS_UQUOTA_ON(mp) &&\
@@ -164,188 +264,91 @@ typedef __uint16_t       xfs_qwarncnt_t;
 #define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME)
 
 
-#ifdef __KERNEL__
-
-#ifdef CONFIG_XFS_QUOTA
-/*
- * External Interface to the XFS disk quota subsystem.
- */
-struct xfs_disk_dquot;
-struct xfs_dqhash;
-struct xfs_dquot;
-struct xfs_inode;
-struct xfs_mount;
-struct xfs_trans;
-
-/*
- * Quota Manager Interface.
- */
-extern struct xfs_qm   *xfs_qm_init(void);
-extern void            xfs_qm_destroy(struct xfs_qm *);
-extern int             xfs_qm_dqflush_all(struct xfs_mount *, int);
-extern int             xfs_qm_dqattach(struct xfs_inode *, uint);
-extern int             xfs_qm_dqpurge_all(struct xfs_mount *, uint);
-extern void            xfs_qm_mount_quotainit(struct xfs_mount *, uint);
-extern void            xfs_qm_unmount_quotadestroy(struct xfs_mount *);
-extern int             xfs_qm_mount_quotas(struct xfs_mount *);
-extern int             xfs_qm_unmount_quotas(struct xfs_mount *);
-extern void            xfs_qm_dqdettach_inode(struct xfs_inode *);
-extern int             xfs_qm_sync(struct xfs_mount *, short);
-
-/*
- * Dquot interface.
- */
-extern void            xfs_dqlock(struct xfs_dquot *);
-extern void            xfs_dqunlock(struct xfs_dquot *);
-extern void            xfs_dqunlock_nonotify(struct xfs_dquot *);
-extern void            xfs_dqlock2(struct xfs_dquot *, struct xfs_dquot *);
-extern void            xfs_qm_dqput(struct xfs_dquot *);
-extern void            xfs_qm_dqrele(struct xfs_dquot *);
-extern xfs_dqid_t      xfs_qm_dqid(struct xfs_dquot *);
-extern int             xfs_qm_dqget(struct xfs_mount *,
-                                    struct xfs_inode *, xfs_dqid_t,
-                                     uint, uint, struct xfs_dquot **);
-extern int             xfs_qm_dqcheck(struct xfs_disk_dquot *,
-                                      xfs_dqid_t, uint, uint, char *);
-
-/*
- * Vnodeops specific code that should actually be _in_ xfs_vnodeops.c, but
- * is here because it's nicer to keep vnodeops (therefore, XFS) lean
- * and clean.
- */
-extern struct xfs_dquot *      xfs_qm_vop_chown(struct xfs_trans *,
-                                                struct xfs_inode *,
-                                                struct xfs_dquot **,
-                                                struct xfs_dquot *);
-extern int             xfs_qm_vop_dqalloc(struct xfs_mount *,
-                                          struct xfs_inode *,
-                                          uid_t, gid_t, uint,
-                                          struct xfs_dquot     **,
-                                          struct xfs_dquot     **);
-
-extern int             xfs_qm_vop_chown_reserve(struct xfs_trans *,
-                                                struct xfs_inode *,
-                                                struct xfs_dquot *,
-                                                struct xfs_dquot *,
-                                                uint);
-
-extern int             xfs_qm_vop_rename_dqattach(struct xfs_inode **);
-extern void            xfs_qm_vop_dqattach_and_dqmod_newinode(
-                                               struct xfs_trans *,
-                                               struct xfs_inode *,
-                                               struct xfs_dquot *,
-                                               struct xfs_dquot *);
-
-
 /*
- * Dquot Transaction interface
+ * The structure kept inside the xfs_trans_t keep track of dquot changes
+ * within a transaction and apply them later.
  */
-extern void            xfs_trans_alloc_dqinfo(struct xfs_trans *);
-extern void            xfs_trans_free_dqinfo(struct xfs_trans *);
-extern void            xfs_trans_dup_dqinfo(struct xfs_trans *,
-                                            struct xfs_trans *);
-extern void            xfs_trans_mod_dquot(struct xfs_trans *,
-                                           struct xfs_dquot *,
-                                           uint, long);
-extern void            xfs_trans_mod_dquot_byino(struct xfs_trans *,
-                                                 struct xfs_inode *,
-                                                 uint, long);
-extern void            xfs_trans_apply_dquot_deltas(struct xfs_trans *);
-extern void            xfs_trans_unreserve_and_mod_dquots(struct xfs_trans *);
-
-extern int             xfs_trans_reserve_quota_nblks(struct xfs_trans *,
-                                                     struct xfs_inode *,
-                                                     long, long, uint);
-
-
-extern int             xfs_trans_reserve_quota_bydquots(struct xfs_trans *,
-                                                        struct xfs_dquot *,
-                                                        struct xfs_dquot *,
-                                                        long, long, uint);
-extern void            xfs_trans_log_dquot(struct xfs_trans *,
-                                           struct xfs_dquot *);
-extern void            xfs_trans_dqjoin(struct xfs_trans *,
-                                        struct xfs_dquot *);
-extern void            xfs_qm_dqrele_all_inodes(struct xfs_mount *, uint);
-
-# define _XQM_ZONE_DESTROY(z)  ((z)? kmem_cache_destroy(z) : (void)0)
-
-#else
-# define xfs_qm_init()                                 (NULL)
-# define xfs_qm_destroy(xqm)                           do { } while (0)
-# define xfs_qm_dqflush_all(m,t)                       (ENOSYS)
-# define xfs_qm_dqattach(i,t)                          (ENOSYS)
-# define xfs_qm_dqpurge_all(m,t)                       (ENOSYS)
-# define xfs_qm_mount_quotainit(m,t)                   do { } while (0)
-# define xfs_qm_unmount_quotadestroy(m)                        do { } while (0)
-# define xfs_qm_mount_quotas(m)                                (ENOSYS)
-# define xfs_qm_unmount_quotas(m)                      (ENOSYS)
-# define xfs_qm_dqdettach_inode(i)                     do { } while (0)
-# define xfs_qm_sync(m,t)                              (ENOSYS)
-# define xfs_dqlock(d)                                 do { } while (0)
-# define xfs_dqunlock(d)                               do { } while (0)
-# define xfs_dqunlock_nonotify(d)                      do { } while (0)
-# define xfs_dqlock2(d1,d2)                            do { } while (0)
-# define xfs_qm_dqput(d)                               do { } while (0)
-# define xfs_qm_dqrele(d)                              do { } while (0)
-# define xfs_qm_dqid(d)                                        (-1)
-# define xfs_qm_dqget(m,i,di,t,f,d)                    (ENOSYS)
-# define xfs_qm_dqcheck(dd,di,t,f,s)                   (ENOSYS)
-# define xfs_trans_alloc_dqinfo(t)                     do { } while (0)
-# define xfs_trans_free_dqinfo(t)                      do { } while (0)
-# define xfs_trans_dup_dqinfo(t1,t2)                   do { } while (0)
-# define xfs_trans_mod_dquot(t,d,f,x)                  do { } while (0)
-# define xfs_trans_mod_dquot_byino(t,i,f,x)            do { } while (0)
-# define xfs_trans_apply_dquot_deltas(t)               do { } while (0)
-# define xfs_trans_unreserve_and_mod_dquots(t)         do { } while (0)
-# define xfs_trans_reserve_quota_nblks(t,i,nb,ni,f)    (ENOSYS)
-# define xfs_trans_reserve_quota_bydquots(t,x,y,b,i,f) (ENOSYS)
-# define xfs_trans_log_dquot(t,d)                      do { } while (0)
-# define xfs_trans_dqjoin(t,d)                         do { } while (0)
-# define xfs_qm_dqrele_all_inodes(m,t)                 do { } while (0)
-# define xfs_qm_vop_chown(t,i,d1,d2)                   (NULL)
-# define xfs_qm_vop_dqalloc(m,i,u,g,f,d1,d2)           (ENOSYS)
-# define xfs_qm_vop_chown_reserve(t,i,d1,d2,f)         (ENOSYS)
-# define xfs_qm_vop_rename_dqattach(i)                 (ENOSYS)
-# define xfs_qm_vop_dqattach_and_dqmod_newinode(t,i,x,y) do { } while (0)
-# define _XQM_ZONE_DESTROY(z)                          do { } while (0)
-#endif /* CONFIG_XFS_QUOTA */
+typedef struct xfs_dqtrx {
+       struct xfs_dquot *qt_dquot;       /* the dquot this refers to */
+       ulong           qt_blk_res;       /* blks reserved on a dquot */
+       ulong           qt_blk_res_used;  /* blks used from the reservation */
+       ulong           qt_ino_res;       /* inode reserved on a dquot */
+       ulong           qt_ino_res_used;  /* inodes used from the reservation */
+       long            qt_bcount_delta;  /* dquot blk count changes */
+       long            qt_delbcnt_delta; /* delayed dquot blk count changes */
+       long            qt_icount_delta;  /* dquot inode count changes */
+       ulong           qt_rtblk_res;     /* # blks reserved on a dquot */
+       ulong           qt_rtblk_res_used;/* # blks used from reservation */
+       long            qt_rtbcount_delta;/* dquot realtime blk changes */
+       long            qt_delrtb_delta;  /* delayed RT blk count changes */
+} xfs_dqtrx_t;
 
 /*
- * Regular disk block quota reservations
+ * Dquot transaction functions, used if quota is enabled.
  */
-#define                xfs_trans_reserve_blkquota(tp, ip, nblks) \
-xfs_trans_reserve_quota_nblks(tp, ip, nblks, 0, XFS_QMOPT_RES_REGBLKS)
-
-#define                xfs_trans_reserve_blkquota_force(tp, ip, nblks) \
-xfs_trans_reserve_quota_nblks(tp, ip, nblks, 0, \
-               XFS_QMOPT_RES_REGBLKS|XFS_QMOPT_FORCE_RES)
-
-#define                xfs_trans_unreserve_blkquota(tp, ip, nblks) \
-(void)xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), 0, XFS_QMOPT_RES_REGBLKS)
-
-#define                xfs_trans_reserve_quota(tp, udq, gdq, nb, ni, f) \
-xfs_trans_reserve_quota_bydquots(tp, udq, gdq, nb, ni, f|XFS_QMOPT_RES_REGBLKS)
-
-#define                xfs_trans_unreserve_quota(tp, ud, gd, b, i, f) \
-xfs_trans_reserve_quota_bydquots(tp, ud, gd, -(b), -(i), f|XFS_QMOPT_RES_REGBLKS)
-
-/*
- * Realtime disk block quota reservations
- */
-#define                xfs_trans_reserve_rtblkquota(mp, tp, ip, nblks) \
-xfs_trans_reserve_quota_nblks(tp, ip, nblks, 0, XFS_QMOPT_RES_RTBLKS)
-
-#define                xfs_trans_unreserve_rtblkquota(tp, ip, nblks) \
-(void)xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), 0, XFS_QMOPT_RES_RTBLKS)
-
-#define                xfs_trans_reserve_rtquota(mp, tp, uq, pq, blks, f) \
-xfs_trans_reserve_quota_bydquots(mp, tp, uq, pq, blks, 0, f|XFS_QMOPT_RES_RTBLKS)
-
-#define                xfs_trans_unreserve_rtquota(tp, uq, pq, blks) \
-xfs_trans_reserve_quota_bydquots(tp, uq, pq, -(blks), XFS_QMOPT_RES_RTBLKS)
-
-
-#endif /* __KERNEL__ */
+typedef void   (*qo_dup_dqinfo_t)(struct xfs_trans *, struct xfs_trans *);
+typedef void   (*qo_mod_dquot_byino_t)(struct xfs_trans *,
+                               struct xfs_inode *, uint, long);
+typedef void   (*qo_free_dqinfo_t)(struct xfs_trans *);
+typedef void   (*qo_apply_dquot_deltas_t)(struct xfs_trans *);
+typedef void   (*qo_unreserve_and_mod_dquots_t)(struct xfs_trans *);
+typedef int    (*qo_reserve_quota_nblks_t)(
+                               struct xfs_trans *, struct xfs_mount *,
+                               struct xfs_inode *, long, long, uint);
+typedef int    (*qo_reserve_quota_bydquots_t)(
+                               struct xfs_trans *, struct xfs_mount *,
+                               struct xfs_dquot *, struct xfs_dquot *,
+                               long, long, uint);
+typedef struct xfs_dqtrxops {
+       qo_dup_dqinfo_t                 qo_dup_dqinfo;
+       qo_free_dqinfo_t                qo_free_dqinfo;
+       qo_mod_dquot_byino_t            qo_mod_dquot_byino;
+       qo_apply_dquot_deltas_t         qo_apply_dquot_deltas;
+       qo_reserve_quota_nblks_t        qo_reserve_quota_nblks;
+       qo_reserve_quota_bydquots_t     qo_reserve_quota_bydquots;
+       qo_unreserve_and_mod_dquots_t   qo_unreserve_and_mod_dquots;
+} xfs_dqtrxops_t;
+
+#define XFS_DQTRXOP(mp, tp, op, args...) \
+                       ((mp)->m_qm_ops.xfs_dqtrxops ? \
+                       ((mp)->m_qm_ops.xfs_dqtrxops->op)(tp, ## args) : 0)
+
+#define XFS_TRANS_DUP_DQINFO(mp, otp, ntp) \
+       XFS_DQTRXOP(mp, otp, qo_dup_dqinfo, ntp)
+#define XFS_TRANS_FREE_DQINFO(mp, tp) \
+       XFS_DQTRXOP(mp, tp, qo_free_dqinfo)
+#define XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, field, delta) \
+       XFS_DQTRXOP(mp, tp, qo_mod_dquot_byino, ip, field, delta)
+#define XFS_TRANS_APPLY_DQUOT_DELTAS(mp, tp) \
+       XFS_DQTRXOP(mp, tp, qo_apply_dquot_deltas)
+#define XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, ninos, fl) \
+       XFS_DQTRXOP(mp, tp, qo_reserve_quota_nblks, mp, ip, nblks, ninos, fl)
+#define XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, nb, ni, fl) \
+       XFS_DQTRXOP(mp, tp, qo_reserve_quota_bydquots, mp, ud, gd, nb, ni, fl)
+#define XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp) \
+       XFS_DQTRXOP(mp, tp, qo_unreserve_and_mod_dquots)
+
+#define XFS_TRANS_RESERVE_BLKQUOTA(mp, tp, ip, nblks) \
+       XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, 0, \
+                               XFS_QMOPT_RES_REGBLKS)
+#define XFS_TRANS_RESERVE_BLKQUOTA_FORCE(mp, tp, ip, nblks) \
+       XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, 0, \
+                               XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES)
+#define XFS_TRANS_UNRESERVE_BLKQUOTA(mp, tp, ip, nblks) \
+       XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, -(nblks), 0, \
+                               XFS_QMOPT_RES_REGBLKS)
+#define XFS_TRANS_RESERVE_QUOTA(mp, tp, ud, gd, nb, ni, f) \
+       XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, nb, ni, \
+                               f | XFS_QMOPT_RES_REGBLKS)
+#define XFS_TRANS_UNRESERVE_QUOTA(mp, tp, ud, gd, nb, ni, f) \
+       XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, -(nb), -(ni), \
+                               f | XFS_QMOPT_RES_REGBLKS)
+
+extern int xfs_qm_dqcheck(xfs_disk_dquot_t *, xfs_dqid_t, uint, uint, char *);
+
+extern struct bhv_vfsops xfs_qmops;
+
+extern void xfs_qm_init(void);
+extern void xfs_qm_exit(void);
 
 #endif /* __XFS_QUOTA_H__ */
diff --git a/fs/xfs/xfs_quota_priv.h b/fs/xfs/xfs_quota_priv.h
deleted file mode 100644 (file)
index d016d2b..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.         Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-#ifndef __XFS_QUOTA_PRIV_H__
-#define __XFS_QUOTA_PRIV_H__
-
-/*
- * Number of bmaps that we ask from bmapi when doing a quotacheck.
- * We make this restriction to keep the memory usage to a minimum.
- */
-#define XFS_DQITER_MAP_SIZE    10
-
-/* Number of dquots that fit in to a dquot block */
-#define XFS_QM_DQPERBLK(mp)    ((mp)->m_quotainfo->qi_dqperchunk)
-
-#define XFS_ISLOCKED_INODE(ip)         (ismrlocked(&(ip)->i_lock, \
-                                           MR_UPDATE | MR_ACCESS) != 0)
-#define XFS_ISLOCKED_INODE_EXCL(ip)    (ismrlocked(&(ip)->i_lock, \
-                                           MR_UPDATE) != 0)
-
-#define XFS_DQ_IS_ADDEDTO_TRX(t, d)    ((d)->q_transp == (t))
-
-#define XFS_QI_MPLRECLAIMS(mp) ((mp)->m_quotainfo->qi_dqreclaims)
-#define XFS_QI_UQIP(mp)                ((mp)->m_quotainfo->qi_uquotaip)
-#define XFS_QI_GQIP(mp)                ((mp)->m_quotainfo->qi_gquotaip)
-#define XFS_QI_DQCHUNKLEN(mp)  ((mp)->m_quotainfo->qi_dqchunklen)
-#define XFS_QI_BTIMELIMIT(mp)  ((mp)->m_quotainfo->qi_btimelimit)
-#define XFS_QI_RTBTIMELIMIT(mp) ((mp)->m_quotainfo->qi_rtbtimelimit)
-#define XFS_QI_ITIMELIMIT(mp)  ((mp)->m_quotainfo->qi_itimelimit)
-#define XFS_QI_BWARNLIMIT(mp)  ((mp)->m_quotainfo->qi_bwarnlimit)
-#define XFS_QI_IWARNLIMIT(mp)  ((mp)->m_quotainfo->qi_iwarnlimit)
-#define XFS_QI_QOFFLOCK(mp)    ((mp)->m_quotainfo->qi_quotaofflock)
-
-#define XFS_QI_MPL_LIST(mp)    ((mp)->m_quotainfo->qi_dqlist)
-#define XFS_QI_MPLLOCK(mp)     ((mp)->m_quotainfo->qi_dqlist.qh_lock)
-#define XFS_QI_MPLNEXT(mp)     ((mp)->m_quotainfo->qi_dqlist.qh_next)
-#define XFS_QI_MPLNDQUOTS(mp)  ((mp)->m_quotainfo->qi_dqlist.qh_nelems)
-
-#define XQMLCK(h)                      (mutex_lock(&((h)->qh_lock), PINOD))
-#define XQMUNLCK(h)                    (mutex_unlock(&((h)->qh_lock)))
-#ifdef DEBUG
-static inline int
-XQMISLCKD(xfs_dqhash_t *h)
-{
-       if (mutex_trylock(&h->qh_lock)) {
-               mutex_unlock(&h->qh_lock);
-               return 0;
-       }
-       return 1;
-}
-#endif
-
-#define XFS_DQ_HASH_LOCK(h)            XQMLCK(h)
-#define XFS_DQ_HASH_UNLOCK(h)          XQMUNLCK(h)
-#define XFS_DQ_IS_HASH_LOCKED(h)       XQMISLCKD(h)
-
-#define xfs_qm_mplist_lock(mp)         XQMLCK(&(XFS_QI_MPL_LIST(mp)))
-#define xfs_qm_mplist_unlock(mp)       XQMUNLCK(&(XFS_QI_MPL_LIST(mp)))
-#define XFS_QM_IS_MPLIST_LOCKED(mp)    XQMISLCKD(&(XFS_QI_MPL_LIST(mp)))
-
-#define xfs_qm_freelist_lock(qm)       XQMLCK(&((qm)->qm_dqfreelist))
-#define xfs_qm_freelist_unlock(qm)     XQMUNLCK(&((qm)->qm_dqfreelist))
-#define XFS_QM_IS_FREELIST_LOCKED(qm)  XQMISLCKD(&((qm)->qm_dqfreelist))
-
-/*
- * Hash into a bucket in the dquot hash table, based on <mp, id>.
- */
-#define XFS_DQ_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \
-                                (__psunsigned_t)(id)) & \
-                               (xfs_Gqm->qm_dqhashmask - 1))
-#define XFS_DQ_HASH(mp, id, type)   (type == XFS_DQ_USER ? \
-                                    (xfs_Gqm->qm_usr_dqhtable + \
-                                     XFS_DQ_HASHVAL(mp, id)) : \
-                                    (xfs_Gqm->qm_grp_dqhtable + \
-                                     XFS_DQ_HASHVAL(mp, id)))
-#define XFS_IS_DQTYPE_ON(mp, type)   (type == XFS_DQ_USER ? \
-                                     XFS_IS_UQUOTA_ON(mp):XFS_IS_GQUOTA_ON(mp))
-#define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \
-       INT_ISZERO(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT) && \
-       INT_ISZERO(dqp->q_core.d_blk_softlimit, ARCH_CONVERT) && \
-       INT_ISZERO(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT) && \
-       INT_ISZERO(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT) && \
-       INT_ISZERO(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) && \
-       INT_ISZERO(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) && \
-       INT_ISZERO(dqp->q_core.d_bcount, ARCH_CONVERT)        && \
-       INT_ISZERO(dqp->q_core.d_rtbcount, ARCH_CONVERT)      && \
-       INT_ISZERO(dqp->q_core.d_icount, ARCH_CONVERT))
-
-#define HL_PREVP       dq_hashlist.ql_prevp
-#define HL_NEXT                dq_hashlist.ql_next
-#define MPL_PREVP      dq_mplist.ql_prevp
-#define MPL_NEXT       dq_mplist.ql_next
-
-
-#define _LIST_REMOVE(h, dqp, PVP, NXT)                         \
-       {                                                       \
-                xfs_dquot_t *d;                                \
-                if (((d) = (dqp)->NXT))                                \
-                        (d)->PVP = (dqp)->PVP;                 \
-                *((dqp)->PVP) = d;                             \
-                (dqp)->NXT = NULL;                             \
-                (dqp)->PVP = NULL;                             \
-                (h)->qh_version++;                             \
-                (h)->qh_nelems--;                              \
-       }
-
-#define _LIST_INSERT(h, dqp, PVP, NXT)                         \
-       {                                                       \
-                xfs_dquot_t *d;                                \
-                if (((d) = (h)->qh_next))                      \
-                        (d)->PVP = &((dqp)->NXT);              \
-                (dqp)->NXT = d;                                \
-                (dqp)->PVP = &((h)->qh_next);                  \
-                (h)->qh_next = dqp;                            \
-                (h)->qh_version++;                             \
-                (h)->qh_nelems++;                              \
-        }
-
-#define FOREACH_DQUOT_IN_MP(dqp, mp) \
-       for ((dqp) = XFS_QI_MPLNEXT(mp); (dqp) != NULL; (dqp) = (dqp)->MPL_NEXT)
-
-#define FOREACH_DQUOT_IN_FREELIST(dqp, qlist)  \
-for ((dqp) = (qlist)->qh_next; (dqp) != (xfs_dquot_t *)(qlist); \
-     (dqp) = (dqp)->dq_flnext)
-
-#define XQM_HASHLIST_INSERT(h, dqp)    \
-        _LIST_INSERT(h, dqp, HL_PREVP, HL_NEXT)
-
-#define XQM_FREELIST_INSERT(h, dqp)    \
-        xfs_qm_freelist_append(h, dqp)
-
-#define XQM_MPLIST_INSERT(h, dqp)      \
-        _LIST_INSERT(h, dqp, MPL_PREVP, MPL_NEXT)
-
-#define XQM_HASHLIST_REMOVE(h, dqp)    \
-        _LIST_REMOVE(h, dqp, HL_PREVP, HL_NEXT)
-#define XQM_FREELIST_REMOVE(dqp)       \
-        xfs_qm_freelist_unlink(dqp)
-#define XQM_MPLIST_REMOVE(h, dqp)      \
-       { _LIST_REMOVE(h, dqp, MPL_PREVP, MPL_NEXT); \
-         XFS_QI_MPLRECLAIMS((dqp)->q_mount)++; }
-
-#define XFS_DQ_IS_LOGITEM_INITD(dqp)   ((dqp)->q_logitem.qli_dquot == (dqp))
-
-#define XFS_QM_DQP_TO_DQACCT(tp, dqp)  (XFS_QM_ISUDQ(dqp) ? \
-                                        (tp)->t_dqinfo->dqa_usrdquots : \
-                                        (tp)->t_dqinfo->dqa_grpdquots)
-#define XFS_IS_SUSER_DQUOT(dqp)                \
-       (INT_ISZERO((dqp)->q_core.d_id, ARCH_CONVERT))
-
-#define XFS_PURGE_INODE(ip)            \
-       {                               \
-         vmap_t dqvmap;                \
-         vnode_t *dqvp;                \
-         dqvp = XFS_ITOV(ip);          \
-         VMAP(dqvp, dqvmap);           \
-         VN_RELE(dqvp);                \
-       }
-
-#define DQFLAGTO_TYPESTR(d)    (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \
-                                (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : "???"))
-#define DQFLAGTO_DIRTYSTR(d)   (XFS_DQ_IS_DIRTY(d) ? "DIRTY" : "NOTDIRTY")
-
-#endif /* __XFS_QUOTA_PRIV_H__ */
index 616c1baf2d0acbbd14fc7097d4eb04659e0c750b..dc6b2b1dd4d44791f17bd9632990de143cba2b6a 100644 (file)
@@ -261,11 +261,12 @@ xfs_rename(
 
        src_dp = XFS_BHVTOI(src_dir_bdp);
        target_dp = XFS_BHVTOI(target_dir_bdp);
+       mp = src_dp->i_mount;
 
        if (DM_EVENT_ENABLED(src_dir_vp->v_vfsp, src_dp, DM_EVENT_RENAME) ||
            DM_EVENT_ENABLED(target_dir_vp->v_vfsp,
                                target_dp, DM_EVENT_RENAME)) {
-               error = dm_send_namesp_event(DM_EVENT_RENAME,
+               error = XFS_SEND_NAMESP(mp, DM_EVENT_RENAME,
                                        src_dir_bdp, DM_RIGHT_NULL,
                                        target_dir_bdp, DM_RIGHT_NULL,
                                        src_name, target_name,
@@ -323,7 +324,6 @@ xfs_rename(
        xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED);
 
        XFS_BMAP_INIT(&free_list, &first_block);
-       mp = src_dp->i_mount;
        tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME);
        cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
        spaceres = XFS_RENAME_SPACE_RES(mp, target_namelen);
@@ -343,12 +343,10 @@ xfs_rename(
        /*
         * Attach the dquots to the inodes
         */
-       if (XFS_IS_QUOTA_ON(mp)) {
-               if ((error = xfs_qm_vop_rename_dqattach(inodes))) {
-                       xfs_trans_cancel(tp, cancel_flags);
-                       rename_which_error_return = __LINE__;
-                       goto rele_return;
-               }
+       if ((error = XFS_QM_DQVOPRENAME(mp, inodes))) {
+               xfs_trans_cancel(tp, cancel_flags);
+               rename_which_error_return = __LINE__;
+               goto rele_return;
        }
 
        /*
@@ -625,7 +623,7 @@ std_return:
        if (DM_EVENT_ENABLED(src_dir_vp->v_vfsp, src_dp, DM_EVENT_POSTRENAME) ||
            DM_EVENT_ENABLED(target_dir_vp->v_vfsp,
                                target_dp, DM_EVENT_POSTRENAME)) {
-               (void) dm_send_namesp_event(DM_EVENT_POSTRENAME,
+               (void) XFS_SEND_NAMESP (mp, DM_EVENT_POSTRENAME,
                                        src_dir_bdp, DM_RIGHT_NULL,
                                        target_dir_bdp, DM_RIGHT_NULL,
                                        src_name, target_name,
index 599ec46ec7a6ac2311d499663a58469f43239a56..fe1050a8ea95e0d2faae98e5747bc6031476cd0e 100644 (file)
@@ -173,11 +173,7 @@ xfs_trans_dup(
        ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used;
        tp->t_rtx_res = tp->t_rtx_res_used;
 
-       /*
-        * dup the dquot stuff too.
-        */
-       if (tp->t_dqinfo)
-               xfs_trans_dup_dqinfo(tp, ntp);
+       XFS_TRANS_DUP_DQINFO(tp->t_mountp, tp, ntp);
 
        atomic_inc(&tp->t_mountp->m_active_trans);
        return ntp;
@@ -703,9 +699,7 @@ shut_us_down:
                 * means is that we have some (non-persistent) quota
                 * reservations that need to be unreserved.
                 */
-               if (tp->t_dqinfo && (tp->t_flags & XFS_TRANS_DQ_DIRTY)) {
-                       xfs_trans_unreserve_and_mod_dquots(tp);
-               }
+               XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp);
                if (tp->t_ticket) {
                        commit_lsn = xfs_log_done(mp, tp->t_ticket,
                                                        NULL, log_flags);
@@ -733,9 +727,7 @@ shut_us_down:
        if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
                xfs_trans_apply_sb_deltas(tp);
        }
-       if (tp->t_flags & XFS_TRANS_DQ_DIRTY) {
-               xfs_trans_apply_dquot_deltas(tp);
-       }
+       XFS_TRANS_APPLY_DQUOT_DELTAS(mp, tp);
 
        /*
         * Ask each log item how many log_vector entries it will
@@ -955,9 +947,7 @@ xfs_trans_uncommit(
        }
 
        xfs_trans_unreserve_and_mod_sb(tp);
-       if (tp->t_dqinfo && (tp->t_flags & XFS_TRANS_DQ_DIRTY)) {
-               xfs_trans_unreserve_and_mod_dquots(tp);
-       }
+       XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(tp->t_mountp, tp);
 
        xfs_trans_free_items(tp, flags);
        xfs_trans_free_busy(tp);
@@ -1079,9 +1069,7 @@ xfs_trans_cancel(
        }
 #endif
        xfs_trans_unreserve_and_mod_sb(tp);
-
-       if (tp->t_dqinfo && (tp->t_flags & XFS_TRANS_DQ_DIRTY))
-               xfs_trans_unreserve_and_mod_dquots(tp);
+       XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(tp->t_mountp, tp);
 
        if (tp->t_ticket) {
                if (flags & XFS_TRANS_RELEASE_LOG_RES) {
@@ -1110,8 +1098,7 @@ xfs_trans_free(
        xfs_trans_t     *tp)
 {
        atomic_dec(&tp->t_mountp->m_active_trans);
-       if (tp->t_dqinfo)
-               xfs_trans_free_dqinfo(tp);
+       XFS_TRANS_FREE_DQINFO(tp->t_mountp, tp);
        kmem_zone_free(xfs_trans_zone, tp);
 }
 
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
deleted file mode 100644 (file)
index 19c83f9..0000000
+++ /dev/null
@@ -1,852 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.         Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include <xfs.h>
-#include <xfs_quota_priv.h>
-
-
-/*
- * Add the locked dquot to the transaction.
- * The dquot must be locked, and it cannot be associated with any
- * transaction.
- */
-void
-xfs_trans_dqjoin(
-       xfs_trans_t     *tp,
-       xfs_dquot_t     *dqp)
-{
-       xfs_dq_logitem_t    *lp;
-
-       ASSERT(! XFS_DQ_IS_ADDEDTO_TRX(tp, dqp));
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-       ASSERT(XFS_DQ_IS_LOGITEM_INITD(dqp));
-       lp = &dqp->q_logitem;
-
-       /*
-        * Get a log_item_desc to point at the new item.
-        */
-       (void) xfs_trans_add_item(tp, (xfs_log_item_t*)(lp));
-
-       /*
-        * Initialize i_transp so we can later determine if this dquot is
-        * associated with this transaction.
-        */
-       dqp->q_transp = tp;
-}
-
-
-/*
- * This is called to mark the dquot as needing
- * to be logged when the transaction is committed.  The dquot must
- * already be associated with the given transaction.
- * Note that it marks the entire transaction as dirty. In the ordinary
- * case, this gets called via xfs_trans_commit, after the transaction
- * is already dirty. However, there's nothing stop this from getting
- * called directly, as done by xfs_qm_scall_setqlim. Hence, the TRANS_DIRTY
- * flag.
- */
-void
-xfs_trans_log_dquot(
-       xfs_trans_t     *tp,
-       xfs_dquot_t     *dqp)
-{
-       xfs_log_item_desc_t     *lidp;
-
-       ASSERT(XFS_DQ_IS_ADDEDTO_TRX(tp, dqp));
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-
-       lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(&dqp->q_logitem));
-       ASSERT(lidp != NULL);
-
-       tp->t_flags |= XFS_TRANS_DIRTY;
-       lidp->lid_flags |= XFS_LID_DIRTY;
-}
-
-/*
- * Carry forward whatever is left of the quota blk reservation to
- * the spanky new transaction
- */
-void
-xfs_trans_dup_dqinfo(
-       xfs_trans_t     *otp,
-       xfs_trans_t     *ntp)
-{
-       xfs_dqtrx_t     *oq, *nq;
-       int             i,j;
-       xfs_dqtrx_t     *oqa, *nqa;
-
-       xfs_trans_alloc_dqinfo(ntp);
-       oqa = otp->t_dqinfo->dqa_usrdquots;
-       nqa = ntp->t_dqinfo->dqa_usrdquots;
-
-       /*
-        * Because the quota blk reservation is carried forward,
-        * it is also necessary to carry forward the DQ_DIRTY flag.
-        */
-       if(otp->t_flags & XFS_TRANS_DQ_DIRTY)
-               ntp->t_flags |= XFS_TRANS_DQ_DIRTY;
-
-       for (j = 0; j < 2; j++) {
-               for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
-                       if (oqa[i].qt_dquot == NULL)
-                               break;
-                       oq = &oqa[i];
-                       nq = &nqa[i];
-
-                       nq->qt_dquot = oq->qt_dquot;
-                       nq->qt_bcount_delta = nq->qt_icount_delta = 0;
-                       nq->qt_rtbcount_delta = 0;
-
-                       /*
-                        * Transfer whatever is left of the reservations.
-                        */
-                       nq->qt_blk_res = oq->qt_blk_res - oq->qt_blk_res_used;
-                       oq->qt_blk_res = oq->qt_blk_res_used;
-
-                       nq->qt_rtblk_res = oq->qt_rtblk_res -
-                               oq->qt_rtblk_res_used;
-                       oq->qt_rtblk_res = oq->qt_rtblk_res_used;
-
-                       nq->qt_ino_res = oq->qt_ino_res - oq->qt_ino_res_used;
-                       oq->qt_ino_res = oq->qt_ino_res_used;
-
-               }
-               oqa = otp->t_dqinfo->dqa_grpdquots;
-               nqa = ntp->t_dqinfo->dqa_grpdquots;
-       }
-}
-
-/*
- * Wrap around mod_dquot to account for both user and group quotas.
- */
-void
-xfs_trans_mod_dquot_byino(
-       xfs_trans_t     *tp,
-       xfs_inode_t     *ip,
-       uint            field,
-       long            delta)
-{
-       ASSERT(tp);
-
-       if (tp->t_dqinfo == NULL)
-               xfs_trans_alloc_dqinfo(tp);
-
-       if (XFS_IS_UQUOTA_ON(tp->t_mountp) && ip->i_udquot) {
-               (void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta);
-       }
-       if (XFS_IS_GQUOTA_ON(tp->t_mountp) && ip->i_gdquot) {
-               (void) xfs_trans_mod_dquot(tp, ip->i_gdquot, field, delta);
-       }
-}
-
-STATIC xfs_dqtrx_t *
-xfs_trans_get_dqtrx(
-       xfs_trans_t     *tp,
-       xfs_dquot_t     *dqp)
-{
-       int             i;
-       xfs_dqtrx_t     *qa;
-
-       for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
-               qa = XFS_QM_DQP_TO_DQACCT(tp, dqp);
-
-               if (qa[i].qt_dquot == NULL ||
-                   qa[i].qt_dquot == dqp) {
-                       return (&qa[i]);
-               }
-       }
-
-       return (NULL);
-}
-
-/*
- * Make the changes in the transaction structure.
- * The moral equivalent to xfs_trans_mod_sb().
- * We don't touch any fields in the dquot, so we don't care
- * if it's locked or not (most of the time it won't be).
- */
-void
-xfs_trans_mod_dquot(
-       xfs_trans_t     *tp,
-       xfs_dquot_t     *dqp,
-       uint            field,
-       long            delta)
-{
-       xfs_dqtrx_t     *qtrx;
-
-       ASSERT(tp);
-       qtrx = NULL;
-
-       if (tp->t_dqinfo == NULL)
-               xfs_trans_alloc_dqinfo(tp);
-       /*
-        * Find either the first free slot or the slot that belongs
-        * to this dquot.
-        */
-       qtrx = xfs_trans_get_dqtrx(tp, dqp);
-       ASSERT(qtrx);
-       if (qtrx->qt_dquot == NULL)
-               qtrx->qt_dquot = dqp;
-
-       switch (field) {
-
-               /*
-                * regular disk blk reservation
-                */
-             case XFS_TRANS_DQ_RES_BLKS:
-               qtrx->qt_blk_res += (ulong)delta;
-               break;
-
-               /*
-                * inode reservation
-                */
-             case XFS_TRANS_DQ_RES_INOS:
-               qtrx->qt_ino_res += (ulong)delta;
-               break;
-
-               /*
-                * disk blocks used.
-                */
-             case XFS_TRANS_DQ_BCOUNT:
-               if (qtrx->qt_blk_res && delta > 0) {
-                       qtrx->qt_blk_res_used += (ulong)delta;
-                       ASSERT(qtrx->qt_blk_res >= qtrx->qt_blk_res_used);
-               }
-               qtrx->qt_bcount_delta += delta;
-               break;
-
-             case XFS_TRANS_DQ_DELBCOUNT:
-               qtrx->qt_delbcnt_delta += delta;
-               break;
-
-               /*
-                * Inode Count
-                */
-             case XFS_TRANS_DQ_ICOUNT:
-               if (qtrx->qt_ino_res && delta > 0) {
-                       qtrx->qt_ino_res_used += (ulong)delta;
-                       ASSERT(qtrx->qt_ino_res >= qtrx->qt_ino_res_used);
-               }
-               qtrx->qt_icount_delta += delta;
-               break;
-
-               /*
-                * rtblk reservation
-                */
-             case XFS_TRANS_DQ_RES_RTBLKS:
-               qtrx->qt_rtblk_res += (ulong)delta;
-               break;
-
-               /*
-                * rtblk count
-                */
-             case XFS_TRANS_DQ_RTBCOUNT:
-               if (qtrx->qt_rtblk_res && delta > 0) {
-                       qtrx->qt_rtblk_res_used += (ulong)delta;
-                       ASSERT(qtrx->qt_rtblk_res >= qtrx->qt_rtblk_res_used);
-               }
-               qtrx->qt_rtbcount_delta += delta;
-               break;
-
-             case XFS_TRANS_DQ_DELRTBCOUNT:
-               qtrx->qt_delrtb_delta += delta;
-               break;
-
-             default:
-               ASSERT(0);
-       }
-       tp->t_flags |= XFS_TRANS_DQ_DIRTY;
-}
-
-
-/*
- * Given an array of dqtrx structures, lock all the dquots associated
- * and join them to the transaction, provided they have been modified.
- * We know that the highest number of dquots (of one type - usr OR grp),
- * involved in a transaction is 2 and that both usr and grp combined - 3.
- * So, we don't attempt to make this very generic.
- */
-STATIC void
-xfs_trans_dqlockedjoin(
-       xfs_trans_t     *tp,
-       xfs_dqtrx_t     *q)
-{
-       ASSERT(q[0].qt_dquot != NULL);
-       if (q[1].qt_dquot == NULL) {
-               xfs_dqlock(q[0].qt_dquot);
-               xfs_trans_dqjoin(tp, q[0].qt_dquot);
-       } else {
-               ASSERT(XFS_QM_TRANS_MAXDQS == 2);
-               xfs_dqlock2(q[0].qt_dquot, q[1].qt_dquot);
-               xfs_trans_dqjoin(tp, q[0].qt_dquot);
-               xfs_trans_dqjoin(tp, q[1].qt_dquot);
-       }
-}
-
-
-/*
- * Called by xfs_trans_commit() and similar in spirit to
- * xfs_trans_apply_sb_deltas().
- * Go thru all the dquots belonging to this transaction and modify the
- * INCORE dquot to reflect the actual usages.
- * Unreserve just the reservations done by this transaction
- * dquot is still left locked at exit.
- */
-void
-xfs_trans_apply_dquot_deltas(
-       xfs_trans_t             *tp)
-{
-       int                     i, j;
-       xfs_dquot_t             *dqp;
-       xfs_dqtrx_t             *qtrx, *qa;
-       xfs_disk_dquot_t        *d;
-       long                    totalbdelta;
-       long                    totalrtbdelta;
-
-       ASSERT(tp->t_dqinfo);
-       qa = tp->t_dqinfo->dqa_usrdquots;
-       for (j = 0; j < 2; j++) {
-               if (qa[0].qt_dquot == NULL) {
-                       qa = tp->t_dqinfo->dqa_grpdquots;
-                       continue;
-               }
-
-               /*
-                * Lock all of the dquots and join them to the transaction.
-                */
-               xfs_trans_dqlockedjoin(tp, qa);
-
-               for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
-                       qtrx = &qa[i];
-                       /*
-                        * The array of dquots is filled
-                        * sequentially, not sparsely.
-                        */
-                       if ((dqp = qtrx->qt_dquot) == NULL)
-                               break;
-
-                       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-                       ASSERT(XFS_DQ_IS_ADDEDTO_TRX(tp, dqp));
-
-                       /*
-                        * adjust the actual number of blocks used
-                        */
-                       d = &dqp->q_core;
-
-                       /*
-                        * The issue here is - sometimes we don't make a blkquota
-                        * reservation intentionally to be fair to users
-                        * (when the amount is small). On the other hand,
-                        * delayed allocs do make reservations, but that's
-                        * outside of a transaction, so we have no
-                        * idea how much was really reserved.
-                        * So, here we've accumulated delayed allocation blks and
-                        * non-delay blks. The assumption is that the
-                        * delayed ones are always reserved (outside of a
-                        * transaction), and the others may or may not have
-                        * quota reservations.
-                        */
-                       totalbdelta = qtrx->qt_bcount_delta +
-                               qtrx->qt_delbcnt_delta;
-                       totalrtbdelta = qtrx->qt_rtbcount_delta +
-                               qtrx->qt_delrtb_delta;
-#ifdef QUOTADEBUG
-                       if (totalbdelta < 0)
-                               ASSERT(INT_GET(d->d_bcount, ARCH_CONVERT) >=
-                                      (xfs_qcnt_t) -totalbdelta);
-
-                       if (totalrtbdelta < 0)
-                               ASSERT(INT_GET(d->d_rtbcount, ARCH_CONVERT) >=
-                                      (xfs_qcnt_t) -totalrtbdelta);
-
-                       if (qtrx->qt_icount_delta < 0)
-                               ASSERT(INT_GET(d->d_icount, ARCH_CONVERT) >=
-                                      (xfs_qcnt_t) -qtrx->qt_icount_delta);
-#endif
-                       if (totalbdelta)
-                               INT_MOD(d->d_bcount, ARCH_CONVERT, (xfs_qcnt_t)totalbdelta);
-
-                       if (qtrx->qt_icount_delta)
-                               INT_MOD(d->d_icount, ARCH_CONVERT, (xfs_qcnt_t)qtrx->qt_icount_delta);
-
-                       if (totalrtbdelta)
-                               INT_MOD(d->d_rtbcount, ARCH_CONVERT, (xfs_qcnt_t)totalrtbdelta);
-
-                       /*
-                        * Start/reset the timer(s) if needed.
-                        */
-                       xfs_qm_adjust_dqtimers(tp->t_mountp, d);
-
-                       dqp->dq_flags |= XFS_DQ_DIRTY;
-                       /*
-                        * add this to the list of items to get logged
-                        */
-                       xfs_trans_log_dquot(tp, dqp);
-                       /*
-                        * Take off what's left of the original reservation.
-                        * In case of delayed allocations, there's no
-                        * reservation that a transaction structure knows of.
-                        */
-                       if (qtrx->qt_blk_res != 0) {
-                               if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) {
-                                       if (qtrx->qt_blk_res >
-                                           qtrx->qt_blk_res_used)
-                                               dqp->q_res_bcount -= (xfs_qcnt_t)
-                                                       (qtrx->qt_blk_res -
-                                                        qtrx->qt_blk_res_used);
-                                       else
-                                               dqp->q_res_bcount -= (xfs_qcnt_t)
-                                                       (qtrx->qt_blk_res_used -
-                                                        qtrx->qt_blk_res);
-                               }
-                       } else {
-                               /*
-                                * These blks were never reserved, either inside
-                                * a transaction or outside one (in a delayed
-                                * allocation). Also, this isn't always a
-                                * negative number since we sometimes
-                                * deliberately skip quota reservations.
-                                */
-                               if (qtrx->qt_bcount_delta) {
-                                       dqp->q_res_bcount +=
-                                             (xfs_qcnt_t)qtrx->qt_bcount_delta;
-                               }
-                       }
-                       /*
-                        * Adjust the RT reservation.
-                        */
-                       if (qtrx->qt_rtblk_res != 0) {
-                               if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) {
-                                       if (qtrx->qt_rtblk_res >
-                                           qtrx->qt_rtblk_res_used)
-                                              dqp->q_res_rtbcount -= (xfs_qcnt_t)
-                                                      (qtrx->qt_rtblk_res -
-                                                       qtrx->qt_rtblk_res_used);
-                                       else
-                                              dqp->q_res_rtbcount -= (xfs_qcnt_t)
-                                                      (qtrx->qt_rtblk_res_used -
-                                                       qtrx->qt_rtblk_res);
-                               }
-                       } else {
-                               if (qtrx->qt_rtbcount_delta)
-                                       dqp->q_res_rtbcount +=
-                                           (xfs_qcnt_t)qtrx->qt_rtbcount_delta;
-                       }
-
-                       /*
-                        * Adjust the inode reservation.
-                        */
-                       if (qtrx->qt_ino_res != 0) {
-                               ASSERT(qtrx->qt_ino_res >=
-                                      qtrx->qt_ino_res_used);
-                               if (qtrx->qt_ino_res > qtrx->qt_ino_res_used)
-                                       dqp->q_res_icount -= (xfs_qcnt_t)
-                                               (qtrx->qt_ino_res -
-                                                qtrx->qt_ino_res_used);
-                       } else {
-                               if (qtrx->qt_icount_delta)
-                                       dqp->q_res_icount +=
-                                           (xfs_qcnt_t)qtrx->qt_icount_delta;
-                       }
-
-
-#ifdef QUOTADEBUG
-                       if (qtrx->qt_rtblk_res != 0)
-                               printk("RT res %d for 0x%p\n",
-                                     (int) qtrx->qt_rtblk_res,
-                                     dqp);
-#endif
-                       ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
-                       ASSERT(dqp->q_res_icount >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
-                       ASSERT(dqp->q_res_rtbcount >= INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT));
-               }
-               /*
-                * Do the group quotas next
-                */
-               qa = tp->t_dqinfo->dqa_grpdquots;
-       }
-}
-
-/*
- * Release the reservations, and adjust the dquots accordingly.
- * This is called only when the transaction is being aborted. If by
- * any chance we have done dquot modifications incore (ie. deltas) already,
- * we simply throw those away, since that's the expected behavior
- * when a transaction is curtailed without a commit.
- */
-void
-xfs_trans_unreserve_and_mod_dquots(
-       xfs_trans_t     *tp)
-{
-       int                     i, j;
-       xfs_dquot_t             *dqp;
-       xfs_dqtrx_t             *qtrx, *qa;
-       boolean_t               locked;
-
-       ASSERT(tp->t_dqinfo);
-       qa = tp->t_dqinfo->dqa_usrdquots;
-
-       for (j = 0; j < 2; j++) {
-               for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
-                       qtrx = &qa[i];
-                       /*
-                        * We assume that the array of dquots is filled
-                        * sequentially, not sparsely.
-                        */
-                       if ((dqp = qtrx->qt_dquot) == NULL)
-                               break;
-                       /*
-                        * Unreserve the original reservation. We don't care
-                        * about the number of blocks used field, or deltas.
-                        * Also we don't bother to zero the fields.
-                        */
-                       locked = B_FALSE;
-                       if (qtrx->qt_blk_res) {
-                               xfs_dqlock(dqp);
-                               locked = B_TRUE;
-                               dqp->q_res_bcount -=
-                                       (xfs_qcnt_t)qtrx->qt_blk_res;
-                       }
-                       if (qtrx->qt_ino_res) {
-                               if (!locked) {
-                                       xfs_dqlock(dqp);
-                                       locked = B_TRUE;
-                               }
-                               dqp->q_res_icount -=
-                                       (xfs_qcnt_t)qtrx->qt_ino_res;
-                       }
-
-                       if (qtrx->qt_rtblk_res) {
-                               if (!locked) {
-                                       xfs_dqlock(dqp);
-                                       locked = B_TRUE;
-                               }
-                               dqp->q_res_rtbcount -=
-                                       (xfs_qcnt_t)qtrx->qt_rtblk_res;
-                       }
-                       if (locked)
-                               xfs_dqunlock(dqp);
-
-               }
-               qa = tp->t_dqinfo->dqa_grpdquots;
-       }
-}
-
-/*
- * This reserves disk blocks and inodes against a dquot.
- * Flags indicate if the dquot is to be locked here and also
- * if the blk reservation is for RT or regular blocks.
- * Sending in XFS_QMOPT_FORCE_RES flag skips the quota check.
- * Returns EDQUOT if quota is exceeded.
- */
-STATIC int
-xfs_trans_dqresv(
-       xfs_trans_t     *tp,
-       xfs_dquot_t     *dqp,
-       long            nblks,
-       long            ninos,
-       uint            flags)
-{
-       int             error;
-       xfs_qcnt_t      hardlimit;
-       xfs_qcnt_t      softlimit;
-       time_t          btimer;
-       xfs_qcnt_t      *resbcountp;
-
-       if (! (flags & XFS_QMOPT_DQLOCK)) {
-               xfs_dqlock(dqp);
-       }
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-       if (flags & XFS_TRANS_DQ_RES_BLKS) {
-               hardlimit = INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT);
-               softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT);
-               btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT);
-               resbcountp = &dqp->q_res_bcount;
-       } else {
-               ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS);
-               hardlimit = INT_GET(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT);
-               softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT);
-               btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT);
-               resbcountp = &dqp->q_res_rtbcount;
-       }
-       error = 0;
-
-       if ((flags & XFS_QMOPT_FORCE_RES) == 0 &&
-           !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT) &&
-           XFS_IS_QUOTA_ENFORCED(dqp->q_mount)) {
-#ifdef QUOTADEBUG
-               printk("BLK Res: nblks=%ld + resbcount=%Ld > hardlimit=%Ld?\n",
-                       nblks, *resbcountp, hardlimit);
-#endif
-               if (nblks > 0) {
-                       /*
-                        * dquot is locked already. See if we'd go over the
-                        * hardlimit or exceed the timelimit if we allocate
-                        * nblks.
-                        */
-                       if (hardlimit > 0ULL &&
-                            (hardlimit <= nblks + *resbcountp)) {
-                               error = EDQUOT;
-                               goto error_return;
-                       }
-
-                       if (softlimit > 0ULL &&
-                            (softlimit <= nblks + *resbcountp)) {
-                               /*
-                                * If timer or warnings has expired,
-                                * return EDQUOT
-                                */
-                               if ((btimer != 0 && get_seconds() > btimer) ||
-                                   (!INT_ISZERO(dqp->q_core.d_bwarns, ARCH_CONVERT) &&
-                                    INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) >=
-                                    XFS_QI_BWARNLIMIT(dqp->q_mount))) {
-                                       error = EDQUOT;
-                                       goto error_return;
-                               }
-                       }
-               }
-               if (ninos > 0) {
-                       if (INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) > 0ULL &&
-                           INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >=
-                           INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT)) {
-                               error = EDQUOT;
-                               goto error_return;
-                       } else if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) > 0ULL &&
-                                  INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >=
-                                  INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) {
-                               /*
-                                * If timer or warnings has expired,
-                                * return EDQUOT
-                                */
-                               if ((!INT_ISZERO(dqp->q_core.d_itimer, ARCH_CONVERT) &&
-                                    get_seconds() > INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)) ||
-                                   (!INT_ISZERO(dqp->q_core.d_iwarns, ARCH_CONVERT) &&
-                                    INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) >=
-                                    XFS_QI_IWARNLIMIT(dqp->q_mount))) {
-                                       error = EDQUOT;
-                                       goto error_return;
-                               }
-                       }
-               }
-       }
-
-       /*
-        * Change the reservation, but not the actual usage.
-        * Note that q_res_bcount = q_core.d_bcount + resv
-        */
-       (*resbcountp) += (xfs_qcnt_t)nblks;
-       if (ninos != 0)
-               dqp->q_res_icount += (xfs_qcnt_t)ninos;
-
-       /*
-        * note the reservation amt in the trans struct too,
-        * so that the transaction knows how much was reserved by
-        * it against this particular dquot.
-        * We don't do this when we are reserving for a delayed allocation,
-        * because we don't have the luxury of a transaction envelope then.
-        */
-       if (tp) {
-               ASSERT(tp->t_dqinfo);
-               ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
-               if (nblks != 0)
-                       xfs_trans_mod_dquot(tp, dqp,
-                                           flags & XFS_QMOPT_RESBLK_MASK,
-                                           nblks);
-               if (ninos != 0)
-                       xfs_trans_mod_dquot(tp, dqp,
-                                           XFS_TRANS_DQ_RES_INOS,
-                                           ninos);
-       }
-       ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT));
-       ASSERT(dqp->q_res_rtbcount >= INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT));
-       ASSERT(dqp->q_res_icount >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT));
-
-error_return:
-       if (! (flags & XFS_QMOPT_DQLOCK)) {
-               xfs_dqunlock(dqp);
-       }
-       return (error);
-}
-
-
-/*
- * Given a dquot(s), make disk block and/or inode reservations against them.
- * The fact that this does the reservation against both the usr and
- * grp quotas is important, because this follows a both-or-nothing
- * approach.
- *
- * flags = XFS_QMOPT_DQLOCK indicate if dquot(s) need to be locked.
- *        XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown.
- *        XFS_TRANS_DQ_RES_BLKS reserves regular disk blocks
- *        XFS_TRANS_DQ_RES_RTBLKS reserves realtime disk blocks
- * dquots are unlocked on return, if they were not locked by caller.
- */
-int
-xfs_trans_reserve_quota_bydquots(
-       xfs_trans_t     *tp,
-       xfs_dquot_t     *udqp,
-       xfs_dquot_t     *gdqp,
-       long            nblks,
-       long            ninos,
-       uint            flags)
-{
-       int             resvd;
-
-       if (tp && tp->t_dqinfo == NULL)
-               xfs_trans_alloc_dqinfo(tp);
-
-       ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
-       resvd = 0;
-
-       if (udqp) {
-               if (xfs_trans_dqresv(tp, udqp, nblks, ninos, flags))
-                       return (EDQUOT);
-               resvd = 1;
-       }
-
-       if (gdqp) {
-               if (xfs_trans_dqresv(tp, gdqp, nblks, ninos, flags)) {
-                       /*
-                        * can't do it, so backout previous reservation
-                        */
-                       if (resvd) {
-                               xfs_trans_dqresv(tp, udqp,  -nblks, -ninos,
-                                                flags);
-                       }
-                       return (EDQUOT);
-               }
-       }
-
-       /*
-        * Didnt change anything critical, so, no need to log
-        */
-       return (0);
-}
-
-
-/*
- * Lock the dquot and change the reservation if we can.
- * This doesn't change the actual usage, just the reservation.
- * The inode sent in is locked.
- *
- * Returns 0 on success, EDQUOT or other errors otherwise
- */
-int
-xfs_trans_reserve_quota_nblks(
-       xfs_trans_t     *tp,
-       xfs_inode_t     *ip,
-       long            nblks,
-       long            ninos,
-       uint            type)
-{
-       int error;
-
-#ifdef QUOTADEBUG
-       if (ip->i_udquot)
-               ASSERT(! XFS_DQ_IS_LOCKED(ip->i_udquot));
-       if (ip->i_gdquot)
-               ASSERT(! XFS_DQ_IS_LOCKED(ip->i_gdquot));
-#endif
-
-       ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
-       ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
-       ASSERT((type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_RTBLKS ||
-              (type & ~XFS_QMOPT_FORCE_RES) == XFS_TRANS_DQ_RES_BLKS);
-
-       /*
-        * Reserve nblks against these dquots, with trans as the mediator.
-        */
-       error = xfs_trans_reserve_quota_bydquots(tp,
-                                                ip->i_udquot, ip->i_gdquot,
-                                                nblks, ninos,
-                                                type);
-       return (error);
-}
-
-/*
- * This routine is called to allocate a quotaoff log item.
- */
-xfs_qoff_logitem_t *
-xfs_trans_get_qoff_item(
-       xfs_trans_t             *tp,
-       xfs_qoff_logitem_t      *startqoff,
-       uint                    flags)
-{
-       xfs_qoff_logitem_t      *q;
-
-       ASSERT(tp != NULL);
-
-       q = xfs_qm_qoff_logitem_init(tp->t_mountp, startqoff, flags);
-       ASSERT(q != NULL);
-
-       /*
-        * Get a log_item_desc to point at the new item.
-        */
-       (void) xfs_trans_add_item(tp, (xfs_log_item_t*)q);
-
-       return (q);
-}
-
-
-/*
- * This is called to mark the quotaoff logitem as needing
- * to be logged when the transaction is committed.  The logitem must
- * already be associated with the given transaction.
- */
-void
-xfs_trans_log_quotaoff_item(
-       xfs_trans_t             *tp,
-       xfs_qoff_logitem_t      *qlp)
-{
-       xfs_log_item_desc_t     *lidp;
-
-       lidp = xfs_trans_find_item(tp, (xfs_log_item_t *)qlp);
-       ASSERT(lidp != NULL);
-
-       tp->t_flags |= XFS_TRANS_DIRTY;
-       lidp->lid_flags |= XFS_LID_DIRTY;
-}
-
-void
-xfs_trans_alloc_dqinfo(
-       xfs_trans_t     *tp)
-{
-       (tp)->t_dqinfo = kmem_zone_zalloc(xfs_Gqm->qm_dqtrxzone, KM_SLEEP);
-}
-
-void
-xfs_trans_free_dqinfo(
-       xfs_trans_t     *tp)
-{
-       kmem_zone_free(xfs_Gqm->qm_dqtrxzone, (tp)->t_dqinfo);
-       (tp)->t_dqinfo = NULL;
-}
index 9059b4261e89c1d641ca8167b109e929775e1e2a..c4d552a134e376d7be05aa43a56716d7b2cdbb4f 100644 (file)
@@ -232,7 +232,7 @@ xfs_dir_ialloc(
                        xfs_buf_relse(ialloc_context);
                        if (dqinfo) {
                                tp->t_dqinfo = dqinfo;
-                               xfs_trans_free_dqinfo(tp);
+                               XFS_TRANS_FREE_DQINFO(tp->t_mountp, tp);
                        }
                        *tpp = ntp;
                        *ipp = NULL;
@@ -254,7 +254,7 @@ xfs_dir_ialloc(
                        *ipp = NULL;
                        return code;
                }
-               xfs_trans_bjoin (tp, ialloc_context);
+               xfs_trans_bjoin(tp, ialloc_context);
 
                /*
                 * Call ialloc again. Since we've locked out all
index 65bb6421472971735e52837fcc73b6777c88a448..dff3827adec403c9349927e6ac86f22617b15f1b 100644 (file)
@@ -68,7 +68,6 @@ xfs_init(void)
        spinlock_init(&xfs_dabuf_global_lock, "xfsda");
 #endif
        mutex_init(&xfs_uuidtabmon, MUTEX_DEFAULT, "xfs_uuidtab");
-       mutex_init(&xfs_Gqm_lock, MUTEX_DEFAULT, "xfs_qmlock");
 
        /*
         * Initialize all of the zone allocators we use.
@@ -175,8 +174,6 @@ xfs_cleanup(void)
        kmem_cache_destroy(xfs_ifork_zone);
        kmem_cache_destroy(xfs_ili_zone);
        kmem_cache_destroy(xfs_chashlist_zone);
-       _XQM_ZONE_DESTROY(qm_dqzone);
-       _XQM_ZONE_DESTROY(qm_dqtrxzone);
        _ACL_ZONE_DESTROY(xfs_acl_zone);
 #if  (defined(DEBUG) || defined(CONFIG_XFS_VNODE_TRACING))
        ktrace_uninit();
@@ -389,6 +386,7 @@ xfs_mount(
        cred_t                  *credp)
 {
        struct vfs              *vfsp = bhvtovfs(bhvp);
+       struct bhv_desc         *p;
        struct xfs_mount        *mp = XFS_BHVTOM(bhvp);
        struct block_device     *ddev, *logdev, *rtdev;
        int                     ronly = (vfsp->vfs_flag & VFS_RDONLY);
@@ -421,28 +419,43 @@ xfs_mount(
                }
        }
 
-       mp->m_io_ops = xfs_iocore_xfs;
+       /*
+        * Setup xfs_mount function vectors from available behaviors
+        */
+       p = vfs_bhv_lookup(vfsp, VFS_POSITION_DM);
+       mp->m_dm_ops = p ? *(xfs_dmops_t *) vfs_bhv_custom(p) : xfs_dmcore_xfs;
+       p = vfs_bhv_lookup(vfsp, VFS_POSITION_QM);
+       mp->m_qm_ops = p ? *(xfs_qmops_t *) vfs_bhv_custom(p) : xfs_qmcore_xfs;
+       p = vfs_bhv_lookup(vfsp, VFS_POSITION_IO);
+       mp->m_io_ops = p ? *(xfs_ioops_t *) vfs_bhv_custom(p) : xfs_iocore_xfs;
 
+       /*
+        * Setup xfs_mount buffer target pointers
+        */
        mp->m_ddev_targp = xfs_alloc_buftarg(ddev);
        if (rtdev)
                mp->m_rtdev_targp = xfs_alloc_buftarg(rtdev);
        mp->m_logdev_targp = (logdev && logdev != ddev) ?
                                xfs_alloc_buftarg(logdev) : mp->m_ddev_targp;
 
+       /*
+        * Setup flags based on mount(2) options and then the superblock
+        */
        error = xfs_start_flags(args, mp, ronly);
        if (error)
                goto error;
-
        error = xfs_readsb(mp);
        if (error)
                goto error;
-
        error = xfs_finish_flags(args, mp, ronly);
        if (error) {
                xfs_freesb(mp);
                goto error;
        }
 
+       /*
+        * Setup xfs_mount buffer target pointers based on superblock
+        */
        xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_blocksize,
                            mp->m_sb.sb_sectsize);
        if (logdev && logdev != ddev) {
@@ -531,16 +544,15 @@ xfs_unmount(
        int             flags,
        cred_t          *credp)
 {
-       xfs_mount_t     *mp;
-       xfs_inode_t     *rip;
-       vnode_t         *rvp = 0;
        struct vfs      *vfsp = bhvtovfs(bdp);
+       xfs_mount_t     *mp = XFS_BHVTOM(bdp);
+       xfs_inode_t     *rip;
+       vnode_t         *rvp;
        int             unmount_event_wanted = 0;
        int             unmount_event_flags = 0;
        int             xfs_unmountfs_needed = 0;
        int             error;
 
-       mp = XFS_BHVTOM(bdp);
        rip = mp->m_rootip;
        rvp = XFS_ITOV(rip);
 
@@ -548,7 +560,7 @@ xfs_unmount(
                bhv_desc_t      *rbdp;
 
                rbdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(rvp), &xfs_vnodeops);
-               error = dm_send_namesp_event(DM_EVENT_PREUNMOUNT,
+               error = XFS_SEND_NAMESP(mp, DM_EVENT_PREUNMOUNT,
                                rbdp, DM_RIGHT_NULL, rbdp, DM_RIGHT_NULL,
                                NULL, NULL, 0, 0,
                                (mp->m_dmevmask & (1<<DM_EVENT_PREUNMOUNT))?
@@ -601,9 +613,9 @@ out:
         */
        if (unmount_event_wanted) {
                /* Note: mp structure must still exist for
-                * dm_send_unmount_event() call.
+                * XFS_SEND_UNMOUNT() call.
                 */
-               dm_send_unmount_event(vfsp, error == 0 ? rvp : NULL,
+               XFS_SEND_UNMOUNT(mp, vfsp, error == 0 ? rvp : NULL,
                        DM_RIGHT_NULL, 0, error, unmount_event_flags);
        }
        if (xfs_unmountfs_needed) {
@@ -679,7 +691,7 @@ xfs_unmount_flush(
         * Release dquot that rootinode, rbmino and rsumino might be holding,
         * flush and purge the quota inodes.
         */
-       error = xfs_qm_unmount_quotas(mp);
+       error = XFS_QM_UNMOUNT(mp);
        if (error == EFSCORRUPTED)
                goto fscorrupt_out2;
 
index 593384e38a54a015018472c8d5c460406dbe2796..1ad2d54f7027c626e030f1127be5691eb92efbc2 100644 (file)
@@ -254,28 +254,26 @@ xfs_getattr(
  */
 STATIC int
 xfs_setattr(
-       bhv_desc_t      *bdp,
-       vattr_t         *vap,
-       int             flags,
-       cred_t          *credp)
+       bhv_desc_t              *bdp,
+       vattr_t                 *vap,
+       int                     flags,
+       cred_t                  *credp)
 {
-       xfs_inode_t     *ip;
-       xfs_trans_t     *tp;
-       xfs_mount_t     *mp;
-       int             mask;
-       int             code;
-       uint            lock_flags;
-       uint            commit_flags=0;
-       uid_t           uid=0, iuid=0;
-       gid_t           gid=0, igid=0;
-       int             timeflags = 0;
-       vnode_t         *vp;
-       xfs_prid_t      projid=0, iprojid=0;
-       int             privileged;
-       int             mandlock_before, mandlock_after;
-       uint            qflags;
-       xfs_dquot_t     *udqp, *gdqp, *olddquot1, *olddquot2;
-       int             file_owner;
+       xfs_inode_t             *ip;
+       xfs_trans_t             *tp;
+       xfs_mount_t             *mp;
+       int                     mask;
+       int                     code;
+       uint                    lock_flags;
+       uint                    commit_flags=0;
+       uid_t                   uid=0, iuid=0;
+       gid_t                   gid=0, igid=0;
+       int                     timeflags = 0;
+       vnode_t                 *vp;
+       xfs_prid_t              projid=0, iprojid=0;
+       int                     mandlock_before, mandlock_after;
+       struct xfs_dquot        *udqp, *gdqp, *olddquot1, *olddquot2;
+       int                     file_owner;
 
        vp = BHV_TO_VNODE(bdp);
        vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
@@ -319,7 +317,8 @@ xfs_setattr(
         * because the i_*dquot fields will get updated anyway.
         */
        if (XFS_IS_QUOTA_ON(mp) && (mask & (XFS_AT_UID|XFS_AT_GID))) {
-               qflags = 0;
+               uint    qflags = 0;
+
                if (mask & XFS_AT_UID) {
                        uid = vap->va_uid;
                        qflags |= XFS_QMOPT_UQUOTA;
@@ -339,8 +338,8 @@ xfs_setattr(
                 */
                ASSERT(udqp == NULL);
                ASSERT(gdqp == NULL);
-               if ((code = xfs_qm_vop_dqalloc(mp, ip, uid, gid, qflags,
-                                                   &udqp, &gdqp)))
+               code = XFS_QM_DQVOPALLOC(mp, ip, uid,gid, qflags, &udqp, &gdqp);
+               if (code)
                        return (code);
        }
 
@@ -365,7 +364,7 @@ xfs_setattr(
        } else {
                if (DM_EVENT_ENABLED (vp->v_vfsp, ip, DM_EVENT_TRUNCATE) &&
                    !(flags & ATTR_DMI)) {
-                       code = xfs_dm_send_data_event (DM_EVENT_TRUNCATE, bdp,
+                       code = XFS_SEND_DATA(mp, DM_EVENT_TRUNCATE, bdp,
                                vap->va_size, 0, AT_DELAY_FLAG(flags), NULL);
                        if (code) {
                                lock_flags = 0;
@@ -482,15 +481,10 @@ xfs_setattr(
                if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||
                    (XFS_IS_GQUOTA_ON(mp) && igid != gid)) {
                        ASSERT(tp);
-                       /*
-                        * XXX:casey - This may result in unnecessary auditing.
-                        */
-                       privileged = capable(CAP_FOWNER);
-                       if ((code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
-                                                         privileged ?
-                                                         XFS_QMOPT_FORCE_RES :
-                                                         0)))
-                               /* out of quota */
+                       code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp,
+                                               capable(CAP_FOWNER) ?
+                                               XFS_QMOPT_FORCE_RES : 0);
+                       if (code)       /* out of quota */
                                goto error_return;
                }
        }
@@ -520,10 +514,8 @@ xfs_setattr(
                /*
                 * Make sure that the dquots are attached to the inode.
                 */
-               if (XFS_IS_QUOTA_ON(mp) && XFS_NOT_DQATTACHED(mp, ip)) {
-                       if ((code = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED)))
-                               goto error_return;
-               }
+               if ((code = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED)))
+                       goto error_return;
        }
 
        /*
@@ -730,13 +722,8 @@ xfs_setattr(
                        if (XFS_IS_UQUOTA_ON(mp)) {
                                ASSERT(mask & XFS_AT_UID);
                                ASSERT(udqp);
-                               ASSERT(xfs_qm_dqid(udqp) == (xfs_dqid_t)uid);
-                               olddquot1 = xfs_qm_vop_chown(tp, ip,
-                                                            &ip->i_udquot,
-                                                            udqp);
-                               /*
-                                * We'll dqrele olddquot at the end.
-                                */
+                               olddquot1 = XFS_QM_DQVOPCHOWN(mp, tp, ip,
+                                                       &ip->i_udquot, udqp);
                        }
                        ip->i_d.di_uid = uid;
                }
@@ -744,10 +731,8 @@ xfs_setattr(
                        if (XFS_IS_GQUOTA_ON(mp)) {
                                ASSERT(mask & XFS_AT_GID);
                                ASSERT(gdqp);
-                               ASSERT(xfs_qm_dqid(gdqp) == gid);
-                               olddquot2 = xfs_qm_vop_chown(tp, ip,
-                                                            &ip->i_gdquot,
-                                                            gdqp);
+                               olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip,
+                                                       &ip->i_gdquot, gdqp);
                        }
                        ip->i_d.di_gid = gid;
                }
@@ -802,9 +787,6 @@ xfs_setattr(
                        ip->i_d.di_flags = 0;
                        if (vap->va_xflags & XFS_XFLAG_REALTIME) {
                                ip->i_d.di_flags |= XFS_DIFLAG_REALTIME;
-                               /* This is replicated in the io core for
-                                * CXFS use
-                                */
                                ip->i_iocore.io_flags |= XFS_IOCORE_RT;
                        }
                        /* can't set PREALLOC this way, just ignore it */
@@ -866,16 +848,12 @@ xfs_setattr(
        xfs_iunlock(ip, lock_flags);
 
        /*
-        * release any dquot(s) inode had kept before chown
+        * Release any dquot(s) the inode had kept before chown.
         */
-       if (olddquot1)
-               xfs_qm_dqrele(olddquot1);
-       if (olddquot2)
-               xfs_qm_dqrele(olddquot2);
-       if (udqp)
-               xfs_qm_dqrele(udqp);
-       if (gdqp)
-               xfs_qm_dqrele(gdqp);
+       XFS_QM_DQRELE(mp, olddquot1);
+       XFS_QM_DQRELE(mp, olddquot2);
+       XFS_QM_DQRELE(mp, udqp);
+       XFS_QM_DQRELE(mp, gdqp);
 
        if (code) {
                return code;
@@ -883,9 +861,9 @@ xfs_setattr(
 
        if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_ATTRIBUTE) &&
            !(flags & ATTR_DMI)) {
-               (void) dm_send_namesp_event (DM_EVENT_ATTRIBUTE, bdp, DM_RIGHT_NULL,
-                               NULL, DM_RIGHT_NULL, NULL, NULL,
-                       0, 0, AT_DELAY_FLAG(flags));
+               (void) XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, bdp, DM_RIGHT_NULL,
+                                       NULL, DM_RIGHT_NULL, NULL, NULL,
+                                       0, 0, AT_DELAY_FLAG(flags));
        }
        return 0;
 
@@ -893,10 +871,8 @@ xfs_setattr(
        commit_flags |= XFS_TRANS_ABORT;
        /* FALLTHROUGH */
  error_return:
-       if (udqp)
-               xfs_qm_dqrele(udqp);
-       if (gdqp)
-               xfs_qm_dqrele(gdqp);
+       XFS_QM_DQRELE(mp, udqp);
+       XFS_QM_DQRELE(mp, gdqp);
        if (tp) {
                xfs_trans_cancel(tp, commit_flags);
        }
@@ -1286,14 +1262,8 @@ xfs_inactive_free_eofblocks(
                /*
                 * Attach the dquots to the inode up front.
                 */
-               if (XFS_IS_QUOTA_ON(mp) &&
-                   ip->i_ino != mp->m_sb.sb_uquotino &&
-                   ip->i_ino != mp->m_sb.sb_gquotino) {
-                       if (XFS_NOT_DQATTACHED(mp, ip)) {
-                               if ((error = xfs_qm_dqattach(ip, 0)))
-                                       return (error);
-                       }
-               }
+               if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+                       return (error);
 
                /*
                 * There are blocks after the end of file.
@@ -1683,7 +1653,7 @@ xfs_inactive(
 
        if (ip->i_d.di_nlink == 0 &&
            DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_DESTROY)) {
-               (void) dm_send_destroy_event(bdp, DM_RIGHT_NULL);
+               (void) XFS_SEND_DESTROY(mp, bdp, DM_RIGHT_NULL);
        }
 
        error = 0;
@@ -1709,14 +1679,9 @@ xfs_inactive(
 
        ASSERT(ip->i_d.di_nlink == 0);
 
-       if (XFS_IS_QUOTA_ON(mp) &&
-           ip->i_ino != mp->m_sb.sb_uquotino &&
-           ip->i_ino != mp->m_sb.sb_gquotino) {
-               if (XFS_NOT_DQATTACHED(mp, ip)) {
-                       if ((error = xfs_qm_dqattach(ip, 0)))
-                               return (VN_INACTIVE_CACHE);
-               }
-       }
+       if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+               return (VN_INACTIVE_CACHE);
+
        tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
        if (truncate) {
                /*
@@ -1826,20 +1791,18 @@ xfs_inactive(
                 * might do that, we need to make sure.  Otherwise the
                 * inode might be lost for a long time or forever.
                 */
-               if (!XFS_FORCED_SHUTDOWN(tp->t_mountp)) {
+               if (!XFS_FORCED_SHUTDOWN(mp)) {
                        cmn_err(CE_NOTE,
-                               "xfs_inactive:  xfs_ifree() returned an error = %d on %s",
-                               error,tp->t_mountp->m_fsname);
-                       xfs_force_shutdown(tp->t_mountp, XFS_METADATA_IO_ERROR);
+               "xfs_inactive:  xfs_ifree() returned an error = %d on %s",
+                               error, mp->m_fsname);
+                       xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR);
                }
                xfs_trans_cancel(tp, commit_flags | XFS_TRANS_ABORT);
        } else {
                /*
                 * Credit the quota account(s). The inode is gone.
                 */
-               if (XFS_IS_QUOTA_ON(tp->t_mountp))
-                       xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT,
-                                                        -1);
+               XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_ICOUNT, -1);
 
                /*
                 * Just ignore errors at this point.  There is
@@ -1850,8 +1813,7 @@ xfs_inactive(
        /*
         * Release the dquots held by inode, if any.
         */
-       if (ip->i_udquot || ip->i_gdquot)
-               xfs_qm_dqdettach_inode(ip);
+       XFS_QM_DQDETACH(mp, ip);
 
        xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
 
@@ -1925,7 +1887,7 @@ xfs_create(
        uint                    cancel_flags;
        int                     committed;
        xfs_prid_t              prid;
-       xfs_dquot_t             *udqp, *gdqp;
+       struct xfs_dquot        *udqp, *gdqp;
        uint                    resblks;
        int                     dm_di_mode;
        int                     namelen;
@@ -1935,22 +1897,22 @@ xfs_create(
        vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address);
 
        dp = XFS_BHVTOI(dir_bdp);
+       mp = dp->i_mount;
 
        dm_di_mode = vap->va_mode|VTTOIF(vap->va_type);
        namelen = VNAMELEN(dentry);
 
        if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) {
-               error = dm_send_namesp_event(DM_EVENT_CREATE,
+               error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,
                                dir_bdp, DM_RIGHT_NULL, NULL,
                                DM_RIGHT_NULL, name, NULL,
                                dm_di_mode, 0, 0);
+
                if (error)
                        return error;
                dm_event_sent = 1;
        }
 
-       mp = dp->i_mount;
-
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
 
@@ -1965,14 +1927,10 @@ xfs_create(
        /*
         * Make sure that we have allocated dquot(s) on disk.
         */
-       if (XFS_IS_QUOTA_ON(mp)) {
-               error = xfs_qm_vop_dqalloc(mp, dp,
-                                          current->fsuid, current->fsgid,
-                                          XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT,
-                                          &udqp, &gdqp);
-               if (error)
-                       goto std_return;
-       }
+       error = XFS_QM_DQVOPALLOC(mp, dp, current->fsuid, current->fsgid,
+                       XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp);
+       if (error)
+               goto std_return;
 
        ip = NULL;
        dp_joined_to_trans = B_FALSE;
@@ -2008,13 +1966,10 @@ xfs_create(
        /*
         * Reserve disk quota and the inode.
         */
-       if (XFS_IS_QUOTA_ON(mp)) {
-               if (xfs_trans_reserve_quota(tp, udqp, gdqp, resblks,
-                                           1, 0)) {
-                       error = EDQUOT;
-                       goto error_return;
-               }
-       }
+       error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
+       if (error)
+               goto error_return;
+
        if (resblks == 0 &&
            (error = XFS_DIR_CANENTER(mp, tp, dp, name, namelen)))
                goto error_return;
@@ -2074,9 +2029,7 @@ xfs_create(
         * These ids of the inode couldn't have changed since the new
         * inode has been locked ever since it was created.
         */
-       if (XFS_IS_QUOTA_ON(mp))
-               xfs_qm_vop_dqattach_and_dqmod_newinode(tp, ip, udqp,
-                                                      gdqp);
+       XFS_QM_DQVOPCREATE(mp, tp, ip, udqp, gdqp);
 
        /*
         * xfs_trans_commit normally decrements the vnode ref count
@@ -2099,10 +2052,8 @@ xfs_create(
                goto error_return;
        }
 
-       if (udqp)
-               xfs_qm_dqrele(udqp);
-       if (gdqp)
-               xfs_qm_dqrele(gdqp);
+       XFS_QM_DQRELE(mp, udqp);
+       XFS_QM_DQRELE(mp, gdqp);
 
        /*
         * Propogate the fact that the vnode changed after the
@@ -2118,7 +2069,7 @@ std_return:
        if ( (*vpp || (error != 0 && dm_event_sent != 0)) &&
                        DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp),
                                                        DM_EVENT_POSTCREATE)) {
-               (void) dm_send_namesp_event(DM_EVENT_POSTCREATE,
+               (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE,
                        dir_bdp, DM_RIGHT_NULL,
                        *vpp ? vn_bhv_lookup_unlocked(VN_BHV_HEAD(vp), &xfs_vnodeops):NULL,
                        DM_RIGHT_NULL, name, NULL,
@@ -2136,10 +2087,8 @@ std_return:
 
        if (!dp_joined_to_trans && (dp != NULL))
                xfs_iunlock(dp, XFS_ILOCK_EXCL);
-       if (udqp)
-               xfs_qm_dqrele(udqp);
-       if (gdqp)
-               xfs_qm_dqrele(gdqp);
+       XFS_QM_DQRELE(mp, udqp);
+       XFS_QM_DQRELE(mp, gdqp);
 
        goto std_return;
 
@@ -2153,10 +2102,8 @@ std_return:
        xfs_trans_cancel(tp, cancel_flags);
        IRELE(ip);
 
-       if (udqp)
-               xfs_qm_dqrele(udqp);
-       if (gdqp)
-               xfs_qm_dqrele(gdqp);
+       XFS_QM_DQRELE(mp, udqp);
+       XFS_QM_DQRELE(mp, gdqp);
 
        goto std_return;
 }
@@ -2437,8 +2384,8 @@ xfs_remove(
        namelen = VNAMELEN(dentry);
 
        if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) {
-               error = dm_send_namesp_event(DM_EVENT_REMOVE, dir_bdp, DM_RIGHT_NULL,
-                                       NULL, DM_RIGHT_NULL,
+               error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, dir_bdp,
+                                       DM_RIGHT_NULL, NULL, DM_RIGHT_NULL,
                                        name, NULL, 0, 0, 0);
                if (error)
                        return error;
@@ -2471,17 +2418,13 @@ xfs_remove(
 
        ITRACE(ip);
 
-       if (XFS_IS_QUOTA_ON(mp)) {
-               ASSERT(! error);
-               if (XFS_NOT_DQATTACHED(mp, dp))
-                       error = xfs_qm_dqattach(dp, 0);
-               if (!error && dp != ip && XFS_NOT_DQATTACHED(mp, ip))
-                       error = xfs_qm_dqattach(ip, 0);
-               if (error) {
-                       REMOVE_DEBUG_TRACE(__LINE__);
-                       IRELE(ip);
-                       goto std_return;
-               }
+       error = XFS_QM_DQATTACH(mp, dp, 0);
+       if (!error && dp != ip)
+               error = XFS_QM_DQATTACH(mp, ip, 0);
+       if (error) {
+               REMOVE_DEBUG_TRACE(__LINE__);
+               IRELE(ip);
+               goto std_return;
        }
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE);
@@ -2606,7 +2549,7 @@ xfs_remove(
  std_return:
        if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp,
                                                DM_EVENT_POSTREMOVE)) {
-               (void) dm_send_namesp_event(DM_EVENT_POSTREMOVE,
+               (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE,
                                dir_bdp, DM_RIGHT_NULL,
                                NULL, DM_RIGHT_NULL,
                                name, NULL, dm_di_mode, error, 0);
@@ -2690,7 +2633,7 @@ xfs_link(
                return XFS_ERROR(EIO);
 
        if (DM_EVENT_ENABLED(src_vp->v_vfsp, tdp, DM_EVENT_LINK)) {
-               error = dm_send_namesp_event(DM_EVENT_LINK,
+               error = XFS_SEND_NAMESP(mp, DM_EVENT_LINK,
                                        target_dir_bdp, DM_RIGHT_NULL,
                                        src_bdp, DM_RIGHT_NULL,
                                        target_name, NULL, 0, 0, 0);
@@ -2700,15 +2643,11 @@ xfs_link(
 
        /* Return through std_return after this point. */
 
-       if (XFS_IS_QUOTA_ON(mp)) {
-               error = 0;
-               if (XFS_NOT_DQATTACHED(mp, sip))
-                       error = xfs_qm_dqattach(sip, 0);
-               if (!error && sip != tdp && XFS_NOT_DQATTACHED(mp, tdp))
-                       error = xfs_qm_dqattach(tdp, 0);
-               if (error)
-                       goto std_return;
-       }
+       error = XFS_QM_DQATTACH(mp, sip, 0);
+       if (!error && sip != tdp)
+               error = XFS_QM_DQATTACH(mp, tdp, 0);
+       if (error)
+               goto std_return;
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_LINK);
        cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
@@ -2798,7 +2737,7 @@ xfs_link(
 std_return:
        if (DM_EVENT_ENABLED(src_vp->v_vfsp, sip,
                                                DM_EVENT_POSTLINK)) {
-               (void) dm_send_namesp_event(DM_EVENT_POSTLINK,
+               (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTLINK,
                                target_dir_bdp, DM_RIGHT_NULL,
                                src_bdp, DM_RIGHT_NULL,
                                target_name, NULL, 0, error, 0);
@@ -2813,8 +2752,6 @@ std_return:
 
        goto std_return;
 }
-
-
 /*
  * xfs_mkdir
  *
@@ -2844,7 +2781,7 @@ xfs_mkdir(
        boolean_t               created = B_FALSE;
        int                     dm_event_sent = 0;
        xfs_prid_t              prid;
-       xfs_dquot_t             *udqp, *gdqp;
+       struct xfs_dquot        *udqp, *gdqp;
        uint                    resblks;
        int                     dm_di_mode;
        int                     dir_namelen;
@@ -2863,7 +2800,7 @@ xfs_mkdir(
        dm_di_mode = vap->va_mode|VTTOIF(vap->va_type);
 
        if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) {
-               error = dm_send_namesp_event(DM_EVENT_CREATE,
+               error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE,
                                        dir_bdp, DM_RIGHT_NULL, NULL,
                                        DM_RIGHT_NULL, dir_name, NULL,
                                        dm_di_mode, 0, 0);
@@ -2886,14 +2823,10 @@ xfs_mkdir(
        /*
         * Make sure that we have allocated dquot(s) on disk.
         */
-       if (XFS_IS_QUOTA_ON(mp)) {
-               error = xfs_qm_vop_dqalloc(mp, dp,
-                                          current->fsuid, current->fsgid,
-                                          XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT,
-                                          &udqp, &gdqp);
-               if (error)
-                       goto std_return;
-       }
+       error = XFS_QM_DQVOPALLOC(mp, dp, current->fsuid, current->fsgid,
+                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
+       if (error)
+               goto std_return;
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR);
        cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
@@ -2925,12 +2858,9 @@ xfs_mkdir(
        /*
         * Reserve disk quota and the inode.
         */
-       if (XFS_IS_QUOTA_ON(mp)) {
-               if (xfs_trans_reserve_quota(tp, udqp, gdqp, resblks, 1, 0)) {
-                       error = XFS_ERROR(EDQUOT);
-                       goto error_return;
-               }
-       }
+       error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
+       if (error)
+               goto error_return;
 
        if (resblks == 0 &&
            (error = XFS_DIR_CANENTER(mp, tp, dp, dir_name, dir_namelen)))
@@ -2999,9 +2929,7 @@ xfs_mkdir(
        /*
         * Attach the dquots to the new inode and modify the icount incore.
         */
-       if (XFS_IS_QUOTA_ON(mp)) {
-               xfs_qm_vop_dqattach_and_dqmod_newinode(tp, cdp, udqp, gdqp);
-       }
+       XFS_QM_DQVOPCREATE(mp, tp, cdp, udqp, gdqp);
 
        /*
         * If this is a synchronous mount, make sure that the
@@ -3019,11 +2947,8 @@ xfs_mkdir(
        }
 
        error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
-       if (udqp)
-                xfs_qm_dqrele(udqp);
-       if (gdqp)
-                xfs_qm_dqrele(gdqp);
-
+       XFS_QM_DQRELE(mp, udqp);
+       XFS_QM_DQRELE(mp, gdqp);
        if (error) {
                IRELE(cdp);
        }
@@ -3035,7 +2960,7 @@ std_return:
        if ( (created || (error != 0 && dm_event_sent != 0)) &&
                        DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp),
                                                DM_EVENT_POSTCREATE)) {
-               (void) dm_send_namesp_event(DM_EVENT_POSTCREATE,
+               (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE,
                                        dir_bdp, DM_RIGHT_NULL,
                                        created ? XFS_ITOBHV(cdp):NULL,
                                        DM_RIGHT_NULL,
@@ -3051,11 +2976,8 @@ std_return:
        cancel_flags |= XFS_TRANS_ABORT;
  error_return:
        xfs_trans_cancel(tp, cancel_flags);
-
-       if (udqp)
-               xfs_qm_dqrele(udqp);
-       if (gdqp)
-               xfs_qm_dqrele(gdqp);
+       XFS_QM_DQRELE(mp, udqp);
+       XFS_QM_DQRELE(mp, gdqp);
 
        if (!dp_joined_to_trans && (dp != NULL)) {
                xfs_iunlock(dp, XFS_ILOCK_EXCL);
@@ -3093,6 +3015,7 @@ xfs_rmdir(
 
        dir_vp = BHV_TO_VNODE(dir_bdp);
        dp = XFS_BHVTOI(dir_bdp);
+       mp = dp->i_mount;
 
        vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address);
 
@@ -3101,7 +3024,7 @@ xfs_rmdir(
        namelen = VNAMELEN(dentry);
 
        if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) {
-               error = dm_send_namesp_event(DM_EVENT_REMOVE,
+               error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE,
                                        dir_bdp, DM_RIGHT_NULL,
                                        NULL, DM_RIGHT_NULL,
                                        name, NULL, 0, 0, 0);
@@ -3136,17 +3059,13 @@ xfs_rmdir(
        /*
         * Get the dquots for the inodes.
         */
-       if (XFS_IS_QUOTA_ON(mp)) {
-               ASSERT(! error);
-               if (XFS_NOT_DQATTACHED(mp, dp))
-                       error = xfs_qm_dqattach(dp, 0);
-               if (!error && dp != cdp && XFS_NOT_DQATTACHED(mp, cdp))
-                       error = xfs_qm_dqattach(cdp, 0);
-               if (error) {
-                       IRELE(cdp);
-                       REMOVE_DEBUG_TRACE(__LINE__);
-                       goto std_return;
-               }
+       error = XFS_QM_DQATTACH(mp, dp, 0);
+       if (!error && dp != cdp)
+               error = XFS_QM_DQATTACH(mp, cdp, 0);
+       if (error) {
+               IRELE(cdp);
+               REMOVE_DEBUG_TRACE(__LINE__);
+               goto std_return;
        }
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR);
@@ -3298,9 +3217,8 @@ xfs_rmdir(
        /* Fall through to std_return with error = 0 or the errno
         * from xfs_trans_commit. */
 std_return:
-       if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp,
-                                               DM_EVENT_POSTREMOVE)) {
-               (void) dm_send_namesp_event(DM_EVENT_POSTREMOVE,
+       if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_POSTREMOVE)) {
+               (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE,
                                        dir_bdp, DM_RIGHT_NULL,
                                        NULL, DM_RIGHT_NULL,
                                        name, NULL, dm_di_mode,
@@ -3391,7 +3309,7 @@ xfs_symlink(
        int                     n;
        xfs_buf_t               *bp;
        xfs_prid_t              prid;
-       xfs_dquot_t             *udqp, *gdqp;
+       struct xfs_dquot        *udqp, *gdqp;
        uint                    resblks;
        char                    *link_name = VNAME(dentry);
        int                     link_namelen;
@@ -3446,10 +3364,9 @@ xfs_symlink(
        }
 
        if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_SYMLINK)) {
-               error = dm_send_namesp_event(DM_EVENT_SYMLINK, dir_bdp, DM_RIGHT_NULL,
-                                               NULL, DM_RIGHT_NULL,
-                                               link_name, target_path,
-                                               0, 0, 0);
+               error = XFS_SEND_NAMESP(mp, DM_EVENT_SYMLINK, dir_bdp,
+                                       DM_RIGHT_NULL, NULL, DM_RIGHT_NULL,
+                                       link_name, target_path, 0, 0, 0);
                if (error)
                        return error;
        }
@@ -3465,14 +3382,10 @@ xfs_symlink(
        /*
         * Make sure that we have allocated dquot(s) on disk.
         */
-       if (XFS_IS_QUOTA_ON(mp)) {
-               error = xfs_qm_vop_dqalloc(mp, dp,
-                                          current->fsuid, current->fsgid,
-                                          XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT,
-                                          &udqp, &gdqp);
-               if (error)
-                       goto std_return;
-       }
+       error = XFS_QM_DQVOPALLOC(mp, dp, current->fsuid, current->fsgid,
+                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
+       if (error)
+               goto std_return;
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_SYMLINK);
        cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
@@ -3503,12 +3416,9 @@ xfs_symlink(
        /*
         * Reserve disk quota : blocks and inode.
         */
-       if (XFS_IS_QUOTA_ON(mp)) {
-               if (xfs_trans_reserve_quota(tp, udqp, gdqp, resblks, 1, 0)) {
-                       error = XFS_ERROR(EDQUOT);
-                       goto error_return;
-               }
-       }
+       error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0);
+       if (error)
+               goto error_return;
 
        /*
         * Check for ability to enter directory entry, if no space reserved.
@@ -3543,9 +3453,7 @@ xfs_symlink(
        /*
         * Also attach the dquot(s) to it, if applicable.
         */
-       if (XFS_IS_QUOTA_ON(mp)) {
-               xfs_qm_vop_dqattach_and_dqmod_newinode(tp, ip, udqp, gdqp);
-       }
+       XFS_QM_DQVOPCREATE(mp, tp, ip, udqp, gdqp);
 
        if (resblks)
                resblks -= XFS_IALLOC_SPACE_RES(mp);
@@ -3641,22 +3549,19 @@ xfs_symlink(
                goto error2;
        }
        error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
-       if (udqp)
-               xfs_qm_dqrele(udqp);
-       if (gdqp)
-               xfs_qm_dqrele(gdqp);
+       XFS_QM_DQRELE(mp, udqp);
+       XFS_QM_DQRELE(mp, gdqp);
 
        /* Fall through to std_return with error = 0 or errno from
         * xfs_trans_commit     */
 std_return:
        if (DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp),
                             DM_EVENT_POSTSYMLINK)) {
-               (void) dm_send_namesp_event(DM_EVENT_POSTSYMLINK,
-                                               dir_bdp, DM_RIGHT_NULL,
-                                               error? NULL:XFS_ITOBHV(ip),
-                                               DM_RIGHT_NULL,
-                                               link_name, target_path,
-                                               0, error, 0);
+               (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTSYMLINK,
+                                       dir_bdp, DM_RIGHT_NULL,
+                                       error ? NULL : XFS_ITOBHV(ip),
+                                       DM_RIGHT_NULL, link_name, target_path,
+                                       0, error, 0);
        }
 
        if (!error) {
@@ -3675,10 +3580,8 @@ std_return:
        cancel_flags |= XFS_TRANS_ABORT;
  error_return:
        xfs_trans_cancel(tp, cancel_flags);
-       if (udqp)
-               xfs_qm_dqrele(udqp);
-       if (gdqp)
-               xfs_qm_dqrele(gdqp);
+       XFS_QM_DQRELE(mp, udqp);
+       XFS_QM_DQRELE(mp, gdqp);
 
        if (!dp_joined_to_trans && (dp != NULL)) {
                xfs_iunlock(dp, XFS_ILOCK_EXCL);
@@ -4165,7 +4068,7 @@ xfs_alloc_file_space(
        /*
         * determine if this is a realtime file
         */
-       if ((rt = (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) != 0) {
+       if ((rt = XFS_IS_REALTIME_INODE(ip)) != 0) {
                if (ip->i_d.di_extsize)
                        rtextsize = ip->i_d.di_extsize;
                else
@@ -4173,12 +4076,8 @@ xfs_alloc_file_space(
        } else
                rtextsize = 0;
 
-       if (XFS_IS_QUOTA_ON(mp)) {
-               if (XFS_NOT_DQATTACHED(mp, ip)) {
-                       if ((error = xfs_qm_dqattach(ip, 0)))
-                               return error;
-               }
-       }
+       if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+               return error;
 
        if (len <= 0)
                return XFS_ERROR(EINVAL);
@@ -4200,7 +4099,7 @@ xfs_alloc_file_space(
                end_dmi_offset = offset+len;
                if (end_dmi_offset > ip->i_d.di_size)
                        end_dmi_offset = ip->i_d.di_size;
-               error = xfs_dm_send_data_event(DM_EVENT_WRITE, XFS_ITOBHV(ip),
+               error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, XFS_ITOBHV(ip),
                        offset, end_dmi_offset - offset,
                        0, NULL);
                if (error)
@@ -4255,15 +4154,11 @@ retry:
                        break;
                }
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-               if (XFS_IS_QUOTA_ON(mp)) {
-                       if (xfs_trans_reserve_quota(tp,
-                                                   ip->i_udquot,
-                                                   ip->i_gdquot,
-                                                   resblks, 0, 0)) {
-                               error = XFS_ERROR(EDQUOT);
-                               goto error1;
-                       }
-               }
+               error = XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp,
+                               ip->i_udquot, ip->i_gdquot, resblks, 0, rt ?
+                               XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS);
+               if (error)
+                       goto error1;
 
                xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
                xfs_trans_ihold(tp, ip);
@@ -4308,13 +4203,13 @@ dmapi_enospc_check:
        if (error == ENOSPC && (attr_flags&ATTR_DMI) == 0 &&
            DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_NOSPACE)) {
 
-               error = dm_send_namesp_event(DM_EVENT_NOSPACE,
+               error = XFS_SEND_NAMESP(mp, DM_EVENT_NOSPACE,
                                XFS_ITOBHV(ip), DM_RIGHT_NULL,
                                XFS_ITOBHV(ip), DM_RIGHT_NULL,
                                NULL, NULL, 0, 0, 0); /* Delay flag intentionally unused */
                if (error == 0)
                        goto retry;     /* Maybe DMAPI app. has made space */
-               /* else fall through with error from xfs_dm_send_data_event */
+               /* else fall through with error from XFS_SEND_DATA */
        }
 
        return error;
@@ -4434,38 +4329,32 @@ xfs_free_file_space(
        int                     nimap;
        uint                    resblks;
        int                     rounding;
-       int                     specrt;
+       int                     rt;
        xfs_fileoff_t           startoffset_fsb;
        xfs_trans_t             *tp;
 
        vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address);
        mp = ip->i_mount;
 
-       if (XFS_IS_QUOTA_ON(mp)) {
-               if (XFS_NOT_DQATTACHED(mp, ip)) {
-                       if ((error = xfs_qm_dqattach(ip, 0)))
-                               return error;
-               }
-       }
+       if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
+               return error;
 
        error = 0;
        if (len <= 0)   /* if nothing being freed */
                return error;
-       specrt =
-               (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) &&
-               !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb);
+       rt = (ip->i_d.di_flags & XFS_DIFLAG_REALTIME);
        startoffset_fsb = XFS_B_TO_FSB(mp, offset);
        end_dmi_offset = offset + len;
        endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset);
 
        if (offset < ip->i_d.di_size &&
-           (attr_flags&ATTR_DMI) == 0  &&
+           (attr_flags & ATTR_DMI) == 0 &&
            DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) {
                if (end_dmi_offset > ip->i_d.di_size)
                        end_dmi_offset = ip->i_d.di_size;
-               error = xfs_dm_send_data_event(DM_EVENT_WRITE, XFS_ITOBHV(ip),
-                       offset, end_dmi_offset - offset,
-                       AT_DELAY_FLAG(attr_flags), NULL);
+               error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, XFS_ITOBHV(ip),
+                               offset, end_dmi_offset - offset,
+                               AT_DELAY_FLAG(attr_flags), NULL);
                if (error)
                        return(error);
        }
@@ -4480,11 +4369,11 @@ xfs_free_file_space(
        xfs_inval_cached_pages(XFS_ITOV(ip), &(ip->i_iocore), ioffset, 0, 0);
        /*
         * Need to zero the stuff we're not freeing, on disk.
-        * If its specrt (realtime & can't use unwritten extents) then
-        * we actually need to zero the extent edges.  Otherwise xfs_bunmapi
+        * If its a realtime file & can't use unwritten extents then we
+        * actually need to zero the extent edges.  Otherwise xfs_bunmapi
         * will take care of it for us.
         */
-       if (specrt) {
+       if (rt && !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) {
                nimap = 1;
                error = xfs_bmapi(NULL, ip, startoffset_fsb, 1, 0, NULL, 0,
                        &imap, &nimap, NULL);
@@ -4561,15 +4450,11 @@ xfs_free_file_space(
                        break;
                }
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-               if (XFS_IS_QUOTA_ON(mp)) {
-                       if (xfs_trans_reserve_quota(tp,
-                                                   ip->i_udquot,
-                                                   ip->i_gdquot,
-                                                   resblks, 0, 0)) {
-                               error = XFS_ERROR(EDQUOT);
-                               goto error1;
-                       }
-               }
+               error = XFS_TRANS_RESERVE_QUOTA(mp, tp,
+                               ip->i_udquot, ip->i_gdquot, resblks, 0, rt ?
+                               XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS);
+               if (error)
+                       goto error1;
 
                xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
                xfs_trans_ihold(tp, ip);
index 469622afcf0973f48790d9aaf8160a3c1c44d10f..9b93838229ff0d13010778ab208558ed34ad94bb 100644 (file)
@@ -31,8 +31,8 @@
  */
 
 #include <xfs.h>
-#include <xfs_quota_priv.h>
 #include <xfs_log_recover.h>
+#include "quota/xfs_qm.h"
 #include "pagebuf/page_buf_internal.h"
 
 #include <linux/ctype.h>