111963SAfshin.Ardakani@Sun.COM /*
211963SAfshin.Ardakani@Sun.COM * CDDL HEADER START
311963SAfshin.Ardakani@Sun.COM *
411963SAfshin.Ardakani@Sun.COM * The contents of this file are subject to the terms of the
511963SAfshin.Ardakani@Sun.COM * Common Development and Distribution License (the "License").
611963SAfshin.Ardakani@Sun.COM * You may not use this file except in compliance with the License.
711963SAfshin.Ardakani@Sun.COM *
811963SAfshin.Ardakani@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911963SAfshin.Ardakani@Sun.COM * or http://www.opensolaris.org/os/licensing.
1011963SAfshin.Ardakani@Sun.COM * See the License for the specific language governing permissions
1111963SAfshin.Ardakani@Sun.COM * and limitations under the License.
1211963SAfshin.Ardakani@Sun.COM *
1311963SAfshin.Ardakani@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1411963SAfshin.Ardakani@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511963SAfshin.Ardakani@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1611963SAfshin.Ardakani@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1711963SAfshin.Ardakani@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1811963SAfshin.Ardakani@Sun.COM *
1911963SAfshin.Ardakani@Sun.COM * CDDL HEADER END
2011963SAfshin.Ardakani@Sun.COM */
21*12508Samw@Sun.COM
2211963SAfshin.Ardakani@Sun.COM /*
2312065SKeyur.Desai@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2411963SAfshin.Ardakani@Sun.COM */
25*12508Samw@Sun.COM
2611963SAfshin.Ardakani@Sun.COM #include <stdio.h>
2711963SAfshin.Ardakani@Sun.COM #include <stdlib.h>
2811963SAfshin.Ardakani@Sun.COM #include <fcntl.h>
2911963SAfshin.Ardakani@Sun.COM #include <attr.h>
3011963SAfshin.Ardakani@Sun.COM #include <unistd.h>
3111963SAfshin.Ardakani@Sun.COM #include <libuutil.h>
3211963SAfshin.Ardakani@Sun.COM #include <libzfs.h>
3311963SAfshin.Ardakani@Sun.COM #include <assert.h>
3411963SAfshin.Ardakani@Sun.COM #include <stddef.h>
3511963SAfshin.Ardakani@Sun.COM #include <strings.h>
3611963SAfshin.Ardakani@Sun.COM #include <errno.h>
3711963SAfshin.Ardakani@Sun.COM #include <synch.h>
3811963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_xdr.h>
3911963SAfshin.Ardakani@Sun.COM #include <smbsrv/libmlsvc.h>
4011963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_idmap.h>
4111963SAfshin.Ardakani@Sun.COM #include <mlsvc.h>
4211963SAfshin.Ardakani@Sun.COM #include <sys/avl.h>
4311963SAfshin.Ardakani@Sun.COM
4411963SAfshin.Ardakani@Sun.COM /*
4511963SAfshin.Ardakani@Sun.COM * smb_quota subsystem interface - mlsvc.h
4611963SAfshin.Ardakani@Sun.COM * ---------------------------------------
4711963SAfshin.Ardakani@Sun.COM * Management of the smb_quota_fs_list (see below).
4811963SAfshin.Ardakani@Sun.COM * smb_quota_init
4911963SAfshin.Ardakani@Sun.COM * smb_quota_fini
5011963SAfshin.Ardakani@Sun.COM * smb_quota_add_fs
5111963SAfshin.Ardakani@Sun.COM * smb_quota_remove_fs
5211963SAfshin.Ardakani@Sun.COM *
5311963SAfshin.Ardakani@Sun.COM * smb_quota public interface - libmlsvc.h
5411963SAfshin.Ardakani@Sun.COM * ---------------------------------------
5511963SAfshin.Ardakani@Sun.COM * Handling of requests to query and set quota data on a filesystem.
5611963SAfshin.Ardakani@Sun.COM * smb_quota_query - query user/group quotas on a filesystem
5711963SAfshin.Ardakani@Sun.COM * smb_quota_set - set user/group quotas ona filesystem
5811963SAfshin.Ardakani@Sun.COM * smb_quota_free - delete the quota list created in smb_quota_query
5911963SAfshin.Ardakani@Sun.COM */
6011963SAfshin.Ardakani@Sun.COM
6111963SAfshin.Ardakani@Sun.COM /*
6211963SAfshin.Ardakani@Sun.COM * Querying user & group quotas - smb_quota_query
6311963SAfshin.Ardakani@Sun.COM *
6411963SAfshin.Ardakani@Sun.COM * In order to fulfill the quota query requests that can be received
6511963SAfshin.Ardakani@Sun.COM * from clients, it is required that the quota data can be provided in
6611963SAfshin.Ardakani@Sun.COM * a well defined and consistent order, and that a request can specify
6711963SAfshin.Ardakani@Sun.COM * at which quota entry to begin the query.
6811963SAfshin.Ardakani@Sun.COM *
6911963SAfshin.Ardakani@Sun.COM * Quota Tree
7011963SAfshin.Ardakani@Sun.COM * Since the file system does not support the above, an avl tree is
7111963SAfshin.Ardakani@Sun.COM * populated with the file system's user and group quota data, and
7211963SAfshin.Ardakani@Sun.COM * then used to provide the data to respond to query requests. The
7311963SAfshin.Ardakani@Sun.COM * avl tree is indexed by the SID.
7411963SAfshin.Ardakani@Sun.COM * Each node of the avl tree is an smb_quota_t structure.
7511963SAfshin.Ardakani@Sun.COM *
7611963SAfshin.Ardakani@Sun.COM * Quota List
7711963SAfshin.Ardakani@Sun.COM * There is a list of avl trees, one per file system.
7811963SAfshin.Ardakani@Sun.COM * Each node in the list is an smb_quota_tree_t structure.
7911963SAfshin.Ardakani@Sun.COM * The list is created via a call to smb_quota_init() when the library
8011963SAfshin.Ardakani@Sun.COM * is initialized, and destroyed via a call to smb_quota_fini() when
8111963SAfshin.Ardakani@Sun.COM * the library is fini'd.
8211963SAfshin.Ardakani@Sun.COM *
8311963SAfshin.Ardakani@Sun.COM * An avl tree for a specific file system is created and added to the
8411963SAfshin.Ardakani@Sun.COM * list via a call to smb_quota_add_fs() when the file system is shared,
8511963SAfshin.Ardakani@Sun.COM * and removed from the list via a call to smb_quota_remove_fs() when
8611963SAfshin.Ardakani@Sun.COM * the file system is unshared.
8711963SAfshin.Ardakani@Sun.COM *
8811963SAfshin.Ardakani@Sun.COM * An avl tree is (re)populated, if required, whenever a quota request
8911963SAfshin.Ardakani@Sun.COM * (EXCLUDING a resume request) is received for its filesystem. The
9011963SAfshin.Ardakani@Sun.COM * avl tree is considered to be expired (needs to be repopulated) if
9111963SAfshin.Ardakani@Sun.COM * either of the following have occurred since it was last (re)populated:
9211963SAfshin.Ardakani@Sun.COM * - SMB_QUOTA_REFRESH seconds have elapsed OR
9311963SAfshin.Ardakani@Sun.COM * - a quota set operation has been performed on its file system
9411963SAfshin.Ardakani@Sun.COM *
9511963SAfshin.Ardakani@Sun.COM * In order to perform a smb_quota_query/set operation on a file system
9611963SAfshin.Ardakani@Sun.COM * the appropriate quota tree must be identified and locked via a call
9711963SAfshin.Ardakani@Sun.COM * to smb_quota_tree_lookup(), The quota tree is locked (qt_locked == B_TRUE)
9811963SAfshin.Ardakani@Sun.COM * until the caller releases it via a call to smb_quota_tree_release().
9911963SAfshin.Ardakani@Sun.COM */
10011963SAfshin.Ardakani@Sun.COM
10111963SAfshin.Ardakani@Sun.COM /*
10211963SAfshin.Ardakani@Sun.COM * smb_quota_tree_t
10311963SAfshin.Ardakani@Sun.COM * Represents an avl tree of user quotas for a file system.
10411963SAfshin.Ardakani@Sun.COM *
10511963SAfshin.Ardakani@Sun.COM * qt_refcnt - a count of the number of users of the tree.
10611963SAfshin.Ardakani@Sun.COM * qt_refcnt is also incremented and decremented when the tree is
10711963SAfshin.Ardakani@Sun.COM * added to and removed from the quota list.
10811963SAfshin.Ardakani@Sun.COM * The tree cannot be deleted until this count is zero.
10911963SAfshin.Ardakani@Sun.COM *
11011963SAfshin.Ardakani@Sun.COM * qt_sharecnt - a count of the shares of the file system which the
11111963SAfshin.Ardakani@Sun.COM * tree represents. smb_quota_remove_fs() cannot remove the tree from
11211963SAfshin.Ardakani@Sun.COM * removed from the quota list until this count is zero.
11311963SAfshin.Ardakani@Sun.COM *
11411963SAfshin.Ardakani@Sun.COM * qt_locked - B_TRUE if someone is currently using the tree, in
11511963SAfshin.Ardakani@Sun.COM * which case a lookup will wait for the tree to become available.
11611963SAfshin.Ardakani@Sun.COM */
11711963SAfshin.Ardakani@Sun.COM typedef struct smb_quota_tree {
11811963SAfshin.Ardakani@Sun.COM list_node_t qt_node;
11911963SAfshin.Ardakani@Sun.COM char *qt_path;
12011963SAfshin.Ardakani@Sun.COM time_t qt_timestamp;
12111963SAfshin.Ardakani@Sun.COM uint32_t qt_refcnt;
12211963SAfshin.Ardakani@Sun.COM uint32_t qt_sharecnt;
12311963SAfshin.Ardakani@Sun.COM boolean_t qt_locked;
12411963SAfshin.Ardakani@Sun.COM avl_tree_t qt_avl;
12511963SAfshin.Ardakani@Sun.COM mutex_t qt_mutex;
12611963SAfshin.Ardakani@Sun.COM }smb_quota_tree_t;
12711963SAfshin.Ardakani@Sun.COM
12811963SAfshin.Ardakani@Sun.COM /*
12911963SAfshin.Ardakani@Sun.COM * smb_quota_fs_list
13011963SAfshin.Ardakani@Sun.COM * list of quota trees; one per shared file system.
13111963SAfshin.Ardakani@Sun.COM */
13211963SAfshin.Ardakani@Sun.COM static list_t smb_quota_fs_list;
13311963SAfshin.Ardakani@Sun.COM static boolean_t smb_quota_list_init = B_FALSE;
13411963SAfshin.Ardakani@Sun.COM static boolean_t smb_quota_shutdown = B_FALSE;
13512065SKeyur.Desai@Sun.COM static mutex_t smb_quota_list_mutex = DEFAULTMUTEX;
13611963SAfshin.Ardakani@Sun.COM static cond_t smb_quota_list_condvar;
13711963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_tree_cnt = 0;
13811963SAfshin.Ardakani@Sun.COM static int smb_quota_fini_timeout = 1; /* seconds */
13911963SAfshin.Ardakani@Sun.COM
14011963SAfshin.Ardakani@Sun.COM /*
14111963SAfshin.Ardakani@Sun.COM * smb_quota_zfs_handle_t
14211963SAfshin.Ardakani@Sun.COM * handle to zfs library and dataset
14311963SAfshin.Ardakani@Sun.COM */
14411963SAfshin.Ardakani@Sun.COM typedef struct smb_quota_zfs_handle {
14511963SAfshin.Ardakani@Sun.COM libzfs_handle_t *z_lib;
14611963SAfshin.Ardakani@Sun.COM zfs_handle_t *z_fs;
14711963SAfshin.Ardakani@Sun.COM } smb_quota_zfs_handle_t;
14811963SAfshin.Ardakani@Sun.COM
14911963SAfshin.Ardakani@Sun.COM /*
15011963SAfshin.Ardakani@Sun.COM * smb_quota_zfs_arg_t
15111963SAfshin.Ardakani@Sun.COM * arg passed to zfs callback when querying quota properties
15211963SAfshin.Ardakani@Sun.COM */
15311963SAfshin.Ardakani@Sun.COM typedef struct smb_quota_zfs_arg {
15411963SAfshin.Ardakani@Sun.COM zfs_userquota_prop_t qa_prop;
15511963SAfshin.Ardakani@Sun.COM avl_tree_t *qa_avl;
15611963SAfshin.Ardakani@Sun.COM } smb_quota_zfs_arg_t;
15711963SAfshin.Ardakani@Sun.COM
15811963SAfshin.Ardakani@Sun.COM static void smb_quota_add_ctrldir(const char *);
15911963SAfshin.Ardakani@Sun.COM static void smb_quota_remove_ctrldir(const char *);
16011963SAfshin.Ardakani@Sun.COM
16111963SAfshin.Ardakani@Sun.COM static smb_quota_tree_t *smb_quota_tree_create(const char *);
16211963SAfshin.Ardakani@Sun.COM static void smb_quota_tree_delete(smb_quota_tree_t *);
16311963SAfshin.Ardakani@Sun.COM
16411963SAfshin.Ardakani@Sun.COM static smb_quota_tree_t *smb_quota_tree_lookup(const char *);
16511963SAfshin.Ardakani@Sun.COM static void smb_quota_tree_release(smb_quota_tree_t *);
16611963SAfshin.Ardakani@Sun.COM static boolean_t smb_quota_tree_match(smb_quota_tree_t *, const char *);
16711963SAfshin.Ardakani@Sun.COM static int smb_quota_sid_cmp(const void *, const void *);
16811963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_tree_populate(smb_quota_tree_t *);
16911963SAfshin.Ardakani@Sun.COM static boolean_t smb_quota_tree_expired(smb_quota_tree_t *);
17011963SAfshin.Ardakani@Sun.COM static void smb_quota_tree_set_expired(smb_quota_tree_t *);
17111963SAfshin.Ardakani@Sun.COM
17211963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_zfs_init(const char *, smb_quota_zfs_handle_t *);
17311963SAfshin.Ardakani@Sun.COM static void smb_quota_zfs_fini(smb_quota_zfs_handle_t *);
17411963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_zfs_get_quotas(smb_quota_tree_t *);
17511963SAfshin.Ardakani@Sun.COM static int smb_quota_zfs_callback(void *, const char *, uid_t, uint64_t);
17611963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_zfs_set_quotas(smb_quota_tree_t *, smb_quota_set_t *);
17711963SAfshin.Ardakani@Sun.COM static int smb_quota_sidstr(uint32_t, zfs_userquota_prop_t, char *);
17811963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_sidtype(smb_quota_tree_t *, char *);
17911963SAfshin.Ardakani@Sun.COM static int smb_quota_getid(char *, uint32_t, uint32_t *);
18011963SAfshin.Ardakani@Sun.COM
18111963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_query_all(smb_quota_tree_t *,
18211963SAfshin.Ardakani@Sun.COM smb_quota_query_t *, smb_quota_response_t *);
18311963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_query_list(smb_quota_tree_t *,
18411963SAfshin.Ardakani@Sun.COM smb_quota_query_t *, smb_quota_response_t *);
18511963SAfshin.Ardakani@Sun.COM
18611963SAfshin.Ardakani@Sun.COM #define SMB_QUOTA_REFRESH 2
18711963SAfshin.Ardakani@Sun.COM #define SMB_QUOTA_CMD_LENGTH 21
18811963SAfshin.Ardakani@Sun.COM #define SMB_QUOTA_CMD_STR_LENGTH SMB_SID_STRSZ+SMB_QUOTA_CMD_LENGTH
18911963SAfshin.Ardakani@Sun.COM
19011963SAfshin.Ardakani@Sun.COM /*
19111963SAfshin.Ardakani@Sun.COM * In order to display the quota properties tab, windows clients
19211963SAfshin.Ardakani@Sun.COM * check for the existence of the quota control file.
19311963SAfshin.Ardakani@Sun.COM */
19411963SAfshin.Ardakani@Sun.COM #define SMB_QUOTA_CNTRL_DIR ".$EXTEND"
19511963SAfshin.Ardakani@Sun.COM #define SMB_QUOTA_CNTRL_FILE "$QUOTA"
19611963SAfshin.Ardakani@Sun.COM #define SMB_QUOTA_CNTRL_INDEX_XATTR "SUNWsmb:$Q:$INDEX_ALLOCATION"
19711963SAfshin.Ardakani@Sun.COM #define SMB_QUOTA_CNTRL_PERM "everyone@:rwpaARWc::allow"
19811963SAfshin.Ardakani@Sun.COM
19911963SAfshin.Ardakani@Sun.COM /*
20011963SAfshin.Ardakani@Sun.COM * smb_quota_init
20111963SAfshin.Ardakani@Sun.COM * Initialize the list to hold the quota trees.
20211963SAfshin.Ardakani@Sun.COM */
20311963SAfshin.Ardakani@Sun.COM void
smb_quota_init(void)20411963SAfshin.Ardakani@Sun.COM smb_quota_init(void)
20511963SAfshin.Ardakani@Sun.COM {
20611963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&smb_quota_list_mutex);
20711963SAfshin.Ardakani@Sun.COM if (!smb_quota_list_init) {
20811963SAfshin.Ardakani@Sun.COM list_create(&smb_quota_fs_list, sizeof (smb_quota_tree_t),
20911963SAfshin.Ardakani@Sun.COM offsetof(smb_quota_tree_t, qt_node));
21011963SAfshin.Ardakani@Sun.COM smb_quota_list_init = B_TRUE;
21111963SAfshin.Ardakani@Sun.COM smb_quota_shutdown = B_FALSE;
21211963SAfshin.Ardakani@Sun.COM }
21311963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex);
21411963SAfshin.Ardakani@Sun.COM }
21511963SAfshin.Ardakani@Sun.COM
21611963SAfshin.Ardakani@Sun.COM /*
21711963SAfshin.Ardakani@Sun.COM * smb_quota_fini
21811963SAfshin.Ardakani@Sun.COM *
21911963SAfshin.Ardakani@Sun.COM * Wait for each quota tree to not be in use (qt_refcnt == 1)
22011963SAfshin.Ardakani@Sun.COM * then remove it from the list and delete it.
22111963SAfshin.Ardakani@Sun.COM */
22211963SAfshin.Ardakani@Sun.COM void
smb_quota_fini(void)22311963SAfshin.Ardakani@Sun.COM smb_quota_fini(void)
22411963SAfshin.Ardakani@Sun.COM {
22511963SAfshin.Ardakani@Sun.COM smb_quota_tree_t *qtree, *qtree_next;
22611963SAfshin.Ardakani@Sun.COM boolean_t remove;
22711963SAfshin.Ardakani@Sun.COM struct timespec tswait;
22811963SAfshin.Ardakani@Sun.COM tswait.tv_sec = smb_quota_fini_timeout;
22911963SAfshin.Ardakani@Sun.COM tswait.tv_nsec = 0;
23011963SAfshin.Ardakani@Sun.COM
23111963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&smb_quota_list_mutex);
23211963SAfshin.Ardakani@Sun.COM smb_quota_shutdown = B_TRUE;
23311963SAfshin.Ardakani@Sun.COM
23411963SAfshin.Ardakani@Sun.COM if (!smb_quota_list_init) {
23511963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex);
23611963SAfshin.Ardakani@Sun.COM return;
23711963SAfshin.Ardakani@Sun.COM }
23811963SAfshin.Ardakani@Sun.COM
23911963SAfshin.Ardakani@Sun.COM (void) cond_broadcast(&smb_quota_list_condvar);
24011963SAfshin.Ardakani@Sun.COM
24112065SKeyur.Desai@Sun.COM while (!list_is_empty(&smb_quota_fs_list)) {
24211963SAfshin.Ardakani@Sun.COM qtree = list_head(&smb_quota_fs_list);
24311963SAfshin.Ardakani@Sun.COM while (qtree != NULL) {
24411963SAfshin.Ardakani@Sun.COM qtree_next = list_next(&smb_quota_fs_list, qtree);
24511963SAfshin.Ardakani@Sun.COM
24611963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&qtree->qt_mutex);
24711963SAfshin.Ardakani@Sun.COM remove = (qtree->qt_refcnt == 1);
24811963SAfshin.Ardakani@Sun.COM if (remove) {
24911963SAfshin.Ardakani@Sun.COM list_remove(&smb_quota_fs_list, qtree);
25011963SAfshin.Ardakani@Sun.COM --qtree->qt_refcnt;
25111963SAfshin.Ardakani@Sun.COM }
25211963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&qtree->qt_mutex);
25311963SAfshin.Ardakani@Sun.COM
25411963SAfshin.Ardakani@Sun.COM if (remove)
25511963SAfshin.Ardakani@Sun.COM smb_quota_tree_delete(qtree);
25611963SAfshin.Ardakani@Sun.COM
25711963SAfshin.Ardakani@Sun.COM qtree = qtree_next;
25811963SAfshin.Ardakani@Sun.COM }
25911963SAfshin.Ardakani@Sun.COM
26012065SKeyur.Desai@Sun.COM if (!list_is_empty(&smb_quota_fs_list)) {
26111963SAfshin.Ardakani@Sun.COM if (cond_reltimedwait(&smb_quota_list_condvar,
26211963SAfshin.Ardakani@Sun.COM &smb_quota_list_mutex, &tswait) == ETIME) {
26311963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING,
26411963SAfshin.Ardakani@Sun.COM "quota shutdown timeout expired");
26511963SAfshin.Ardakani@Sun.COM break;
26611963SAfshin.Ardakani@Sun.COM }
26711963SAfshin.Ardakani@Sun.COM }
26811963SAfshin.Ardakani@Sun.COM }
26911963SAfshin.Ardakani@Sun.COM
27011963SAfshin.Ardakani@Sun.COM if (list_is_empty(&smb_quota_fs_list)) {
27111963SAfshin.Ardakani@Sun.COM list_destroy(&smb_quota_fs_list);
27211963SAfshin.Ardakani@Sun.COM smb_quota_list_init = B_FALSE;
27311963SAfshin.Ardakani@Sun.COM }
27411963SAfshin.Ardakani@Sun.COM
27511963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex);
27611963SAfshin.Ardakani@Sun.COM }
27711963SAfshin.Ardakani@Sun.COM
27811963SAfshin.Ardakani@Sun.COM /*
27911963SAfshin.Ardakani@Sun.COM * smb_quota_add_fs
28011963SAfshin.Ardakani@Sun.COM *
28111963SAfshin.Ardakani@Sun.COM * If there is not a quota tree representing the specified path,
28211963SAfshin.Ardakani@Sun.COM * create one and add it to the list.
28311963SAfshin.Ardakani@Sun.COM */
28411963SAfshin.Ardakani@Sun.COM void
smb_quota_add_fs(const char * path)28511963SAfshin.Ardakani@Sun.COM smb_quota_add_fs(const char *path)
28611963SAfshin.Ardakani@Sun.COM {
28711963SAfshin.Ardakani@Sun.COM smb_quota_tree_t *qtree;
28811963SAfshin.Ardakani@Sun.COM
28911963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&smb_quota_list_mutex);
29011963SAfshin.Ardakani@Sun.COM
29111963SAfshin.Ardakani@Sun.COM if (!smb_quota_list_init || smb_quota_shutdown) {
29211963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex);
29311963SAfshin.Ardakani@Sun.COM return;
29411963SAfshin.Ardakani@Sun.COM }
29511963SAfshin.Ardakani@Sun.COM
29611963SAfshin.Ardakani@Sun.COM qtree = list_head(&smb_quota_fs_list);
29711963SAfshin.Ardakani@Sun.COM while (qtree != NULL) {
29811963SAfshin.Ardakani@Sun.COM if (smb_quota_tree_match(qtree, path)) {
29911963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&qtree->qt_mutex);
30011963SAfshin.Ardakani@Sun.COM ++qtree->qt_sharecnt;
30111963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&qtree->qt_mutex);
30211963SAfshin.Ardakani@Sun.COM break;
30311963SAfshin.Ardakani@Sun.COM }
30411963SAfshin.Ardakani@Sun.COM qtree = list_next(&smb_quota_fs_list, qtree);
30511963SAfshin.Ardakani@Sun.COM }
30611963SAfshin.Ardakani@Sun.COM
30711963SAfshin.Ardakani@Sun.COM if (qtree == NULL) {
30811963SAfshin.Ardakani@Sun.COM qtree = smb_quota_tree_create(path);
30911963SAfshin.Ardakani@Sun.COM if (qtree)
31011963SAfshin.Ardakani@Sun.COM list_insert_head(&smb_quota_fs_list, (void *)qtree);
31111963SAfshin.Ardakani@Sun.COM }
31211963SAfshin.Ardakani@Sun.COM
31311963SAfshin.Ardakani@Sun.COM if (qtree)
31411963SAfshin.Ardakani@Sun.COM smb_quota_add_ctrldir(path);
31511963SAfshin.Ardakani@Sun.COM
31611963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex);
31711963SAfshin.Ardakani@Sun.COM }
31811963SAfshin.Ardakani@Sun.COM
31911963SAfshin.Ardakani@Sun.COM /*
32011963SAfshin.Ardakani@Sun.COM * smb_quota_remove_fs
32111963SAfshin.Ardakani@Sun.COM *
32211963SAfshin.Ardakani@Sun.COM * If this is the last share that the quota tree represents
32311963SAfshin.Ardakani@Sun.COM * (qtree->qt_sharecnt == 0) remove the qtree from the list.
32411963SAfshin.Ardakani@Sun.COM * The qtree will be deleted if/when there is nobody using it
32511963SAfshin.Ardakani@Sun.COM * (qtree->qt_refcnt == 0).
32611963SAfshin.Ardakani@Sun.COM */
32711963SAfshin.Ardakani@Sun.COM void
smb_quota_remove_fs(const char * path)32811963SAfshin.Ardakani@Sun.COM smb_quota_remove_fs(const char *path)
32911963SAfshin.Ardakani@Sun.COM {
33011963SAfshin.Ardakani@Sun.COM smb_quota_tree_t *qtree;
33111963SAfshin.Ardakani@Sun.COM boolean_t delete = B_FALSE;
33211963SAfshin.Ardakani@Sun.COM
33311963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&smb_quota_list_mutex);
33411963SAfshin.Ardakani@Sun.COM
33511963SAfshin.Ardakani@Sun.COM if (!smb_quota_list_init || smb_quota_shutdown) {
33611963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex);
33711963SAfshin.Ardakani@Sun.COM return;
33811963SAfshin.Ardakani@Sun.COM }
33911963SAfshin.Ardakani@Sun.COM
34011963SAfshin.Ardakani@Sun.COM qtree = list_head(&smb_quota_fs_list);
34111963SAfshin.Ardakani@Sun.COM while (qtree != NULL) {
34211963SAfshin.Ardakani@Sun.COM assert(qtree->qt_refcnt > 0);
34311963SAfshin.Ardakani@Sun.COM if (smb_quota_tree_match(qtree, path)) {
34411963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&qtree->qt_mutex);
34511963SAfshin.Ardakani@Sun.COM --qtree->qt_sharecnt;
34611963SAfshin.Ardakani@Sun.COM if (qtree->qt_sharecnt == 0) {
34711963SAfshin.Ardakani@Sun.COM list_remove(&smb_quota_fs_list, (void *)qtree);
34811963SAfshin.Ardakani@Sun.COM smb_quota_remove_ctrldir(qtree->qt_path);
34911963SAfshin.Ardakani@Sun.COM --(qtree->qt_refcnt);
35011963SAfshin.Ardakani@Sun.COM delete = (qtree->qt_refcnt == 0);
35111963SAfshin.Ardakani@Sun.COM }
35211963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&qtree->qt_mutex);
35311963SAfshin.Ardakani@Sun.COM if (delete)
35411963SAfshin.Ardakani@Sun.COM smb_quota_tree_delete(qtree);
35511963SAfshin.Ardakani@Sun.COM break;
35611963SAfshin.Ardakani@Sun.COM }
35711963SAfshin.Ardakani@Sun.COM qtree = list_next(&smb_quota_fs_list, qtree);
35811963SAfshin.Ardakani@Sun.COM }
35911963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex);
36011963SAfshin.Ardakani@Sun.COM }
36111963SAfshin.Ardakani@Sun.COM
36211963SAfshin.Ardakani@Sun.COM /*
36311963SAfshin.Ardakani@Sun.COM * smb_quota_query
36411963SAfshin.Ardakani@Sun.COM *
36511963SAfshin.Ardakani@Sun.COM * Get list of user/group quotas entries.
36611963SAfshin.Ardakani@Sun.COM * Request->qq_query_op determines whether to get quota entries
36711963SAfshin.Ardakani@Sun.COM * for the specified SIDs (smb_quota_query_list) OR to get all
36811963SAfshin.Ardakani@Sun.COM * quota entries, optionally starting at a specified SID.
36911963SAfshin.Ardakani@Sun.COM *
37011963SAfshin.Ardakani@Sun.COM * Returns NT_STATUS codes.
37111963SAfshin.Ardakani@Sun.COM */
37211963SAfshin.Ardakani@Sun.COM uint32_t
smb_quota_query(smb_quota_query_t * request,smb_quota_response_t * reply)37311963SAfshin.Ardakani@Sun.COM smb_quota_query(smb_quota_query_t *request, smb_quota_response_t *reply)
37411963SAfshin.Ardakani@Sun.COM {
37511963SAfshin.Ardakani@Sun.COM uint32_t status;
37611963SAfshin.Ardakani@Sun.COM smb_quota_tree_t *qtree;
37711963SAfshin.Ardakani@Sun.COM smb_quota_query_op_t query_op = request->qq_query_op;
37811963SAfshin.Ardakani@Sun.COM
37911963SAfshin.Ardakani@Sun.COM list_create(&reply->qr_quota_list, sizeof (smb_quota_t),
38011963SAfshin.Ardakani@Sun.COM offsetof(smb_quota_t, q_list_node));
38111963SAfshin.Ardakani@Sun.COM
38211963SAfshin.Ardakani@Sun.COM qtree = smb_quota_tree_lookup(request->qq_root_path);
38311963SAfshin.Ardakani@Sun.COM if (qtree == NULL)
38411963SAfshin.Ardakani@Sun.COM return (NT_STATUS_INVALID_PARAMETER);
38511963SAfshin.Ardakani@Sun.COM
38611963SAfshin.Ardakani@Sun.COM /* If NOT resuming a previous query all, refresh qtree if required */
38711963SAfshin.Ardakani@Sun.COM if ((query_op != SMB_QUOTA_QUERY_ALL) || (request->qq_restart)) {
38811963SAfshin.Ardakani@Sun.COM status = smb_quota_tree_populate(qtree);
38911963SAfshin.Ardakani@Sun.COM if (status != NT_STATUS_SUCCESS) {
39011963SAfshin.Ardakani@Sun.COM smb_quota_tree_release(qtree);
39111963SAfshin.Ardakani@Sun.COM return (status);
39211963SAfshin.Ardakani@Sun.COM }
39311963SAfshin.Ardakani@Sun.COM }
39411963SAfshin.Ardakani@Sun.COM
39511963SAfshin.Ardakani@Sun.COM switch (query_op) {
39611963SAfshin.Ardakani@Sun.COM case SMB_QUOTA_QUERY_SIDLIST:
39711963SAfshin.Ardakani@Sun.COM status = smb_quota_query_list(qtree, request, reply);
39811963SAfshin.Ardakani@Sun.COM break;
39911963SAfshin.Ardakani@Sun.COM case SMB_QUOTA_QUERY_STARTSID:
40011963SAfshin.Ardakani@Sun.COM case SMB_QUOTA_QUERY_ALL:
40111963SAfshin.Ardakani@Sun.COM status = smb_quota_query_all(qtree, request, reply);
40211963SAfshin.Ardakani@Sun.COM break;
40311963SAfshin.Ardakani@Sun.COM case SMB_QUOTA_QUERY_INVALID_OP:
40411963SAfshin.Ardakani@Sun.COM default:
40511963SAfshin.Ardakani@Sun.COM status = NT_STATUS_INVALID_PARAMETER;
40611963SAfshin.Ardakani@Sun.COM break;
40711963SAfshin.Ardakani@Sun.COM }
40811963SAfshin.Ardakani@Sun.COM
40911963SAfshin.Ardakani@Sun.COM smb_quota_tree_release(qtree);
41011963SAfshin.Ardakani@Sun.COM
41111963SAfshin.Ardakani@Sun.COM return (status);
41211963SAfshin.Ardakani@Sun.COM }
41311963SAfshin.Ardakani@Sun.COM
41411963SAfshin.Ardakani@Sun.COM /*
41511963SAfshin.Ardakani@Sun.COM * smb_quota_set
41611963SAfshin.Ardakani@Sun.COM *
41711963SAfshin.Ardakani@Sun.COM * Set the list of quota entries.
41811963SAfshin.Ardakani@Sun.COM */
41911963SAfshin.Ardakani@Sun.COM uint32_t
smb_quota_set(smb_quota_set_t * request)42011963SAfshin.Ardakani@Sun.COM smb_quota_set(smb_quota_set_t *request)
42111963SAfshin.Ardakani@Sun.COM {
42211963SAfshin.Ardakani@Sun.COM uint32_t status;
42311963SAfshin.Ardakani@Sun.COM smb_quota_tree_t *qtree;
42411963SAfshin.Ardakani@Sun.COM
42511963SAfshin.Ardakani@Sun.COM qtree = smb_quota_tree_lookup(request->qs_root_path);
42611963SAfshin.Ardakani@Sun.COM if (qtree == NULL)
42711963SAfshin.Ardakani@Sun.COM return (NT_STATUS_INVALID_PARAMETER);
42811963SAfshin.Ardakani@Sun.COM
42911963SAfshin.Ardakani@Sun.COM status = smb_quota_zfs_set_quotas(qtree, request);
43011963SAfshin.Ardakani@Sun.COM
43111963SAfshin.Ardakani@Sun.COM smb_quota_tree_set_expired(qtree);
43211963SAfshin.Ardakani@Sun.COM smb_quota_tree_release(qtree);
43311963SAfshin.Ardakani@Sun.COM
43411963SAfshin.Ardakani@Sun.COM return (status);
43511963SAfshin.Ardakani@Sun.COM }
43611963SAfshin.Ardakani@Sun.COM
43711963SAfshin.Ardakani@Sun.COM /*
43811963SAfshin.Ardakani@Sun.COM * smb_quota_free
43911963SAfshin.Ardakani@Sun.COM *
44011963SAfshin.Ardakani@Sun.COM * This method frees quota entries.
44111963SAfshin.Ardakani@Sun.COM */
44211963SAfshin.Ardakani@Sun.COM void
smb_quota_free(smb_quota_response_t * reply)44311963SAfshin.Ardakani@Sun.COM smb_quota_free(smb_quota_response_t *reply)
44411963SAfshin.Ardakani@Sun.COM {
44511963SAfshin.Ardakani@Sun.COM list_t *list = &reply->qr_quota_list;
44611963SAfshin.Ardakani@Sun.COM smb_quota_t *quota;
44711963SAfshin.Ardakani@Sun.COM
44811963SAfshin.Ardakani@Sun.COM while ((quota = list_head(list)) != NULL) {
44911963SAfshin.Ardakani@Sun.COM list_remove(list, quota);
45011963SAfshin.Ardakani@Sun.COM free(quota);
45111963SAfshin.Ardakani@Sun.COM }
45211963SAfshin.Ardakani@Sun.COM
45311963SAfshin.Ardakani@Sun.COM list_destroy(list);
45411963SAfshin.Ardakani@Sun.COM }
45511963SAfshin.Ardakani@Sun.COM
45611963SAfshin.Ardakani@Sun.COM /*
45711963SAfshin.Ardakani@Sun.COM * smb_quota_query_all
45811963SAfshin.Ardakani@Sun.COM *
45911963SAfshin.Ardakani@Sun.COM * Query quotas sequentially from tree, optionally starting at a
46011963SAfshin.Ardakani@Sun.COM * specified sid. If request->qq_single is TRUE only one quota
46111963SAfshin.Ardakani@Sun.COM * should be returned, otherwise up to request->qq_max_quota
46211963SAfshin.Ardakani@Sun.COM * should be returned.
46311963SAfshin.Ardakani@Sun.COM *
46411963SAfshin.Ardakani@Sun.COM * SMB_QUOTA_QUERY_STARTSID
46511963SAfshin.Ardakani@Sun.COM * The query should start at the startsid, the first sid in
46611963SAfshin.Ardakani@Sun.COM * request->qq_sid_list.
46711963SAfshin.Ardakani@Sun.COM *
46811963SAfshin.Ardakani@Sun.COM * SMQ_QUOTA_QUERY_ALL
46911963SAfshin.Ardakani@Sun.COM * If request->qq_restart the query should restart at the start
47011963SAfshin.Ardakani@Sun.COM * of the avl tree. Otherwise the first sid in request->qq_sid_list
47111963SAfshin.Ardakani@Sun.COM * is the resume sid and the query should start at the tree entry
47211963SAfshin.Ardakani@Sun.COM * after the one it refers to.
47311963SAfshin.Ardakani@Sun.COM *
47411963SAfshin.Ardakani@Sun.COM * Returns NT_STATUS codes.
47511963SAfshin.Ardakani@Sun.COM */
47611963SAfshin.Ardakani@Sun.COM static uint32_t
smb_quota_query_all(smb_quota_tree_t * qtree,smb_quota_query_t * request,smb_quota_response_t * reply)47711963SAfshin.Ardakani@Sun.COM smb_quota_query_all(smb_quota_tree_t *qtree, smb_quota_query_t *request,
47811963SAfshin.Ardakani@Sun.COM smb_quota_response_t *reply)
47911963SAfshin.Ardakani@Sun.COM {
48011963SAfshin.Ardakani@Sun.COM avl_tree_t *avl_tree = &qtree->qt_avl;
48111963SAfshin.Ardakani@Sun.COM avl_index_t where;
48211963SAfshin.Ardakani@Sun.COM list_t *sid_list, *quota_list;
48311963SAfshin.Ardakani@Sun.COM smb_quota_sid_t *sid;
48411963SAfshin.Ardakani@Sun.COM smb_quota_t *quota, *quotal, key;
48511963SAfshin.Ardakani@Sun.COM uint32_t count;
48611963SAfshin.Ardakani@Sun.COM
48711963SAfshin.Ardakani@Sun.COM /* find starting sid */
48811963SAfshin.Ardakani@Sun.COM if (request->qq_query_op == SMB_QUOTA_QUERY_STARTSID) {
48911963SAfshin.Ardakani@Sun.COM sid_list = &request->qq_sid_list;
49011963SAfshin.Ardakani@Sun.COM sid = list_head(sid_list);
49111963SAfshin.Ardakani@Sun.COM (void) strlcpy(key.q_sidstr, sid->qs_sidstr, SMB_SID_STRSZ);
49211963SAfshin.Ardakani@Sun.COM quota = avl_find(avl_tree, &key, &where);
49311963SAfshin.Ardakani@Sun.COM if (quota == NULL)
49411963SAfshin.Ardakani@Sun.COM return (NT_STATUS_INVALID_PARAMETER);
49511963SAfshin.Ardakani@Sun.COM } else if (request->qq_restart) {
49611963SAfshin.Ardakani@Sun.COM quota = avl_first(avl_tree);
49711963SAfshin.Ardakani@Sun.COM if (quota == NULL)
498*12508Samw@Sun.COM return (NT_STATUS_NO_MORE_ENTRIES);
49911963SAfshin.Ardakani@Sun.COM } else {
50011963SAfshin.Ardakani@Sun.COM sid_list = &request->qq_sid_list;
50111963SAfshin.Ardakani@Sun.COM sid = list_head(sid_list);
50211963SAfshin.Ardakani@Sun.COM (void) strlcpy(key.q_sidstr, sid->qs_sidstr, SMB_SID_STRSZ);
50311963SAfshin.Ardakani@Sun.COM quota = avl_find(avl_tree, &key, &where);
50411963SAfshin.Ardakani@Sun.COM if (quota == NULL)
50511963SAfshin.Ardakani@Sun.COM return (NT_STATUS_INVALID_PARAMETER);
50611963SAfshin.Ardakani@Sun.COM quota = AVL_NEXT(avl_tree, quota);
50711963SAfshin.Ardakani@Sun.COM if (quota == NULL)
508*12508Samw@Sun.COM return (NT_STATUS_NO_MORE_ENTRIES);
50911963SAfshin.Ardakani@Sun.COM }
51011963SAfshin.Ardakani@Sun.COM
51111963SAfshin.Ardakani@Sun.COM if ((request->qq_single) && (request->qq_max_quota > 1))
51211963SAfshin.Ardakani@Sun.COM request->qq_max_quota = 1;
51311963SAfshin.Ardakani@Sun.COM
51411963SAfshin.Ardakani@Sun.COM quota_list = &reply->qr_quota_list;
51511963SAfshin.Ardakani@Sun.COM count = 0;
51611963SAfshin.Ardakani@Sun.COM while (quota) {
51711963SAfshin.Ardakani@Sun.COM if (count >= request->qq_max_quota)
51811963SAfshin.Ardakani@Sun.COM break;
51911963SAfshin.Ardakani@Sun.COM
52011963SAfshin.Ardakani@Sun.COM quotal = malloc(sizeof (smb_quota_t));
52111963SAfshin.Ardakani@Sun.COM if (quotal == NULL)
52211963SAfshin.Ardakani@Sun.COM return (NT_STATUS_NO_MEMORY);
52311963SAfshin.Ardakani@Sun.COM bcopy(quota, quotal, sizeof (smb_quota_t));
52411963SAfshin.Ardakani@Sun.COM
52511963SAfshin.Ardakani@Sun.COM list_insert_tail(quota_list, quotal);
52611963SAfshin.Ardakani@Sun.COM ++count;
52711963SAfshin.Ardakani@Sun.COM
52811963SAfshin.Ardakani@Sun.COM quota = AVL_NEXT(avl_tree, quota);
52911963SAfshin.Ardakani@Sun.COM }
53011963SAfshin.Ardakani@Sun.COM
53111963SAfshin.Ardakani@Sun.COM return (NT_STATUS_SUCCESS);
53211963SAfshin.Ardakani@Sun.COM }
53311963SAfshin.Ardakani@Sun.COM
53411963SAfshin.Ardakani@Sun.COM /*
53511963SAfshin.Ardakani@Sun.COM * smb_quota_query_list
53611963SAfshin.Ardakani@Sun.COM *
53711963SAfshin.Ardakani@Sun.COM * Iterate through request sid list querying the avl tree for each.
53811963SAfshin.Ardakani@Sun.COM * Insert an entry in the reply quota list for each sid.
53911963SAfshin.Ardakani@Sun.COM * For any sid that cannot be found in the avl tree, the reply
54011963SAfshin.Ardakani@Sun.COM * quota list entry should contain zeros.
54111963SAfshin.Ardakani@Sun.COM */
54211963SAfshin.Ardakani@Sun.COM static uint32_t
smb_quota_query_list(smb_quota_tree_t * qtree,smb_quota_query_t * request,smb_quota_response_t * reply)54311963SAfshin.Ardakani@Sun.COM smb_quota_query_list(smb_quota_tree_t *qtree, smb_quota_query_t *request,
54411963SAfshin.Ardakani@Sun.COM smb_quota_response_t *reply)
54511963SAfshin.Ardakani@Sun.COM {
54611963SAfshin.Ardakani@Sun.COM avl_tree_t *avl_tree = &qtree->qt_avl;
54711963SAfshin.Ardakani@Sun.COM avl_index_t where;
54811963SAfshin.Ardakani@Sun.COM list_t *sid_list, *quota_list;
54911963SAfshin.Ardakani@Sun.COM smb_quota_sid_t *sid;
55011963SAfshin.Ardakani@Sun.COM smb_quota_t *quota, *quotal, key;
55111963SAfshin.Ardakani@Sun.COM
55211963SAfshin.Ardakani@Sun.COM quota_list = &reply->qr_quota_list;
55311963SAfshin.Ardakani@Sun.COM sid_list = &request->qq_sid_list;
55411963SAfshin.Ardakani@Sun.COM sid = list_head(sid_list);
55511963SAfshin.Ardakani@Sun.COM while (sid) {
55611963SAfshin.Ardakani@Sun.COM quotal = malloc(sizeof (smb_quota_t));
55711963SAfshin.Ardakani@Sun.COM if (quotal == NULL)
55811963SAfshin.Ardakani@Sun.COM return (NT_STATUS_NO_MEMORY);
55911963SAfshin.Ardakani@Sun.COM
56011963SAfshin.Ardakani@Sun.COM (void) strlcpy(key.q_sidstr, sid->qs_sidstr, SMB_SID_STRSZ);
56111963SAfshin.Ardakani@Sun.COM quota = avl_find(avl_tree, &key, &where);
56211963SAfshin.Ardakani@Sun.COM if (quota) {
56311963SAfshin.Ardakani@Sun.COM bcopy(quota, quotal, sizeof (smb_quota_t));
56411963SAfshin.Ardakani@Sun.COM } else {
56511963SAfshin.Ardakani@Sun.COM bzero(quotal, sizeof (smb_quota_t));
56611963SAfshin.Ardakani@Sun.COM (void) strlcpy(quotal->q_sidstr, sid->qs_sidstr,
56711963SAfshin.Ardakani@Sun.COM SMB_SID_STRSZ);
56811963SAfshin.Ardakani@Sun.COM }
56911963SAfshin.Ardakani@Sun.COM
57011963SAfshin.Ardakani@Sun.COM list_insert_tail(quota_list, quotal);
57111963SAfshin.Ardakani@Sun.COM sid = list_next(sid_list, sid);
57211963SAfshin.Ardakani@Sun.COM }
57311963SAfshin.Ardakani@Sun.COM
57411963SAfshin.Ardakani@Sun.COM return (NT_STATUS_SUCCESS);
57511963SAfshin.Ardakani@Sun.COM }
57611963SAfshin.Ardakani@Sun.COM
57711963SAfshin.Ardakani@Sun.COM /*
57811963SAfshin.Ardakani@Sun.COM * smb_quota_zfs_set_quotas
57911963SAfshin.Ardakani@Sun.COM *
58011963SAfshin.Ardakani@Sun.COM * This method sets the list of quota entries.
58111963SAfshin.Ardakani@Sun.COM *
58211963SAfshin.Ardakani@Sun.COM * A quota list or threshold value of SMB_QUOTA_UNLIMITED means that
58311963SAfshin.Ardakani@Sun.COM * the user / group does not have a quota limit. In ZFS this maps to
58411963SAfshin.Ardakani@Sun.COM * 0 (none).
58511963SAfshin.Ardakani@Sun.COM * A quota list or threshold value of (SMB_QUOTA_UNLIMITED - 1) means
58611963SAfshin.Ardakani@Sun.COM * that the user / group quota should be removed. In ZFS this maps to
58711963SAfshin.Ardakani@Sun.COM * 0 (none).
58811963SAfshin.Ardakani@Sun.COM */
58911963SAfshin.Ardakani@Sun.COM static uint32_t
smb_quota_zfs_set_quotas(smb_quota_tree_t * qtree,smb_quota_set_t * request)59011963SAfshin.Ardakani@Sun.COM smb_quota_zfs_set_quotas(smb_quota_tree_t *qtree, smb_quota_set_t *request)
59111963SAfshin.Ardakani@Sun.COM {
59211963SAfshin.Ardakani@Sun.COM smb_quota_zfs_handle_t zfs_hdl;
59311963SAfshin.Ardakani@Sun.COM char *typestr, qsetstr[SMB_QUOTA_CMD_STR_LENGTH];
59411963SAfshin.Ardakani@Sun.COM char qlimit[SMB_QUOTA_CMD_LENGTH];
59511963SAfshin.Ardakani@Sun.COM list_t *quota_list;
59611963SAfshin.Ardakani@Sun.COM smb_quota_t *quota;
59711963SAfshin.Ardakani@Sun.COM uint32_t id;
59811963SAfshin.Ardakani@Sun.COM uint32_t status = NT_STATUS_SUCCESS;
59911963SAfshin.Ardakani@Sun.COM uint32_t sidtype;
60011963SAfshin.Ardakani@Sun.COM
60111963SAfshin.Ardakani@Sun.COM status = smb_quota_zfs_init(request->qs_root_path, &zfs_hdl);
60211963SAfshin.Ardakani@Sun.COM if (status != NT_STATUS_SUCCESS)
60311963SAfshin.Ardakani@Sun.COM return (status);
60411963SAfshin.Ardakani@Sun.COM
60511963SAfshin.Ardakani@Sun.COM quota_list = &request->qs_quota_list;
60611963SAfshin.Ardakani@Sun.COM quota = list_head(quota_list);
60711963SAfshin.Ardakani@Sun.COM
60811963SAfshin.Ardakani@Sun.COM while (quota) {
60911963SAfshin.Ardakani@Sun.COM if ((quota->q_limit == SMB_QUOTA_UNLIMITED) ||
61011963SAfshin.Ardakani@Sun.COM (quota->q_limit == (SMB_QUOTA_UNLIMITED - 1))) {
61111963SAfshin.Ardakani@Sun.COM quota->q_limit = 0;
61211963SAfshin.Ardakani@Sun.COM }
61311963SAfshin.Ardakani@Sun.COM (void) snprintf(qlimit, SMB_QUOTA_CMD_LENGTH, "%llu",
61411963SAfshin.Ardakani@Sun.COM quota->q_limit);
61511963SAfshin.Ardakani@Sun.COM
61611963SAfshin.Ardakani@Sun.COM sidtype = smb_quota_sidtype(qtree, quota->q_sidstr);
61711963SAfshin.Ardakani@Sun.COM switch (sidtype) {
61811963SAfshin.Ardakani@Sun.COM case SidTypeUser:
61911963SAfshin.Ardakani@Sun.COM typestr = "userquota";
62011963SAfshin.Ardakani@Sun.COM break;
62111963SAfshin.Ardakani@Sun.COM case SidTypeWellKnownGroup:
62211963SAfshin.Ardakani@Sun.COM case SidTypeGroup:
62311963SAfshin.Ardakani@Sun.COM case SidTypeAlias:
62411963SAfshin.Ardakani@Sun.COM typestr = "groupquota";
62511963SAfshin.Ardakani@Sun.COM break;
62611963SAfshin.Ardakani@Sun.COM default:
62711963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "Failed to set quota for %s: "
62811963SAfshin.Ardakani@Sun.COM "%s (%d) not valid for quotas", quota->q_sidstr,
62911963SAfshin.Ardakani@Sun.COM smb_sid_type2str(sidtype), sidtype);
63011963SAfshin.Ardakani@Sun.COM quota = list_next(quota_list, quota);
63111963SAfshin.Ardakani@Sun.COM continue;
63211963SAfshin.Ardakani@Sun.COM }
63311963SAfshin.Ardakani@Sun.COM
63411963SAfshin.Ardakani@Sun.COM if ((smb_quota_getid(quota->q_sidstr, sidtype, &id) == 0) &&
63511963SAfshin.Ardakani@Sun.COM !(IDMAP_ID_IS_EPHEMERAL(id))) {
63611963SAfshin.Ardakani@Sun.COM (void) snprintf(qsetstr, SMB_QUOTA_CMD_STR_LENGTH,
63711963SAfshin.Ardakani@Sun.COM "%s@%d", typestr, id);
63811963SAfshin.Ardakani@Sun.COM } else {
63911963SAfshin.Ardakani@Sun.COM (void) snprintf(qsetstr, SMB_QUOTA_CMD_STR_LENGTH,
64011963SAfshin.Ardakani@Sun.COM "%s@%s", typestr, quota->q_sidstr);
64111963SAfshin.Ardakani@Sun.COM }
64211963SAfshin.Ardakani@Sun.COM
64311963SAfshin.Ardakani@Sun.COM errno = 0;
64411963SAfshin.Ardakani@Sun.COM if (zfs_prop_set(zfs_hdl.z_fs, qsetstr, qlimit) != 0) {
64511963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "Failed to set quota for %s: %s",
64611963SAfshin.Ardakani@Sun.COM quota->q_sidstr, strerror(errno));
64711963SAfshin.Ardakani@Sun.COM status = NT_STATUS_INVALID_PARAMETER;
64811963SAfshin.Ardakani@Sun.COM break;
64911963SAfshin.Ardakani@Sun.COM }
65011963SAfshin.Ardakani@Sun.COM
65111963SAfshin.Ardakani@Sun.COM quota = list_next(quota_list, quota);
65211963SAfshin.Ardakani@Sun.COM }
65311963SAfshin.Ardakani@Sun.COM
65411963SAfshin.Ardakani@Sun.COM smb_quota_zfs_fini(&zfs_hdl);
65511963SAfshin.Ardakani@Sun.COM return (status);
65611963SAfshin.Ardakani@Sun.COM }
65711963SAfshin.Ardakani@Sun.COM
65811963SAfshin.Ardakani@Sun.COM /*
65911963SAfshin.Ardakani@Sun.COM * smb_quota_sidtype
66011963SAfshin.Ardakani@Sun.COM *
66111963SAfshin.Ardakani@Sun.COM * Determine the type of the sid. If the sid exists in
66211963SAfshin.Ardakani@Sun.COM * the qtree get its type from there, otherwise do an
66311963SAfshin.Ardakani@Sun.COM * lsa_lookup_sid().
66411963SAfshin.Ardakani@Sun.COM */
66511963SAfshin.Ardakani@Sun.COM static uint32_t
smb_quota_sidtype(smb_quota_tree_t * qtree,char * sidstr)66611963SAfshin.Ardakani@Sun.COM smb_quota_sidtype(smb_quota_tree_t *qtree, char *sidstr)
66711963SAfshin.Ardakani@Sun.COM {
66811963SAfshin.Ardakani@Sun.COM smb_quota_t key, *quota;
66911963SAfshin.Ardakani@Sun.COM avl_index_t where;
67011963SAfshin.Ardakani@Sun.COM smb_sid_t *sid = NULL;
67111963SAfshin.Ardakani@Sun.COM smb_account_t ainfo;
67211963SAfshin.Ardakani@Sun.COM uint32_t sidtype = SidTypeUnknown;
67311963SAfshin.Ardakani@Sun.COM
67411963SAfshin.Ardakani@Sun.COM (void) strlcpy(key.q_sidstr, sidstr, SMB_SID_STRSZ);
67511963SAfshin.Ardakani@Sun.COM quota = avl_find(&qtree->qt_avl, &key, &where);
67611963SAfshin.Ardakani@Sun.COM if (quota)
67711963SAfshin.Ardakani@Sun.COM return (quota->q_sidtype);
67811963SAfshin.Ardakani@Sun.COM
67911963SAfshin.Ardakani@Sun.COM sid = smb_sid_fromstr(sidstr);
68011963SAfshin.Ardakani@Sun.COM if (sid != NULL) {
68111963SAfshin.Ardakani@Sun.COM if (lsa_lookup_sid(sid, &ainfo) == NT_STATUS_SUCCESS) {
68211963SAfshin.Ardakani@Sun.COM sidtype = ainfo.a_type;
68311963SAfshin.Ardakani@Sun.COM smb_account_free(&ainfo);
68411963SAfshin.Ardakani@Sun.COM }
68511963SAfshin.Ardakani@Sun.COM smb_sid_free(sid);
68611963SAfshin.Ardakani@Sun.COM }
68711963SAfshin.Ardakani@Sun.COM return (sidtype);
68811963SAfshin.Ardakani@Sun.COM }
68911963SAfshin.Ardakani@Sun.COM
69011963SAfshin.Ardakani@Sun.COM /*
69111963SAfshin.Ardakani@Sun.COM * smb_quota_getid
69211963SAfshin.Ardakani@Sun.COM *
69311963SAfshin.Ardakani@Sun.COM * Get the user/group id for the sid.
69411963SAfshin.Ardakani@Sun.COM */
69511963SAfshin.Ardakani@Sun.COM static int
smb_quota_getid(char * sidstr,uint32_t sidtype,uint32_t * id)69611963SAfshin.Ardakani@Sun.COM smb_quota_getid(char *sidstr, uint32_t sidtype, uint32_t *id)
69711963SAfshin.Ardakani@Sun.COM {
69811963SAfshin.Ardakani@Sun.COM int rc = 0;
69911963SAfshin.Ardakani@Sun.COM smb_sid_t *sid = NULL;
70011963SAfshin.Ardakani@Sun.COM int idtype;
70111963SAfshin.Ardakani@Sun.COM
70211963SAfshin.Ardakani@Sun.COM sid = smb_sid_fromstr(sidstr);
70311963SAfshin.Ardakani@Sun.COM if (sid == NULL)
70411963SAfshin.Ardakani@Sun.COM return (-1);
70511963SAfshin.Ardakani@Sun.COM
70611963SAfshin.Ardakani@Sun.COM switch (sidtype) {
70711963SAfshin.Ardakani@Sun.COM case SidTypeUser:
70811963SAfshin.Ardakani@Sun.COM idtype = SMB_IDMAP_USER;
70911963SAfshin.Ardakani@Sun.COM break;
71011963SAfshin.Ardakani@Sun.COM case SidTypeWellKnownGroup:
71111963SAfshin.Ardakani@Sun.COM case SidTypeGroup:
71211963SAfshin.Ardakani@Sun.COM case SidTypeAlias:
71311963SAfshin.Ardakani@Sun.COM idtype = SMB_IDMAP_GROUP;
71411963SAfshin.Ardakani@Sun.COM break;
71511963SAfshin.Ardakani@Sun.COM default:
71611963SAfshin.Ardakani@Sun.COM rc = -1;
71711963SAfshin.Ardakani@Sun.COM break;
71811963SAfshin.Ardakani@Sun.COM }
71911963SAfshin.Ardakani@Sun.COM
72011963SAfshin.Ardakani@Sun.COM if (rc == 0)
72111963SAfshin.Ardakani@Sun.COM rc = smb_idmap_getid(sid, id, &idtype);
72211963SAfshin.Ardakani@Sun.COM
72311963SAfshin.Ardakani@Sun.COM smb_sid_free(sid);
72411963SAfshin.Ardakani@Sun.COM
72511963SAfshin.Ardakani@Sun.COM return (rc);
72611963SAfshin.Ardakani@Sun.COM }
72711963SAfshin.Ardakani@Sun.COM
72811963SAfshin.Ardakani@Sun.COM /*
72911963SAfshin.Ardakani@Sun.COM * smb_quota_tree_lookup
73011963SAfshin.Ardakani@Sun.COM *
73111963SAfshin.Ardakani@Sun.COM * Find the quota tree in smb_quota_fs_list.
73211963SAfshin.Ardakani@Sun.COM *
73311963SAfshin.Ardakani@Sun.COM * If the tree is found but is locked, waits for it to become available.
73411963SAfshin.Ardakani@Sun.COM * If the tree is available, locks it and returns it.
73511963SAfshin.Ardakani@Sun.COM * Otherwise, returns NULL.
73611963SAfshin.Ardakani@Sun.COM */
73711963SAfshin.Ardakani@Sun.COM static smb_quota_tree_t *
smb_quota_tree_lookup(const char * path)73811963SAfshin.Ardakani@Sun.COM smb_quota_tree_lookup(const char *path)
73911963SAfshin.Ardakani@Sun.COM {
74011963SAfshin.Ardakani@Sun.COM smb_quota_tree_t *qtree = NULL;
74111963SAfshin.Ardakani@Sun.COM
74211963SAfshin.Ardakani@Sun.COM assert(path);
74311963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&smb_quota_list_mutex);
74411963SAfshin.Ardakani@Sun.COM
74511963SAfshin.Ardakani@Sun.COM qtree = list_head(&smb_quota_fs_list);
74611963SAfshin.Ardakani@Sun.COM while (qtree != NULL) {
74711963SAfshin.Ardakani@Sun.COM if (!smb_quota_list_init || smb_quota_shutdown) {
74811963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex);
74911963SAfshin.Ardakani@Sun.COM return (NULL);
75011963SAfshin.Ardakani@Sun.COM }
75111963SAfshin.Ardakani@Sun.COM
75211963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&qtree->qt_mutex);
75311963SAfshin.Ardakani@Sun.COM assert(qtree->qt_refcnt > 0);
75411963SAfshin.Ardakani@Sun.COM
75511963SAfshin.Ardakani@Sun.COM if (!smb_quota_tree_match(qtree, path)) {
75611963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&qtree->qt_mutex);
75711963SAfshin.Ardakani@Sun.COM qtree = list_next(&smb_quota_fs_list, qtree);
75811963SAfshin.Ardakani@Sun.COM continue;
75911963SAfshin.Ardakani@Sun.COM }
76011963SAfshin.Ardakani@Sun.COM
76111963SAfshin.Ardakani@Sun.COM if (qtree->qt_locked) {
76211963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&qtree->qt_mutex);
76311963SAfshin.Ardakani@Sun.COM (void) cond_wait(&smb_quota_list_condvar,
76411963SAfshin.Ardakani@Sun.COM &smb_quota_list_mutex);
76511963SAfshin.Ardakani@Sun.COM qtree = list_head(&smb_quota_fs_list);
76611963SAfshin.Ardakani@Sun.COM continue;
76711963SAfshin.Ardakani@Sun.COM }
76811963SAfshin.Ardakani@Sun.COM
76911963SAfshin.Ardakani@Sun.COM ++(qtree->qt_refcnt);
77011963SAfshin.Ardakani@Sun.COM qtree->qt_locked = B_TRUE;
77111963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&qtree->qt_mutex);
77211963SAfshin.Ardakani@Sun.COM break;
77311963SAfshin.Ardakani@Sun.COM };
77411963SAfshin.Ardakani@Sun.COM
77511963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex);
77611963SAfshin.Ardakani@Sun.COM return (qtree);
77711963SAfshin.Ardakani@Sun.COM }
77811963SAfshin.Ardakani@Sun.COM
77911963SAfshin.Ardakani@Sun.COM /*
78011963SAfshin.Ardakani@Sun.COM * smb_quota_tree_release
78111963SAfshin.Ardakani@Sun.COM */
78211963SAfshin.Ardakani@Sun.COM static void
smb_quota_tree_release(smb_quota_tree_t * qtree)78311963SAfshin.Ardakani@Sun.COM smb_quota_tree_release(smb_quota_tree_t *qtree)
78411963SAfshin.Ardakani@Sun.COM {
78511963SAfshin.Ardakani@Sun.COM boolean_t delete;
78611963SAfshin.Ardakani@Sun.COM
78711963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&qtree->qt_mutex);
78811963SAfshin.Ardakani@Sun.COM assert(qtree->qt_locked);
78911963SAfshin.Ardakani@Sun.COM assert(qtree->qt_refcnt > 0);
79011963SAfshin.Ardakani@Sun.COM
79111963SAfshin.Ardakani@Sun.COM --(qtree->qt_refcnt);
79211963SAfshin.Ardakani@Sun.COM qtree->qt_locked = B_FALSE;
79311963SAfshin.Ardakani@Sun.COM delete = (qtree->qt_refcnt == 0);
79411963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&qtree->qt_mutex);
79511963SAfshin.Ardakani@Sun.COM
79611963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&smb_quota_list_mutex);
79711963SAfshin.Ardakani@Sun.COM if (delete)
79811963SAfshin.Ardakani@Sun.COM smb_quota_tree_delete(qtree);
79911963SAfshin.Ardakani@Sun.COM (void) cond_broadcast(&smb_quota_list_condvar);
80011963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex);
80111963SAfshin.Ardakani@Sun.COM }
80211963SAfshin.Ardakani@Sun.COM
80311963SAfshin.Ardakani@Sun.COM /*
80411963SAfshin.Ardakani@Sun.COM * smb_quota_tree_match
80511963SAfshin.Ardakani@Sun.COM *
80611963SAfshin.Ardakani@Sun.COM * Determine if qtree represents the file system identified by path
80711963SAfshin.Ardakani@Sun.COM */
80811963SAfshin.Ardakani@Sun.COM static boolean_t
smb_quota_tree_match(smb_quota_tree_t * qtree,const char * path)80911963SAfshin.Ardakani@Sun.COM smb_quota_tree_match(smb_quota_tree_t *qtree, const char *path)
81011963SAfshin.Ardakani@Sun.COM {
81111963SAfshin.Ardakani@Sun.COM return (strncmp(qtree->qt_path, path, MAXPATHLEN) == 0);
81211963SAfshin.Ardakani@Sun.COM }
81311963SAfshin.Ardakani@Sun.COM
81411963SAfshin.Ardakani@Sun.COM /*
81511963SAfshin.Ardakani@Sun.COM * smb_quota_tree_create
81611963SAfshin.Ardakani@Sun.COM *
81711963SAfshin.Ardakani@Sun.COM * Create and initialize an smb_quota_tree_t structure
81811963SAfshin.Ardakani@Sun.COM */
81911963SAfshin.Ardakani@Sun.COM static smb_quota_tree_t *
smb_quota_tree_create(const char * path)82011963SAfshin.Ardakani@Sun.COM smb_quota_tree_create(const char *path)
82111963SAfshin.Ardakani@Sun.COM {
82211963SAfshin.Ardakani@Sun.COM smb_quota_tree_t *qtree;
82311963SAfshin.Ardakani@Sun.COM
82411963SAfshin.Ardakani@Sun.COM assert(MUTEX_HELD(&smb_quota_list_mutex));
82511963SAfshin.Ardakani@Sun.COM
82612065SKeyur.Desai@Sun.COM qtree = calloc(sizeof (smb_quota_tree_t), 1);
82711963SAfshin.Ardakani@Sun.COM if (qtree == NULL)
82811963SAfshin.Ardakani@Sun.COM return (NULL);
82911963SAfshin.Ardakani@Sun.COM
83011963SAfshin.Ardakani@Sun.COM qtree->qt_path = strdup(path);
83111963SAfshin.Ardakani@Sun.COM if (qtree->qt_path == NULL) {
83211963SAfshin.Ardakani@Sun.COM free(qtree);
83311963SAfshin.Ardakani@Sun.COM return (NULL);
83411963SAfshin.Ardakani@Sun.COM }
83511963SAfshin.Ardakani@Sun.COM
83611963SAfshin.Ardakani@Sun.COM qtree->qt_timestamp = 0;
83711963SAfshin.Ardakani@Sun.COM qtree->qt_locked = B_FALSE;
83811963SAfshin.Ardakani@Sun.COM qtree->qt_refcnt = 1;
83911963SAfshin.Ardakani@Sun.COM qtree->qt_sharecnt = 1;
84011963SAfshin.Ardakani@Sun.COM
84111963SAfshin.Ardakani@Sun.COM avl_create(&qtree->qt_avl, smb_quota_sid_cmp,
84211963SAfshin.Ardakani@Sun.COM sizeof (smb_quota_t), offsetof(smb_quota_t, q_avl_node));
84311963SAfshin.Ardakani@Sun.COM
84411963SAfshin.Ardakani@Sun.COM ++smb_quota_tree_cnt;
84511963SAfshin.Ardakani@Sun.COM return (qtree);
84611963SAfshin.Ardakani@Sun.COM }
84711963SAfshin.Ardakani@Sun.COM
84811963SAfshin.Ardakani@Sun.COM /*
84911963SAfshin.Ardakani@Sun.COM * smb_quota_tree_delete
85011963SAfshin.Ardakani@Sun.COM *
85111963SAfshin.Ardakani@Sun.COM * Free and delete the smb_quota_tree_t structure.
85211963SAfshin.Ardakani@Sun.COM * qtree must have no users (refcnt == 0).
85311963SAfshin.Ardakani@Sun.COM */
85411963SAfshin.Ardakani@Sun.COM static void
smb_quota_tree_delete(smb_quota_tree_t * qtree)85511963SAfshin.Ardakani@Sun.COM smb_quota_tree_delete(smb_quota_tree_t *qtree)
85611963SAfshin.Ardakani@Sun.COM {
85711963SAfshin.Ardakani@Sun.COM void *cookie = NULL;
85811963SAfshin.Ardakani@Sun.COM smb_quota_t *node;
85911963SAfshin.Ardakani@Sun.COM
86011963SAfshin.Ardakani@Sun.COM assert(MUTEX_HELD(&smb_quota_list_mutex));
86111963SAfshin.Ardakani@Sun.COM assert(qtree->qt_refcnt == 0);
86211963SAfshin.Ardakani@Sun.COM
86311963SAfshin.Ardakani@Sun.COM while ((node = avl_destroy_nodes(&qtree->qt_avl, &cookie)) != NULL)
86411963SAfshin.Ardakani@Sun.COM free(node);
86511963SAfshin.Ardakani@Sun.COM avl_destroy(&qtree->qt_avl);
86611963SAfshin.Ardakani@Sun.COM
86711963SAfshin.Ardakani@Sun.COM free(qtree->qt_path);
86811963SAfshin.Ardakani@Sun.COM free(qtree);
86911963SAfshin.Ardakani@Sun.COM
87011963SAfshin.Ardakani@Sun.COM --smb_quota_tree_cnt;
87111963SAfshin.Ardakani@Sun.COM }
87211963SAfshin.Ardakani@Sun.COM
87311963SAfshin.Ardakani@Sun.COM /*
87411963SAfshin.Ardakani@Sun.COM * smb_quota_sid_cmp
87511963SAfshin.Ardakani@Sun.COM *
87611963SAfshin.Ardakani@Sun.COM * Comparision function for nodes in an AVL tree which holds quota
87711963SAfshin.Ardakani@Sun.COM * entries indexed by SID.
87811963SAfshin.Ardakani@Sun.COM */
87911963SAfshin.Ardakani@Sun.COM static int
smb_quota_sid_cmp(const void * l_arg,const void * r_arg)88011963SAfshin.Ardakani@Sun.COM smb_quota_sid_cmp(const void *l_arg, const void *r_arg)
88111963SAfshin.Ardakani@Sun.COM {
88211963SAfshin.Ardakani@Sun.COM const char *l_sid = ((smb_quota_t *)l_arg)->q_sidstr;
88311963SAfshin.Ardakani@Sun.COM const char *r_sid = ((smb_quota_t *)r_arg)->q_sidstr;
88411963SAfshin.Ardakani@Sun.COM int ret;
88511963SAfshin.Ardakani@Sun.COM
88611963SAfshin.Ardakani@Sun.COM ret = strncasecmp(l_sid, r_sid, SMB_SID_STRSZ);
88711963SAfshin.Ardakani@Sun.COM
88811963SAfshin.Ardakani@Sun.COM if (ret > 0)
88911963SAfshin.Ardakani@Sun.COM return (1);
89011963SAfshin.Ardakani@Sun.COM if (ret < 0)
89111963SAfshin.Ardakani@Sun.COM return (-1);
89211963SAfshin.Ardakani@Sun.COM return (0);
89311963SAfshin.Ardakani@Sun.COM }
89411963SAfshin.Ardakani@Sun.COM
89511963SAfshin.Ardakani@Sun.COM /*
89611963SAfshin.Ardakani@Sun.COM * smb_quota_tree_populate
89711963SAfshin.Ardakani@Sun.COM *
89811963SAfshin.Ardakani@Sun.COM * If the quota tree needs to be (re)populated:
89911963SAfshin.Ardakani@Sun.COM * - delete the qtree's contents
90011963SAfshin.Ardakani@Sun.COM * - repopulate the qtree from zfs
90111963SAfshin.Ardakani@Sun.COM * - set the qtree's timestamp.
90211963SAfshin.Ardakani@Sun.COM */
90311963SAfshin.Ardakani@Sun.COM static uint32_t
smb_quota_tree_populate(smb_quota_tree_t * qtree)90411963SAfshin.Ardakani@Sun.COM smb_quota_tree_populate(smb_quota_tree_t *qtree)
90511963SAfshin.Ardakani@Sun.COM {
90611963SAfshin.Ardakani@Sun.COM void *cookie = NULL;
90711963SAfshin.Ardakani@Sun.COM void *node;
90811963SAfshin.Ardakani@Sun.COM uint32_t status;
90911963SAfshin.Ardakani@Sun.COM
91011963SAfshin.Ardakani@Sun.COM assert(qtree->qt_locked);
91111963SAfshin.Ardakani@Sun.COM
91211963SAfshin.Ardakani@Sun.COM if (!smb_quota_tree_expired(qtree))
91311963SAfshin.Ardakani@Sun.COM return (NT_STATUS_SUCCESS);
91411963SAfshin.Ardakani@Sun.COM
91511963SAfshin.Ardakani@Sun.COM while ((node = avl_destroy_nodes(&qtree->qt_avl, &cookie)) != NULL)
91611963SAfshin.Ardakani@Sun.COM free(node);
91711963SAfshin.Ardakani@Sun.COM
91811963SAfshin.Ardakani@Sun.COM status = smb_quota_zfs_get_quotas(qtree);
91911963SAfshin.Ardakani@Sun.COM if (status != NT_STATUS_SUCCESS)
92011963SAfshin.Ardakani@Sun.COM return (status);
92111963SAfshin.Ardakani@Sun.COM
92211963SAfshin.Ardakani@Sun.COM qtree->qt_timestamp = time(NULL);
92311963SAfshin.Ardakani@Sun.COM
92411963SAfshin.Ardakani@Sun.COM return (NT_STATUS_SUCCESS);
92511963SAfshin.Ardakani@Sun.COM }
92611963SAfshin.Ardakani@Sun.COM
92711963SAfshin.Ardakani@Sun.COM static boolean_t
smb_quota_tree_expired(smb_quota_tree_t * qtree)92811963SAfshin.Ardakani@Sun.COM smb_quota_tree_expired(smb_quota_tree_t *qtree)
92911963SAfshin.Ardakani@Sun.COM {
93011963SAfshin.Ardakani@Sun.COM time_t tnow = time(NULL);
93111963SAfshin.Ardakani@Sun.COM return ((tnow - qtree->qt_timestamp) > SMB_QUOTA_REFRESH);
93211963SAfshin.Ardakani@Sun.COM }
93311963SAfshin.Ardakani@Sun.COM
93411963SAfshin.Ardakani@Sun.COM static void
smb_quota_tree_set_expired(smb_quota_tree_t * qtree)93511963SAfshin.Ardakani@Sun.COM smb_quota_tree_set_expired(smb_quota_tree_t *qtree)
93611963SAfshin.Ardakani@Sun.COM {
93711963SAfshin.Ardakani@Sun.COM qtree->qt_timestamp = 0;
93811963SAfshin.Ardakani@Sun.COM }
93911963SAfshin.Ardakani@Sun.COM
94011963SAfshin.Ardakani@Sun.COM /*
94111963SAfshin.Ardakani@Sun.COM * smb_quota_zfs_get_quotas
94211963SAfshin.Ardakani@Sun.COM *
94311963SAfshin.Ardakani@Sun.COM * Get user and group quotas from ZFS and use them to
94411963SAfshin.Ardakani@Sun.COM * populate the quota tree.
94511963SAfshin.Ardakani@Sun.COM */
94611963SAfshin.Ardakani@Sun.COM static uint32_t
smb_quota_zfs_get_quotas(smb_quota_tree_t * qtree)94711963SAfshin.Ardakani@Sun.COM smb_quota_zfs_get_quotas(smb_quota_tree_t *qtree)
94811963SAfshin.Ardakani@Sun.COM {
94911963SAfshin.Ardakani@Sun.COM smb_quota_zfs_handle_t zfs_hdl;
95011963SAfshin.Ardakani@Sun.COM smb_quota_zfs_arg_t arg;
95111963SAfshin.Ardakani@Sun.COM zfs_userquota_prop_t p;
95211963SAfshin.Ardakani@Sun.COM uint32_t status = NT_STATUS_SUCCESS;
95311963SAfshin.Ardakani@Sun.COM
95411963SAfshin.Ardakani@Sun.COM status = smb_quota_zfs_init(qtree->qt_path, &zfs_hdl);
95511963SAfshin.Ardakani@Sun.COM if (status != NT_STATUS_SUCCESS)
95611963SAfshin.Ardakani@Sun.COM return (status);
95711963SAfshin.Ardakani@Sun.COM
95811963SAfshin.Ardakani@Sun.COM arg.qa_avl = &qtree->qt_avl;
95911963SAfshin.Ardakani@Sun.COM for (p = 0; p < ZFS_NUM_USERQUOTA_PROPS; p++) {
96011963SAfshin.Ardakani@Sun.COM arg.qa_prop = p;
96111963SAfshin.Ardakani@Sun.COM if (zfs_userspace(zfs_hdl.z_fs, p,
96211963SAfshin.Ardakani@Sun.COM smb_quota_zfs_callback, &arg) != 0) {
96311963SAfshin.Ardakani@Sun.COM status = NT_STATUS_INTERNAL_ERROR;
96411963SAfshin.Ardakani@Sun.COM break;
96511963SAfshin.Ardakani@Sun.COM }
96611963SAfshin.Ardakani@Sun.COM }
96711963SAfshin.Ardakani@Sun.COM
96811963SAfshin.Ardakani@Sun.COM smb_quota_zfs_fini(&zfs_hdl);
96911963SAfshin.Ardakani@Sun.COM return (status);
97011963SAfshin.Ardakani@Sun.COM }
97111963SAfshin.Ardakani@Sun.COM
97211963SAfshin.Ardakani@Sun.COM /*
97311963SAfshin.Ardakani@Sun.COM * smb_quota_zfs_callback
97411963SAfshin.Ardakani@Sun.COM *
97511963SAfshin.Ardakani@Sun.COM * Find or create a node in the avl tree (arg->qa_avl) that matches
97611963SAfshin.Ardakani@Sun.COM * the SID derived from domain and rid. If no domain is specified,
97711963SAfshin.Ardakani@Sun.COM * lookup the sid (smb_quota_sidstr()).
97811963SAfshin.Ardakani@Sun.COM * Populate the node.
97911963SAfshin.Ardakani@Sun.COM * The property type (arg->qa_prop) determines which property 'space'
98011963SAfshin.Ardakani@Sun.COM * refers to.
98111963SAfshin.Ardakani@Sun.COM */
98211963SAfshin.Ardakani@Sun.COM static int
smb_quota_zfs_callback(void * arg,const char * domain,uid_t rid,uint64_t space)98311963SAfshin.Ardakani@Sun.COM smb_quota_zfs_callback(void *arg, const char *domain, uid_t rid, uint64_t space)
98411963SAfshin.Ardakani@Sun.COM {
98511963SAfshin.Ardakani@Sun.COM smb_quota_zfs_arg_t *qarg = (smb_quota_zfs_arg_t *)arg;
98611963SAfshin.Ardakani@Sun.COM zfs_userquota_prop_t qprop = qarg->qa_prop;
98711963SAfshin.Ardakani@Sun.COM avl_tree_t *avl_tree = qarg->qa_avl;
98811963SAfshin.Ardakani@Sun.COM avl_index_t where;
98911963SAfshin.Ardakani@Sun.COM smb_quota_t *quota, key;
99011963SAfshin.Ardakani@Sun.COM
99111963SAfshin.Ardakani@Sun.COM if (domain == NULL || domain[0] == '\0') {
99211963SAfshin.Ardakani@Sun.COM if (smb_quota_sidstr(rid, qprop, key.q_sidstr) != 0)
99311963SAfshin.Ardakani@Sun.COM return (0);
99411963SAfshin.Ardakani@Sun.COM } else {
99511963SAfshin.Ardakani@Sun.COM (void) snprintf(key.q_sidstr, SMB_SID_STRSZ, "%s-%u",
99611963SAfshin.Ardakani@Sun.COM domain, (uint32_t)rid);
99711963SAfshin.Ardakani@Sun.COM }
99811963SAfshin.Ardakani@Sun.COM
99911963SAfshin.Ardakani@Sun.COM quota = avl_find(avl_tree, &key, &where);
100011963SAfshin.Ardakani@Sun.COM if (quota == NULL) {
100111963SAfshin.Ardakani@Sun.COM quota = malloc(sizeof (smb_quota_t));
100211963SAfshin.Ardakani@Sun.COM if (quota == NULL)
100311963SAfshin.Ardakani@Sun.COM return (NT_STATUS_NO_MEMORY);
100411963SAfshin.Ardakani@Sun.COM bzero(quota, sizeof (smb_quota_t));
100511963SAfshin.Ardakani@Sun.COM quota->q_thresh = SMB_QUOTA_UNLIMITED;
100611963SAfshin.Ardakani@Sun.COM quota->q_limit = SMB_QUOTA_UNLIMITED;
100711963SAfshin.Ardakani@Sun.COM avl_insert(avl_tree, (void *)quota, where);
100811963SAfshin.Ardakani@Sun.COM (void) strlcpy(quota->q_sidstr, key.q_sidstr, SMB_SID_STRSZ);
100911963SAfshin.Ardakani@Sun.COM }
101011963SAfshin.Ardakani@Sun.COM
101111963SAfshin.Ardakani@Sun.COM switch (qprop) {
101211963SAfshin.Ardakani@Sun.COM case ZFS_PROP_USERUSED:
101311963SAfshin.Ardakani@Sun.COM quota->q_sidtype = SidTypeUser;
101411963SAfshin.Ardakani@Sun.COM quota->q_used = space;
101511963SAfshin.Ardakani@Sun.COM break;
101611963SAfshin.Ardakani@Sun.COM case ZFS_PROP_GROUPUSED:
101711963SAfshin.Ardakani@Sun.COM quota->q_sidtype = SidTypeGroup;
101811963SAfshin.Ardakani@Sun.COM quota->q_used = space;
101911963SAfshin.Ardakani@Sun.COM break;
102011963SAfshin.Ardakani@Sun.COM case ZFS_PROP_USERQUOTA:
102111963SAfshin.Ardakani@Sun.COM quota->q_sidtype = SidTypeUser;
102211963SAfshin.Ardakani@Sun.COM quota->q_limit = space;
102311963SAfshin.Ardakani@Sun.COM break;
102411963SAfshin.Ardakani@Sun.COM case ZFS_PROP_GROUPQUOTA:
102511963SAfshin.Ardakani@Sun.COM quota->q_sidtype = SidTypeGroup;
102611963SAfshin.Ardakani@Sun.COM quota->q_limit = space;
102711963SAfshin.Ardakani@Sun.COM break;
102811963SAfshin.Ardakani@Sun.COM default:
102911963SAfshin.Ardakani@Sun.COM break;
103011963SAfshin.Ardakani@Sun.COM }
103111963SAfshin.Ardakani@Sun.COM
103211963SAfshin.Ardakani@Sun.COM quota->q_thresh = quota->q_limit;
103311963SAfshin.Ardakani@Sun.COM
103411963SAfshin.Ardakani@Sun.COM return (0);
103511963SAfshin.Ardakani@Sun.COM }
103611963SAfshin.Ardakani@Sun.COM
103711963SAfshin.Ardakani@Sun.COM /*
103811963SAfshin.Ardakani@Sun.COM * smb_quota_sidstr
103911963SAfshin.Ardakani@Sun.COM *
104011963SAfshin.Ardakani@Sun.COM * Use idmap to get the sid for the specified id and return
104111963SAfshin.Ardakani@Sun.COM * the string version of the sid in sidstr.
104211963SAfshin.Ardakani@Sun.COM * sidstr must be a buffer of at least SMB_SID_STRSZ.
104311963SAfshin.Ardakani@Sun.COM */
104411963SAfshin.Ardakani@Sun.COM static int
smb_quota_sidstr(uint32_t id,zfs_userquota_prop_t qprop,char * sidstr)104511963SAfshin.Ardakani@Sun.COM smb_quota_sidstr(uint32_t id, zfs_userquota_prop_t qprop, char *sidstr)
104611963SAfshin.Ardakani@Sun.COM {
104711963SAfshin.Ardakani@Sun.COM int idtype;
104811963SAfshin.Ardakani@Sun.COM smb_sid_t *sid;
104911963SAfshin.Ardakani@Sun.COM
105011963SAfshin.Ardakani@Sun.COM switch (qprop) {
105111963SAfshin.Ardakani@Sun.COM case ZFS_PROP_USERUSED:
105211963SAfshin.Ardakani@Sun.COM case ZFS_PROP_USERQUOTA:
105311963SAfshin.Ardakani@Sun.COM idtype = SMB_IDMAP_USER;
105411963SAfshin.Ardakani@Sun.COM break;
105511963SAfshin.Ardakani@Sun.COM case ZFS_PROP_GROUPUSED:
105611963SAfshin.Ardakani@Sun.COM case ZFS_PROP_GROUPQUOTA:
105711963SAfshin.Ardakani@Sun.COM idtype = SMB_IDMAP_GROUP;
105811963SAfshin.Ardakani@Sun.COM break;
105911963SAfshin.Ardakani@Sun.COM default:
106011963SAfshin.Ardakani@Sun.COM return (-1);
106111963SAfshin.Ardakani@Sun.COM }
106211963SAfshin.Ardakani@Sun.COM
106311963SAfshin.Ardakani@Sun.COM if (smb_idmap_getsid(id, idtype, &sid) != IDMAP_SUCCESS)
106411963SAfshin.Ardakani@Sun.COM return (-1);
106511963SAfshin.Ardakani@Sun.COM
106611963SAfshin.Ardakani@Sun.COM smb_sid_tostr(sid, sidstr);
106711963SAfshin.Ardakani@Sun.COM smb_sid_free(sid);
106811963SAfshin.Ardakani@Sun.COM
106911963SAfshin.Ardakani@Sun.COM return (0);
107011963SAfshin.Ardakani@Sun.COM }
107111963SAfshin.Ardakani@Sun.COM
107211963SAfshin.Ardakani@Sun.COM /*
107311963SAfshin.Ardakani@Sun.COM * smb_quota_zfs_init
107411963SAfshin.Ardakani@Sun.COM *
107511963SAfshin.Ardakani@Sun.COM * Initialize zfs library and dataset handles
107611963SAfshin.Ardakani@Sun.COM */
107711963SAfshin.Ardakani@Sun.COM static uint32_t
smb_quota_zfs_init(const char * path,smb_quota_zfs_handle_t * zfs_hdl)107811963SAfshin.Ardakani@Sun.COM smb_quota_zfs_init(const char *path, smb_quota_zfs_handle_t *zfs_hdl)
107911963SAfshin.Ardakani@Sun.COM {
108011963SAfshin.Ardakani@Sun.COM char dataset[MAXPATHLEN];
108111963SAfshin.Ardakani@Sun.COM
108211963SAfshin.Ardakani@Sun.COM if (smb_getdataset(path, dataset, MAXPATHLEN) != 0)
108311963SAfshin.Ardakani@Sun.COM return (NT_STATUS_INVALID_PARAMETER);
108411963SAfshin.Ardakani@Sun.COM
108511963SAfshin.Ardakani@Sun.COM if ((zfs_hdl->z_lib = libzfs_init()) == NULL)
108611963SAfshin.Ardakani@Sun.COM return (NT_STATUS_INTERNAL_ERROR);
108711963SAfshin.Ardakani@Sun.COM
108811963SAfshin.Ardakani@Sun.COM zfs_hdl->z_fs = zfs_open(zfs_hdl->z_lib, dataset, ZFS_TYPE_DATASET);
108911963SAfshin.Ardakani@Sun.COM if (zfs_hdl->z_fs == NULL) {
109011963SAfshin.Ardakani@Sun.COM libzfs_fini(zfs_hdl->z_lib);
109111963SAfshin.Ardakani@Sun.COM return (NT_STATUS_ACCESS_DENIED);
109211963SAfshin.Ardakani@Sun.COM }
109311963SAfshin.Ardakani@Sun.COM
109411963SAfshin.Ardakani@Sun.COM return (NT_STATUS_SUCCESS);
109511963SAfshin.Ardakani@Sun.COM }
109611963SAfshin.Ardakani@Sun.COM
109711963SAfshin.Ardakani@Sun.COM /*
109811963SAfshin.Ardakani@Sun.COM * smb_quota_zfs_fini
109911963SAfshin.Ardakani@Sun.COM *
110011963SAfshin.Ardakani@Sun.COM * Close zfs library and dataset handles
110111963SAfshin.Ardakani@Sun.COM */
110211963SAfshin.Ardakani@Sun.COM static void
smb_quota_zfs_fini(smb_quota_zfs_handle_t * zfs_hdl)110311963SAfshin.Ardakani@Sun.COM smb_quota_zfs_fini(smb_quota_zfs_handle_t *zfs_hdl)
110411963SAfshin.Ardakani@Sun.COM {
110511963SAfshin.Ardakani@Sun.COM zfs_close(zfs_hdl->z_fs);
110611963SAfshin.Ardakani@Sun.COM libzfs_fini(zfs_hdl->z_lib);
110711963SAfshin.Ardakani@Sun.COM }
110811963SAfshin.Ardakani@Sun.COM
110911963SAfshin.Ardakani@Sun.COM /*
111011963SAfshin.Ardakani@Sun.COM * smb_quota_add_ctrldir
111111963SAfshin.Ardakani@Sun.COM *
111211963SAfshin.Ardakani@Sun.COM * In order to display the quota properties tab, windows clients
111311963SAfshin.Ardakani@Sun.COM * check for the existence of the quota control file, created
111411963SAfshin.Ardakani@Sun.COM * here as follows:
111511963SAfshin.Ardakani@Sun.COM * - Create SMB_QUOTA_CNTRL_DIR directory (with A_HIDDEN & A_SYSTEM
111611963SAfshin.Ardakani@Sun.COM * attributes).
111711963SAfshin.Ardakani@Sun.COM * - Create the SMB_QUOTA_CNTRL_FILE file (with extended attribute
111811963SAfshin.Ardakani@Sun.COM * SMB_QUOTA_CNTRL_INDEX_XATTR) in the SMB_QUOTA_CNTRL_DIR directory.
111911963SAfshin.Ardakani@Sun.COM * - Set the acl of SMB_QUOTA_CNTRL_FILE file to SMB_QUOTA_CNTRL_PERM.
112011963SAfshin.Ardakani@Sun.COM */
112111963SAfshin.Ardakani@Sun.COM static void
smb_quota_add_ctrldir(const char * path)112211963SAfshin.Ardakani@Sun.COM smb_quota_add_ctrldir(const char *path)
112311963SAfshin.Ardakani@Sun.COM {
112411963SAfshin.Ardakani@Sun.COM int newfd, dirfd, afd;
112511963SAfshin.Ardakani@Sun.COM nvlist_t *request;
112611963SAfshin.Ardakani@Sun.COM char dir[MAXPATHLEN], file[MAXPATHLEN];
112711963SAfshin.Ardakani@Sun.COM acl_t *aclp;
112811963SAfshin.Ardakani@Sun.COM struct stat statbuf;
112911963SAfshin.Ardakani@Sun.COM
113011963SAfshin.Ardakani@Sun.COM assert(path != NULL);
113111963SAfshin.Ardakani@Sun.COM
113211963SAfshin.Ardakani@Sun.COM (void) snprintf(dir, MAXPATHLEN, ".%s/%s", path, SMB_QUOTA_CNTRL_DIR);
113311963SAfshin.Ardakani@Sun.COM (void) snprintf(file, MAXPATHLEN, "%s/%s", dir, SMB_QUOTA_CNTRL_FILE);
113411963SAfshin.Ardakani@Sun.COM if ((mkdir(dir, 0750) < 0) && (errno != EEXIST))
113511963SAfshin.Ardakani@Sun.COM return;
113611963SAfshin.Ardakani@Sun.COM
113711963SAfshin.Ardakani@Sun.COM if ((dirfd = open(dir, O_RDONLY)) < 0) {
113811963SAfshin.Ardakani@Sun.COM (void) remove(dir);
113911963SAfshin.Ardakani@Sun.COM return;
114011963SAfshin.Ardakani@Sun.COM }
114111963SAfshin.Ardakani@Sun.COM
114211963SAfshin.Ardakani@Sun.COM if (nvlist_alloc(&request, NV_UNIQUE_NAME, 0) == 0) {
114311963SAfshin.Ardakani@Sun.COM if ((nvlist_add_boolean_value(request, A_HIDDEN, 1) != 0) ||
114411963SAfshin.Ardakani@Sun.COM (nvlist_add_boolean_value(request, A_SYSTEM, 1) != 0) ||
114511963SAfshin.Ardakani@Sun.COM (fsetattr(dirfd, XATTR_VIEW_READWRITE, request))) {
114611963SAfshin.Ardakani@Sun.COM nvlist_free(request);
114711963SAfshin.Ardakani@Sun.COM (void) close(dirfd);
114811963SAfshin.Ardakani@Sun.COM (void) remove(dir);
114911963SAfshin.Ardakani@Sun.COM return;
115011963SAfshin.Ardakani@Sun.COM }
115111963SAfshin.Ardakani@Sun.COM }
115211963SAfshin.Ardakani@Sun.COM nvlist_free(request);
115311963SAfshin.Ardakani@Sun.COM (void) close(dirfd);
115411963SAfshin.Ardakani@Sun.COM
115511963SAfshin.Ardakani@Sun.COM if (stat(file, &statbuf) != 0) {
115611963SAfshin.Ardakani@Sun.COM if ((newfd = creat(file, 0640)) < 0) {
115711963SAfshin.Ardakani@Sun.COM (void) remove(dir);
115811963SAfshin.Ardakani@Sun.COM return;
115911963SAfshin.Ardakani@Sun.COM }
116011963SAfshin.Ardakani@Sun.COM (void) close(newfd);
116111963SAfshin.Ardakani@Sun.COM }
116211963SAfshin.Ardakani@Sun.COM
116311963SAfshin.Ardakani@Sun.COM afd = attropen(file, SMB_QUOTA_CNTRL_INDEX_XATTR, O_RDWR | O_CREAT,
116411963SAfshin.Ardakani@Sun.COM 0640);
116511963SAfshin.Ardakani@Sun.COM if (afd == -1) {
116611963SAfshin.Ardakani@Sun.COM (void) unlink(file);
116711963SAfshin.Ardakani@Sun.COM (void) remove(dir);
116811963SAfshin.Ardakani@Sun.COM return;
116911963SAfshin.Ardakani@Sun.COM }
117011963SAfshin.Ardakani@Sun.COM (void) close(afd);
117111963SAfshin.Ardakani@Sun.COM
117211963SAfshin.Ardakani@Sun.COM if (acl_fromtext(SMB_QUOTA_CNTRL_PERM, &aclp) != 0) {
117311963SAfshin.Ardakani@Sun.COM (void) unlink(file);
117411963SAfshin.Ardakani@Sun.COM (void) remove(dir);
117511963SAfshin.Ardakani@Sun.COM return;
117611963SAfshin.Ardakani@Sun.COM }
117711963SAfshin.Ardakani@Sun.COM
117811963SAfshin.Ardakani@Sun.COM if (acl_set(file, aclp) == -1) {
117911963SAfshin.Ardakani@Sun.COM (void) unlink(file);
118011963SAfshin.Ardakani@Sun.COM (void) remove(dir);
118111963SAfshin.Ardakani@Sun.COM acl_free(aclp);
118211963SAfshin.Ardakani@Sun.COM return;
118311963SAfshin.Ardakani@Sun.COM }
118411963SAfshin.Ardakani@Sun.COM acl_free(aclp);
118511963SAfshin.Ardakani@Sun.COM }
118611963SAfshin.Ardakani@Sun.COM
118711963SAfshin.Ardakani@Sun.COM /*
118811963SAfshin.Ardakani@Sun.COM * smb_quota_remove_ctrldir
118911963SAfshin.Ardakani@Sun.COM *
119011963SAfshin.Ardakani@Sun.COM * Remove SMB_QUOTA_CNTRL_FILE and SMB_QUOTA_CNTRL_DIR.
119111963SAfshin.Ardakani@Sun.COM */
119211963SAfshin.Ardakani@Sun.COM static void
smb_quota_remove_ctrldir(const char * path)119311963SAfshin.Ardakani@Sun.COM smb_quota_remove_ctrldir(const char *path)
119411963SAfshin.Ardakani@Sun.COM {
119511963SAfshin.Ardakani@Sun.COM char dir[MAXPATHLEN], file[MAXPATHLEN];
119611963SAfshin.Ardakani@Sun.COM assert(path);
119711963SAfshin.Ardakani@Sun.COM
119811963SAfshin.Ardakani@Sun.COM (void) snprintf(dir, MAXPATHLEN, ".%s/%s", path, SMB_QUOTA_CNTRL_DIR);
119911963SAfshin.Ardakani@Sun.COM (void) snprintf(file, MAXPATHLEN, "%s/%s", dir, SMB_QUOTA_CNTRL_FILE);
120011963SAfshin.Ardakani@Sun.COM (void) unlink(file);
120111963SAfshin.Ardakani@Sun.COM (void) remove(dir);
120211963SAfshin.Ardakani@Sun.COM }
1203