Initial Linux ZFS GIT Repo
[zfs.git] / zfs / lib / libudmu / udmu_util.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  lustre/dmu/udmu.c
5  *  Module that interacts with the ZFS DMU and provides an abstraction
6  *  to the rest of Lustre.
7  *
8  *  Copyright (c) 2007 Cluster File Systems, Inc.
9  *   Author: Manoj Joseph <manoj.joseph@sun.com>
10  *
11  *   This file is part of the Lustre file system, http://www.lustre.org
12  *   Lustre is a trademark of Cluster File Systems, Inc.
13  *
14  *   You may have signed or agreed to another license before downloading
15  *   this software.  If so, you are bound by the terms and conditions
16  *   of that agreement, and the following does not apply to you.  See the
17  *   LICENSE file included with this distribution for more information.
18  *
19  *   If you did not agree to a different license, then this copy of Lustre
20  *   is open source software; you can redistribute it and/or modify it
21  *   under the terms of version 2 of the GNU General Public License as
22  *   published by the Free Software Foundation.
23  *
24  *   In either case, Lustre is distributed in the hope that it will be
25  *   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
26  *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  *   license text for more details.
28  */
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <sys/debug.h>
34 #include <sys/stat.h>
35 #include <sys/statvfs.h>
36 #include <sys/errno.h>
37
38 #include <udmu.h>
39 #include <udmu_util.h>
40
41 static int udmu_util_object_delete(udmu_objset_t *uos, dmu_buf_t **dbp,
42                                    void *tag)
43 {
44         dmu_tx_t *tx;
45         uint64_t id;
46         int rc;
47
48         id = udmu_object_get_id(*dbp);
49         tx = udmu_tx_create(uos);
50
51         udmu_tx_hold_free(tx, id, 0, DMU_OBJECT_END);
52
53         rc = udmu_tx_assign(tx, TXG_WAIT);
54         if (rc) {
55                 fprintf(stderr,
56                         "udmu_util_object_delete: udmu_tx_assign failed (%d)", rc);
57                 udmu_tx_abort(tx);
58                 return (rc);
59         }
60
61         rc = udmu_object_delete(uos, dbp, tx, tag);
62         if (rc)
63                 fprintf(stderr, "udmu_object_delete() failed (%d)", rc);
64
65         udmu_tx_commit(tx);
66         return rc;
67 }
68
69 int udmu_util_mkdir(udmu_objset_t *uos, dmu_buf_t *parent_db,
70                     const char *name, dmu_buf_t **new_dbp, void *tag)
71 {
72         dmu_buf_t *db;
73         dmu_tx_t *tx;
74         uint64_t id, pid, value;
75         int rc;
76
77         /* return EEXIST early to avoid object creation/deletion */
78         rc = udmu_zap_lookup(uos, parent_db, name, &id,
79                              sizeof(id), sizeof(uint64_t));
80         if (rc == 0)
81                 return EEXIST;
82
83         pid = udmu_object_get_id(parent_db);
84
85         tx = udmu_tx_create(uos);
86         udmu_tx_hold_zap(tx, DMU_NEW_OBJECT, 1, NULL); /* for zap create */
87         udmu_tx_hold_bonus(tx, pid); /* for zap_add */
88         udmu_tx_hold_zap(tx, pid, 1, (char *)name); /* for zap_add */
89
90         rc = udmu_tx_assign(tx, TXG_WAIT);
91         if (rc) {
92                 fprintf(stderr,
93                         "udmu_util_mkdir: udmu_tx_assign failed (%d)", rc);
94                 udmu_tx_abort(tx);
95                 return (rc);
96         }
97
98         udmu_zap_create(uos, &db, tx, tag);
99         id = udmu_object_get_id(db);
100         value = ZFS_DIRENT_MAKE(0, id);
101         rc = udmu_zap_insert(uos, parent_db, tx, name, &value, sizeof(value));
102         udmu_tx_commit(tx);
103
104         if (rc) {
105                 fprintf(stderr, "can't insert (%s) in zap (%d)", name, rc);
106                 /* error handling, delete just created object */
107                 udmu_util_object_delete(uos, &db, tag);
108         } else if (new_dbp) {
109                 *new_dbp = db;
110         } else {
111                 udmu_object_put_dmu_buf(db, tag);
112         }
113
114         return (rc);
115 }
116
117 int udmu_util_setattr(udmu_objset_t *uos, dmu_buf_t *db, vnattr_t *va)
118 {
119         dmu_tx_t *tx;
120         int rc;
121
122         tx = udmu_tx_create(uos);
123         udmu_tx_hold_bonus(tx, udmu_object_get_id(db));
124
125         rc = udmu_tx_assign(tx, TXG_WAIT);
126         if (rc) {
127                 udmu_tx_abort(tx);
128         } else {
129                 udmu_object_setattr(db, tx, va);
130                 udmu_tx_commit(tx);
131         }
132
133         return (rc);
134 }
135
136 int udmu_util_create(udmu_objset_t *uos, dmu_buf_t *parent_db,
137                      const char *name, dmu_buf_t **new_dbp, void *tag)
138 {
139         dmu_buf_t *db;
140         dmu_tx_t *tx;
141         uint64_t id, pid, value;
142         int rc;
143
144         /* return EEXIST early to avoid object creation/deletion */
145         rc = udmu_zap_lookup(uos, parent_db, name, &id,
146                              sizeof(id), sizeof(uint64_t));
147         if (rc == 0)
148                 return EEXIST;
149
150         pid = udmu_object_get_id(parent_db);
151
152         tx = udmu_tx_create(uos);
153
154         udmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
155         udmu_tx_hold_bonus(tx, pid);
156         udmu_tx_hold_zap(tx, pid, 1, (char *) name);
157
158         rc = udmu_tx_assign(tx, TXG_WAIT);
159         if (rc) {
160                 fprintf(stderr,
161                         "udmu_util_create: udmu_tx_assign failed (%d)", rc);
162                 udmu_tx_abort(tx);
163                 return (rc);
164         }
165
166         udmu_object_create(uos, &db, tx, tag);
167         id = udmu_object_get_id(db);
168         value = ZFS_DIRENT_MAKE(0, id);
169         rc = udmu_zap_insert(uos, parent_db, tx, name,
170                              &value, sizeof(value));
171         udmu_tx_commit(tx);
172
173         if (rc) {
174                 fprintf(stderr, "can't insert new object in zap (%d)", rc);
175                 /* error handling, delete just created object */
176                 udmu_util_object_delete(uos, &db, tag);
177         } else if (new_dbp) {
178                 *new_dbp = db;
179         } else {
180                 udmu_object_put_dmu_buf(db, tag);
181         }
182
183         return (rc);
184 }
185
186 int udmu_util_lookup(udmu_objset_t *uos, dmu_buf_t *parent_db,
187                      const char *name, dmu_buf_t **new_dbp, void *tag)
188 {
189         uint64_t id;
190         int rc;
191
192         rc = udmu_zap_lookup(uos, parent_db, name, &id,
193                              sizeof(id), sizeof(uint64_t));
194         if (rc == 0) {
195                 udmu_object_get_dmu_buf(uos, id, new_dbp, tag);
196         }
197
198         return (rc);
199 }
200
201 int udmu_util_write(udmu_objset_t *uos, dmu_buf_t *db,
202                     uint64_t offset, uint64_t len, void *buf)
203 {
204         dmu_tx_t *tx;
205         int set_size = 0;
206         uint64_t end = offset + len;
207         vnattr_t va;
208         int rc;
209
210         udmu_object_getattr(db, &va);
211
212         if (va.va_size < end) {
213                 /* extending write; set file size */
214                 set_size = 1;
215                 va.va_mask = AT_SIZE;
216                 va.va_size = end;
217         }
218
219         tx = udmu_tx_create(uos);
220         if (set_size) {
221                 udmu_tx_hold_bonus(tx, udmu_object_get_id(db));
222         }
223         udmu_tx_hold_write(tx, udmu_object_get_id(db), offset, len);
224
225         rc = udmu_tx_assign(tx, TXG_WAIT);
226         if (rc) {
227                 fprintf(stderr, "dmu_tx_assign() failed %d", rc);
228                 udmu_tx_abort(tx);
229                 return (-rc);
230         }
231
232         udmu_object_write(uos, db, tx, offset,
233                           len, buf);
234         if (set_size) {
235                 udmu_object_setattr(db, tx, &va);
236         }
237
238         udmu_tx_commit(tx);
239
240         return (len);
241 }