VFS quota: add a function to set a per mount-point global space limit
authorFrancois Tigeot <ftigeot@wolfpond.org>
Sat, 17 Mar 2012 21:15:09 +0000 (22:15 +0100)
committerFrançois Tigeot <ftigeot@wolfpond.org>
Mon, 16 Apr 2012 19:18:50 +0000 (21:18 +0200)
sbin/vquota/vquota.8
sbin/vquota/vquota.c
sys/kern/vfs_quota.c

index 7ea37cd..34e1382 100644 (file)
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2011 François Tigeot
+.\" Copyright (c) 2011,2012 François Tigeot
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
@@ -25,7 +25,7 @@
 .
 .\" Note: The date here should be updated whenever a non-trivial
 .\" change is made to the manual page.
-.Dd January 19, 2012
+.Dd March 23, 2012
 .Dt VQUOTA 8
 .Os
 .Sh NAME
@@ -73,7 +73,7 @@ List mounted file systems having space accounting enabled
 .
 .\" ==== show ====
 .It Cm show Ar mount_point
-Show file size usage for the file system mounted under
+Show file size usage and quota limits for the file system mounted under
 .Ar mount_point .
 The information is broken down by uid and gid
 .
@@ -84,6 +84,12 @@ mounted under
 .Ar mount_point
 with real usage data. This command scans an entire filesystem
 directory hierarchy and may be slow to run
+.\" ==== limit ====
+.It Cm limit Ar mount_point size
+Set a global quota of
+.Ar size
+bytes for the filesystem mounted under
+.Ar mount_point .
 .El
 .
 .Sh EXAMPLES
index 49712b0..e6348ba 100644 (file)
@@ -62,6 +62,7 @@ usage(int retcode)
 {
        fprintf(stderr, "usage: vquota [-Dhn] check directory\n");
        fprintf(stderr, "       vquota [-Dhn] lsfs\n");
+       fprintf(stderr, "       vquota [-Dhn] limit mount_point size\n");
        fprintf(stderr, "       vquota [-Dhn] show mount_point\n");
        fprintf(stderr, "       vquota [-Dhn] sync mount_point\n");
        exit(retcode);
@@ -615,6 +616,32 @@ static int cmd_sync(char *dirname)
        return rv;
 }
 
+static int
+cmd_limit(char *dirname, uint64_t limit)
+{
+       prop_dictionary_t res, args;
+       int rv = 0;
+
+       args = prop_dictionary_create();
+       if (args == NULL)
+               printf("cmd_limit(): couldn't create args dictionary\n");
+       res  = prop_dictionary_create();
+       if (res == NULL)
+               printf("cmd_limit(): couldn't create res dictionary\n");
+
+       (void) prop_dictionary_set_uint64(args, "limit", limit);
+
+       if (send_command(dirname, "set limit", args, &res) == false) {
+               printf("Failed to send message to kernel\n");
+               rv = 1;
+       }
+
+       prop_object_release(args);
+       prop_object_release(res);
+
+       return rv;
+}
+
 int
 main(int argc, char **argv)
 {
@@ -646,6 +673,15 @@ main(int argc, char **argv)
        if (strcmp(argv[0], "lsfs") == 0) {
                return get_fslist();
        }
+       if (strcmp(argv[0], "limit") == 0) {
+               uint64_t limit;
+               if (argc != 3)
+                       usage(1);
+               if (dehumanize_number(argv[2], &limit) < 0)
+                       err(1, "bad number for option: %s", argv[2]);
+
+               return cmd_limit(argv[1], limit);
+       }
        if (strcmp(argv[0], "show") == 0) {
                if (argc != 2)
                        usage(1);
index ecce97a..1fdd488 100644 (file)
@@ -269,6 +269,20 @@ cmd_set_usage_all(struct mount *mp, prop_array_t args)
        return 0;
 }
 
+static int
+cmd_set_limit(struct mount *mp, prop_dictionary_t args)
+{
+       uint64_t limit;
+
+       prop_dictionary_get_uint64(args, "limit", &limit);
+
+       spin_lock(&mp->mnt_acct.ac_spin);
+       mp->mnt_acct.ac_limit = limit;
+       spin_unlock(&mp->mnt_acct.ac_spin);
+
+       return 0;
+}
+
 int
 sys_vquotactl(struct vquotactl_args *vqa)
 /* const char *path, struct plistref *pref */
@@ -326,6 +340,10 @@ sys_vquotactl(struct vquotactl_args *vqa)
                error = cmd_set_usage_all(mp, args);
                goto done;
        }
+       if (strcmp(cmd, "set limit") == 0) {
+               error = cmd_set_limit(mp, args);
+               goto done;
+       }
        return EINVAL;
 
 done: