4 * The bees perform the grunt work of handling a file event
6 * This code was written by Peter Lawthers, and placed in the public
7 * domain for use by DMAPI implementors and app writers.
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
14 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
15 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
16 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
17 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
19 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 #include <sys/types.h>
26 #include <sys/resource.h>
36 extern int optind, optopt, opterr;
41 extern int restore_filedata(dm_sessid_t, void *, size_t, dm_token_t,
42 void *, size_t, dm_off_t);
43 extern int get_dmchange(dm_sessid_t, void *, size_t, dm_token_t, u_int *);
44 extern int setup_dmapi(dm_sessid_t *);
45 extern void err_msg(char *, ...);
46 extern void errno_msg(char *, ...);
48 int stagein_file(dm_sessid_t, dm_token_t, dm_eventmsg_t *);
49 int inval_file(dm_sessid_t, dm_token_t, dm_eventmsg_t *);
50 int check_lockstate(dm_sessid_t, void *, size_t, dm_token_t);
51 int clear_mrgns(dm_sessid_t, void *, size_t, dm_token_t);
52 int find_msg(dm_sessid_t, dm_token_t, dm_eventmsg_t **);
53 int get_stghandle(dm_sessid_t, void *, size_t, dm_token_t, void **,
63 fprintf(stderr, "Usage: %s ", prog);
64 fprintf(stderr, " <-i invalidate file> ");
65 fprintf(stderr, " <-r restore file> ");
66 fprintf(stderr, "[-s sid] [-t token] \n");
76 dm_eventmsg_t *msgheader;
77 char *sid_str, *token_str;
82 int restore_flag, inval_flag;
91 while ((c = getopt(argc, argv, "s:t:ri")) != EOF) {
119 if (sid_str == NULL || token_str == NULL) {
123 if ((restore_flag > 0) && (inval_flag > 0)) {
128 if (sscanf(sid_str, "%d", &sid) <= 0) {
129 err_msg("Can't convert sid");
132 if (sscanf(token_str, "%d", &token) <= 0) {
133 err_msg("Can't convert token");
138 * Now we have our session and token. We just need to
139 * let the DMAPI know we exist so we can use the interface.
140 * We don't need to create a session since we'll be using
141 * the session of our parent.
143 error = dm_init_service(&cp);
145 errno_msg("Can't init DMAPI");
148 if (strcmp(cp, DM_VER_STR_CONTENTS)) {
149 err_msg("Compiled for a different version");
154 * Find the message our caller wants us to handle
156 error = find_msg(sid, token, &msgheader);
161 * Now service the particular event type
164 error = stagein_file(sid, token, msgheader);
166 error = inval_file(sid, token, msgheader);
173 * Find the data event message that correponds to the token.
176 * A pointer to malloc'd memory that contains the message
177 * we're supposed to handle in the 'msgheader' param.
183 dm_eventmsg_t **msgheader)
190 * Malloc a buffer that we think is large enough for
191 * the common message header and the event specific part.
192 * If it's not large enough, we can always resize it.
194 buflen = sizeof(dm_eventmsg_t) + sizeof(dm_data_event_t) + HANDLE_LEN;
195 buf = (void *)malloc(buflen);
197 err_msg("Can't alloc memory for event buffer");
201 error = dm_find_eventmsg(sid, token, buflen, buf, &rlen);
203 if (errno != E2BIG) {
205 errno_msg("Can't obtain message from token");
210 buf = (void *)malloc(buflen);
212 err_msg("Can't resize event buffer");
215 error = dm_find_eventmsg(sid, token, buflen, buf, &rlen);
217 errno_msg("Can't get message with resized buffer");
222 *msgheader = (dm_eventmsg_t *)buf;
228 * Check the lock state associated with the file. If the token
229 * does not reference exclusive access, try to upgrade our lock.
230 * If we can't upgrade, drop the lock and start over
241 u_int change_start, change_end;
243 error = dm_query_right(sid, hanp, hlen, token, &right);
245 errno_msg("Can't query file access rights");
248 #if defined(__sgi) || defined(linux)
250 * There are no access rights on the SGI. 1 means it's
253 if (right == DM_RIGHT_SHARED)
257 if (right != DM_RIGHT_EXCL) {
258 error = dm_request_right(sid, hanp, hlen, token, 0,
261 if (errno != EAGAIN) {
262 errno_msg("Can't upgrade lock");
265 error = get_dmchange(sid, hanp, hlen, token,
271 error = dm_release_right(sid, hanp, hlen, token);
273 errno_msg("Can't release file access rights");
276 error = dm_request_right(sid, hanp, hlen, token,
277 DM_RR_WAIT, DM_RIGHT_EXCL);
279 errno_msg("Can't get exclusive right to file");
284 * If the file changed while we slept, then someone
285 * must have modified the file
287 error = get_dmchange(sid, hanp, hlen, token,
292 if (change_start != change_end) {
293 err_msg("File changed while waiting for lock");
303 * Stage in the data for a file
309 dm_eventmsg_t *msgheader)
312 void *stg_hanp, *hanp;
313 size_t stg_hlen, hlen;
314 int error, ret_errno;
316 dm_data_event_t *msg;
319 * Extract the event-specific info from the message header,
320 * then get the file handle.
322 msg = DM_GET_VALUE(msgheader, ev_data, dm_data_event_t *);
323 hanp = DM_GET_VALUE(msg, de_handle, void *);
324 hlen = DM_GET_LEN(msg, de_handle);
327 * Check our permissions. We need exclusive access to the
328 * file to stage it back in.
330 error = check_lockstate(sid, hanp, hlen, token);
335 * get the staging file handle from it's DM attributes
338 error = get_stghandle(sid, hanp, hlen, token, &stg_hanp, &stg_hlen);
343 * We keep the exclusive lock held for the *entire* duration
344 * of the stagein. This is not required, but just quick and
345 * [sl]easy. For a large file, it is typically better to release
346 * the lock, and have a sliding window of managed regions to allow
347 * people to consume the data as it is being read in.
349 error = restore_filedata(sid, hanp, hlen, token, stg_hanp, stg_hlen,
355 * Now that the data is restored, and while we still have exclusive
356 * access to the file, clear the managed regions.
358 error = clear_mrgns(sid, hanp, hlen, token);
364 free((char *)stg_hanp);
367 * Figure out what our response to the event will be. Once
368 * we've responded to the event, the token is no longer valid.
369 * On error, we pick the (less than helpful) errno EIO to signal
370 * to the user that something went wrong.
373 reply = DM_RESP_ABORT;
376 reply = DM_RESP_CONTINUE;
379 (void)dm_respond_event(sid, token, reply, ret_errno, 0, 0);
386 * Turn off event monitoring for a file. In a real HSM, we would
387 * probably want to either invalidate the file's data on
388 * tertiary storage, or start some aging process so that it will
389 * eventually go away.
391 * The assumption is that for write and truncate events, the file
392 * data is about to be invalidated.
398 dm_eventmsg_t *msgheader)
400 dm_data_event_t *msg;
403 int error, ret_errno;
407 * Extract the event-specific info from the message header,
408 * then get the file handle.
410 msg = DM_GET_VALUE(msgheader, ev_data, dm_data_event_t *);
411 hanp = DM_GET_VALUE(msg, de_handle, void *);
412 hlen = DM_GET_LEN(msg, de_handle);
415 * Check our permissions. We need exclusive access to the
416 * file to clear our managed regions.
418 error = check_lockstate(sid, hanp, hlen, token);
423 * Clear all the managed regions for the file.
425 error = clear_mrgns(sid, hanp, hlen, token);
429 * Figure out what our response to the event will be. Once
430 * we've responded to the event, the token is no longer valid.
431 * On error, we pick the (less than helpful) errno EIO to signal
432 * to the user that something went wrong.
435 reply = DM_RESP_ABORT;
438 reply = DM_RESP_CONTINUE;
441 (void)dm_respond_event(sid, token, reply, ret_errno, 0, 0);
447 * Clear all of the managed regions for a file.
456 dm_region_t *rgn, *sv_rgn;
457 u_int nregions, nret;
463 * We take a guess first and assume there is only one managed
464 * region per file. There should'nt be more than this, but
465 * it never hurts to check, since we want to make sure that
466 * all regions are turned off.
468 * The main purpose of this is to demonstrate the use of the
473 rgn = (dm_region_t *)malloc(nregions * sizeof(dm_region_t));
475 err_msg("Can't allocate memory for region buffers");
479 error = dm_get_region(sid, hanp, hlen, token, nregions, rgn, &nret);
481 if (errno != E2BIG) {
482 errno_msg("Can't get list of managed regions for file");
487 * Now we know how many managed regions there are, so we can
492 rgn = (dm_region_t *)malloc(nregions * sizeof(dm_region_t));
494 err_msg("Can't resize region buffers");
497 error = dm_get_region(sid, hanp, hlen, token, nregions, rgn,
500 errno_msg("Can't get list of managed regions for file");
508 * Clear all the managed regions
510 for (i=0; i<nregions; i++) {
513 rgn->rg_flags = DM_REGION_NOEVENT;
518 error = dm_set_region(sid, hanp, hlen, token, nregions, rgn,
521 errno_msg("Can't clear list of managed regions for file");
534 * Extract the staging file handle from a file's DM attributes
549 dm_attrname_t hanp_attrname;
550 dm_attrname_t hlen_attrname;
553 * First get the length of the file handle, so we
554 * can size our buffer correctly
556 memcpy((void *)&hlen_attrname.an_chars[0], DLOC_HANLEN, DM_ATTR_NAME_SIZE);
557 error = dm_get_dmattr(sid, hanp, hlen, token, &hlen_attrname,
558 sizeof(size_t), &han_len, &rlen);
561 * On any error, even E2BIG, we bail since the size of
562 * the file handle should be a constant
564 errno_msg("Can't get size of staging file handle");
567 if (rlen != sizeof(size_t)) {
568 err_msg("File handle length component incorrect");
573 * Malloc space for our staging file handle, and
574 * extract it from our DM attributes
576 han_buf = (void *)malloc(han_len);
577 if (han_buf == NULL) {
578 err_msg("Can't alloc memory for file handle");
582 memcpy((void *)&hanp_attrname.an_chars[0], DLOC_HAN, DM_ATTR_NAME_SIZE);
583 error = dm_get_dmattr(sid, hanp, hlen, token, &hanp_attrname,
584 han_len, han_buf, &rlen);
586 errno_msg("Can't get staging file handle");
590 if (rlen != han_len) {
591 err_msg("File handle is incorrect length");