forked from Minki/linux
657d3bfa98
Sometimes it may be useful for userspace to know (e.g. for some hosting guys) that some user stopped exceeding his hardlimit or softlimit in quotas. Implement sending of such events to userspace via quota netlink protocol so that they don't have to poll for such events. Based on idea and initial implementation by Vladislav Bogdanov. Cc: Vladislav Bogdanov <slava@nsys.by> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
365 lines
13 KiB
C
365 lines
13 KiB
C
/*
|
|
* Copyright (c) 1982, 1986 Regents of the University of California.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to Berkeley by
|
|
* Robert Elz at The University of Melbourne.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* Version: $Id: quota.h,v 2.0 1996/11/17 16:48:14 mvw Exp mvw $
|
|
*/
|
|
|
|
#ifndef _LINUX_QUOTA_
|
|
#define _LINUX_QUOTA_
|
|
|
|
#include <linux/errno.h>
|
|
#include <linux/types.h>
|
|
|
|
#define __DQUOT_VERSION__ "dquot_6.5.1"
|
|
#define __DQUOT_NUM_VERSION__ 6*10000+5*100+1
|
|
|
|
/* Size of blocks in which are counted size limits */
|
|
#define QUOTABLOCK_BITS 10
|
|
#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
|
|
|
|
/* Conversion routines from and to quota blocks */
|
|
#define qb2kb(x) ((x) << (QUOTABLOCK_BITS-10))
|
|
#define kb2qb(x) ((x) >> (QUOTABLOCK_BITS-10))
|
|
#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS)
|
|
|
|
#define MAXQUOTAS 2
|
|
#define USRQUOTA 0 /* element used for user quotas */
|
|
#define GRPQUOTA 1 /* element used for group quotas */
|
|
|
|
/*
|
|
* Definitions for the default names of the quotas files.
|
|
*/
|
|
#define INITQFNAMES { \
|
|
"user", /* USRQUOTA */ \
|
|
"group", /* GRPQUOTA */ \
|
|
"undefined", \
|
|
};
|
|
|
|
/*
|
|
* Command definitions for the 'quotactl' system call.
|
|
* The commands are broken into a main command defined below
|
|
* and a subcommand that is used to convey the type of
|
|
* quota that is being manipulated (see above).
|
|
*/
|
|
#define SUBCMDMASK 0x00ff
|
|
#define SUBCMDSHIFT 8
|
|
#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
|
|
|
|
#define Q_SYNC 0x800001 /* sync disk copy of a filesystems quotas */
|
|
#define Q_QUOTAON 0x800002 /* turn quotas on */
|
|
#define Q_QUOTAOFF 0x800003 /* turn quotas off */
|
|
#define Q_GETFMT 0x800004 /* get quota format used on given filesystem */
|
|
#define Q_GETINFO 0x800005 /* get information about quota files */
|
|
#define Q_SETINFO 0x800006 /* set information about quota files */
|
|
#define Q_GETQUOTA 0x800007 /* get user quota structure */
|
|
#define Q_SETQUOTA 0x800008 /* set user quota structure */
|
|
|
|
/*
|
|
* Quota structure used for communication with userspace via quotactl
|
|
* Following flags are used to specify which fields are valid
|
|
*/
|
|
#define QIF_BLIMITS 1
|
|
#define QIF_SPACE 2
|
|
#define QIF_ILIMITS 4
|
|
#define QIF_INODES 8
|
|
#define QIF_BTIME 16
|
|
#define QIF_ITIME 32
|
|
#define QIF_LIMITS (QIF_BLIMITS | QIF_ILIMITS)
|
|
#define QIF_USAGE (QIF_SPACE | QIF_INODES)
|
|
#define QIF_TIMES (QIF_BTIME | QIF_ITIME)
|
|
#define QIF_ALL (QIF_LIMITS | QIF_USAGE | QIF_TIMES)
|
|
|
|
struct if_dqblk {
|
|
__u64 dqb_bhardlimit;
|
|
__u64 dqb_bsoftlimit;
|
|
__u64 dqb_curspace;
|
|
__u64 dqb_ihardlimit;
|
|
__u64 dqb_isoftlimit;
|
|
__u64 dqb_curinodes;
|
|
__u64 dqb_btime;
|
|
__u64 dqb_itime;
|
|
__u32 dqb_valid;
|
|
};
|
|
|
|
/*
|
|
* Structure used for setting quota information about file via quotactl
|
|
* Following flags are used to specify which fields are valid
|
|
*/
|
|
#define IIF_BGRACE 1
|
|
#define IIF_IGRACE 2
|
|
#define IIF_FLAGS 4
|
|
#define IIF_ALL (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS)
|
|
|
|
struct if_dqinfo {
|
|
__u64 dqi_bgrace;
|
|
__u64 dqi_igrace;
|
|
__u32 dqi_flags;
|
|
__u32 dqi_valid;
|
|
};
|
|
|
|
/*
|
|
* Definitions for quota netlink interface
|
|
*/
|
|
#define QUOTA_NL_NOWARN 0
|
|
#define QUOTA_NL_IHARDWARN 1 /* Inode hardlimit reached */
|
|
#define QUOTA_NL_ISOFTLONGWARN 2 /* Inode grace time expired */
|
|
#define QUOTA_NL_ISOFTWARN 3 /* Inode softlimit reached */
|
|
#define QUOTA_NL_BHARDWARN 4 /* Block hardlimit reached */
|
|
#define QUOTA_NL_BSOFTLONGWARN 5 /* Block grace time expired */
|
|
#define QUOTA_NL_BSOFTWARN 6 /* Block softlimit reached */
|
|
#define QUOTA_NL_IHARDBELOW 7 /* Usage got below inode hardlimit */
|
|
#define QUOTA_NL_ISOFTBELOW 8 /* Usage got below inode softlimit */
|
|
#define QUOTA_NL_BHARDBELOW 9 /* Usage got below block hardlimit */
|
|
#define QUOTA_NL_BSOFTBELOW 10 /* Usage got below block softlimit */
|
|
|
|
enum {
|
|
QUOTA_NL_C_UNSPEC,
|
|
QUOTA_NL_C_WARNING,
|
|
__QUOTA_NL_C_MAX,
|
|
};
|
|
#define QUOTA_NL_C_MAX (__QUOTA_NL_C_MAX - 1)
|
|
|
|
enum {
|
|
QUOTA_NL_A_UNSPEC,
|
|
QUOTA_NL_A_QTYPE,
|
|
QUOTA_NL_A_EXCESS_ID,
|
|
QUOTA_NL_A_WARNING,
|
|
QUOTA_NL_A_DEV_MAJOR,
|
|
QUOTA_NL_A_DEV_MINOR,
|
|
QUOTA_NL_A_CAUSED_ID,
|
|
__QUOTA_NL_A_MAX,
|
|
};
|
|
#define QUOTA_NL_A_MAX (__QUOTA_NL_A_MAX - 1)
|
|
|
|
|
|
#ifdef __KERNEL__
|
|
#include <linux/list.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/rwsem.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/wait.h>
|
|
|
|
#include <linux/dqblk_xfs.h>
|
|
#include <linux/dqblk_v1.h>
|
|
#include <linux/dqblk_v2.h>
|
|
|
|
#include <asm/atomic.h>
|
|
|
|
typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
|
|
typedef __u64 qsize_t; /* Type in which we store sizes */
|
|
|
|
extern spinlock_t dq_data_lock;
|
|
|
|
/* Maximal numbers of writes for quota operation (insert/delete/update)
|
|
* (over VFS all formats) */
|
|
#define DQUOT_INIT_ALLOC max(V1_INIT_ALLOC, V2_INIT_ALLOC)
|
|
#define DQUOT_INIT_REWRITE max(V1_INIT_REWRITE, V2_INIT_REWRITE)
|
|
#define DQUOT_DEL_ALLOC max(V1_DEL_ALLOC, V2_DEL_ALLOC)
|
|
#define DQUOT_DEL_REWRITE max(V1_DEL_REWRITE, V2_DEL_REWRITE)
|
|
|
|
/*
|
|
* Data for one user/group kept in memory
|
|
*/
|
|
struct mem_dqblk {
|
|
__u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */
|
|
__u32 dqb_bsoftlimit; /* preferred limit on disk blks */
|
|
qsize_t dqb_curspace; /* current used space */
|
|
__u32 dqb_ihardlimit; /* absolute limit on allocated inodes */
|
|
__u32 dqb_isoftlimit; /* preferred inode limit */
|
|
__u32 dqb_curinodes; /* current # allocated inodes */
|
|
time_t dqb_btime; /* time limit for excessive disk use */
|
|
time_t dqb_itime; /* time limit for excessive inode use */
|
|
};
|
|
|
|
/*
|
|
* Data for one quotafile kept in memory
|
|
*/
|
|
struct quota_format_type;
|
|
|
|
struct mem_dqinfo {
|
|
struct quota_format_type *dqi_format;
|
|
int dqi_fmt_id; /* Id of the dqi_format - used when turning
|
|
* quotas on after remount RW */
|
|
struct list_head dqi_dirty_list; /* List of dirty dquots */
|
|
unsigned long dqi_flags;
|
|
unsigned int dqi_bgrace;
|
|
unsigned int dqi_igrace;
|
|
qsize_t dqi_maxblimit;
|
|
qsize_t dqi_maxilimit;
|
|
union {
|
|
struct v1_mem_dqinfo v1_i;
|
|
struct v2_mem_dqinfo v2_i;
|
|
} u;
|
|
};
|
|
|
|
struct super_block;
|
|
|
|
#define DQF_MASK 0xffff /* Mask for format specific flags */
|
|
#define DQF_INFO_DIRTY_B 16
|
|
#define DQF_INFO_DIRTY (1 << DQF_INFO_DIRTY_B) /* Is info dirty? */
|
|
|
|
extern void mark_info_dirty(struct super_block *sb, int type);
|
|
static inline int info_dirty(struct mem_dqinfo *info)
|
|
{
|
|
return test_bit(DQF_INFO_DIRTY_B, &info->dqi_flags);
|
|
}
|
|
|
|
struct dqstats {
|
|
int lookups;
|
|
int drops;
|
|
int reads;
|
|
int writes;
|
|
int cache_hits;
|
|
int allocated_dquots;
|
|
int free_dquots;
|
|
int syncs;
|
|
};
|
|
|
|
extern struct dqstats dqstats;
|
|
|
|
#define DQ_MOD_B 0 /* dquot modified since read */
|
|
#define DQ_BLKS_B 1 /* uid/gid has been warned about blk limit */
|
|
#define DQ_INODES_B 2 /* uid/gid has been warned about inode limit */
|
|
#define DQ_FAKE_B 3 /* no limits only usage */
|
|
#define DQ_READ_B 4 /* dquot was read into memory */
|
|
#define DQ_ACTIVE_B 5 /* dquot is active (dquot_release not called) */
|
|
|
|
struct dquot {
|
|
struct hlist_node dq_hash; /* Hash list in memory */
|
|
struct list_head dq_inuse; /* List of all quotas */
|
|
struct list_head dq_free; /* Free list element */
|
|
struct list_head dq_dirty; /* List of dirty dquots */
|
|
struct mutex dq_lock; /* dquot IO lock */
|
|
atomic_t dq_count; /* Use count */
|
|
wait_queue_head_t dq_wait_unused; /* Wait queue for dquot to become unused */
|
|
struct super_block *dq_sb; /* superblock this applies to */
|
|
unsigned int dq_id; /* ID this applies to (uid, gid) */
|
|
loff_t dq_off; /* Offset of dquot on disk */
|
|
unsigned long dq_flags; /* See DQ_* */
|
|
short dq_type; /* Type of quota */
|
|
struct mem_dqblk dq_dqb; /* Diskquota usage */
|
|
};
|
|
|
|
#define NODQUOT (struct dquot *)NULL
|
|
|
|
#define QUOTA_OK 0
|
|
#define NO_QUOTA 1
|
|
|
|
/* Operations which must be implemented by each quota format */
|
|
struct quota_format_ops {
|
|
int (*check_quota_file)(struct super_block *sb, int type); /* Detect whether file is in our format */
|
|
int (*read_file_info)(struct super_block *sb, int type); /* Read main info about file - called on quotaon() */
|
|
int (*write_file_info)(struct super_block *sb, int type); /* Write main info about file */
|
|
int (*free_file_info)(struct super_block *sb, int type); /* Called on quotaoff() */
|
|
int (*read_dqblk)(struct dquot *dquot); /* Read structure for one user */
|
|
int (*commit_dqblk)(struct dquot *dquot); /* Write structure for one user */
|
|
int (*release_dqblk)(struct dquot *dquot); /* Called when last reference to dquot is being dropped */
|
|
};
|
|
|
|
/* Operations working with dquots */
|
|
struct dquot_operations {
|
|
int (*initialize) (struct inode *, int);
|
|
int (*drop) (struct inode *);
|
|
int (*alloc_space) (struct inode *, qsize_t, int);
|
|
int (*alloc_inode) (const struct inode *, unsigned long);
|
|
int (*free_space) (struct inode *, qsize_t);
|
|
int (*free_inode) (const struct inode *, unsigned long);
|
|
int (*transfer) (struct inode *, struct iattr *);
|
|
int (*write_dquot) (struct dquot *); /* Ordinary dquot write */
|
|
int (*acquire_dquot) (struct dquot *); /* Quota is going to be created on disk */
|
|
int (*release_dquot) (struct dquot *); /* Quota is going to be deleted from disk */
|
|
int (*mark_dirty) (struct dquot *); /* Dquot is marked dirty */
|
|
int (*write_info) (struct super_block *, int); /* Write of quota "superblock" */
|
|
};
|
|
|
|
/* Operations handling requests from userspace */
|
|
struct quotactl_ops {
|
|
int (*quota_on)(struct super_block *, int, int, char *, int);
|
|
int (*quota_off)(struct super_block *, int, int);
|
|
int (*quota_sync)(struct super_block *, int);
|
|
int (*get_info)(struct super_block *, int, struct if_dqinfo *);
|
|
int (*set_info)(struct super_block *, int, struct if_dqinfo *);
|
|
int (*get_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *);
|
|
int (*set_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *);
|
|
int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
|
|
int (*set_xstate)(struct super_block *, unsigned int, int);
|
|
int (*get_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *);
|
|
int (*set_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *);
|
|
};
|
|
|
|
struct quota_format_type {
|
|
int qf_fmt_id; /* Quota format id */
|
|
struct quota_format_ops *qf_ops; /* Operations of format */
|
|
struct module *qf_owner; /* Module implementing quota format */
|
|
struct quota_format_type *qf_next;
|
|
};
|
|
|
|
#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */
|
|
#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */
|
|
#define DQUOT_USR_SUSPENDED 0x04 /* User diskquotas are off, but
|
|
* we have necessary info in
|
|
* memory to turn them on */
|
|
#define DQUOT_GRP_SUSPENDED 0x08 /* The same for group quotas */
|
|
|
|
struct quota_info {
|
|
unsigned int flags; /* Flags for diskquotas on this device */
|
|
struct mutex dqio_mutex; /* lock device while I/O in progress */
|
|
struct mutex dqonoff_mutex; /* Serialize quotaon & quotaoff */
|
|
struct rw_semaphore dqptr_sem; /* serialize ops using quota_info struct, pointers from inode to dquots */
|
|
struct inode *files[MAXQUOTAS]; /* inodes of quotafiles */
|
|
struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */
|
|
struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */
|
|
};
|
|
|
|
int register_quota_format(struct quota_format_type *fmt);
|
|
void unregister_quota_format(struct quota_format_type *fmt);
|
|
|
|
struct quota_module_name {
|
|
int qm_fmt_id;
|
|
char *qm_mod_name;
|
|
};
|
|
|
|
#define INIT_QUOTA_MODULE_NAMES {\
|
|
{QFMT_VFS_OLD, "quota_v1"},\
|
|
{QFMT_VFS_V0, "quota_v2"},\
|
|
{0, NULL}}
|
|
|
|
#else
|
|
|
|
# /* nodep */ include <sys/cdefs.h>
|
|
|
|
__BEGIN_DECLS
|
|
long quotactl __P ((unsigned int, const char *, int, caddr_t));
|
|
__END_DECLS
|
|
|
|
#endif /* __KERNEL__ */
|
|
#endif /* _QUOTA_ */
|