2 * This is sample code generated by rpcgen.
3 * These are only templates and you can use them
4 * as a guideline for developing your own functions.
12 #define NFS_BLOCKSIZE 32768
13 #define NFS_MAXSIZE (1 << 20)
15 /* Check that a string is a valid file name. We require that it be valid
16 * UTF-8, that it not be empty, and that it not contain embedded forward
17 * slashes. Also checks that the length of the string is not more than the
18 * maximum allowed length. This function does allow the names "." and "..".
19 * Returns TRUE if the string is allowed as a filename. */
20 gboolean validate_filename(const char *filename)
22 if (filename == NULL || filename[0] == '\0')
24 if (strlen(filename) > 255)
26 if (!g_utf8_validate(filename, -1, NULL))
28 if (strchr(filename, '/') != NULL)
33 /* Arrange for a reference to an inode to be dropped when the RPC request
35 void schedule_inode_unref(RPCRequest *req, BlueSkyInode *inode)
37 struct cleanup_list *c = g_new(struct cleanup_list, 1);
38 c->func = (void (*)(void *))bluesky_inode_unref;
40 c->next = req->cleanup;
44 /* Look up a BlueSkyInode given an NFS filehandle. Returns NULL if the
45 * filehandle is invalid. */
46 BlueSkyInode *lookup_fh(RPCRequest *req, nfs_fh3 *fh)
48 BlueSkyInode *inode = NULL;
49 if (fh->data.data_len == 8) {
50 uint64_t inum = GUINT64_FROM_BE(*(uint64_t *)(fh->data.data_val));
51 inode = bluesky_get_inode(fs, inum);
53 schedule_inode_unref(req, inode);
58 int64_t decode_nfstime3(nfstime3 *time)
60 int64_t result = (int64_t)time->seconds * 1000000;
61 result += time->nseconds / 1000;
65 void set_attributes(BlueSkyInode *inode, sattr3 *attributes)
67 int64_t now = bluesky_get_current_time();
69 if (attributes->mode.set) {
70 inode->mode = attributes->mode.set_uint32_u.val;
73 if (attributes->uid.set) {
74 inode->uid = attributes->uid.set_uint32_u.val;
77 if (attributes->gid.set) {
78 inode->gid = attributes->gid.set_uint32_u.val;
81 if (attributes->size.set) {
82 if (inode->type == BLUESKY_REGULAR) {
83 bluesky_file_truncate(inode, attributes->size.set_uint64_u.val);
88 switch (attributes->atime.set) {
91 case SET_TO_SERVER_TIME:
94 case SET_TO_CLIENT_TIME:
95 inode->atime = decode_nfstime3(&attributes->atime.set_time_u.time);
99 switch (attributes->mtime.set) {
102 case SET_TO_SERVER_TIME:
105 case SET_TO_CLIENT_TIME:
106 inode->mtime = decode_nfstime3(&attributes->mtime.set_time_u.time);
110 bluesky_inode_update_ctime(inode, FALSE);
113 /* Copy inode attributes into NFS response. The BlueSkyInode should be locked
115 void encode_fattr3(struct fattr3 *result, BlueSkyInode *inode)
117 result->type = inode->type;
118 result->mode = inode->mode;
119 result->nlink = inode->nlink;
120 result->uid = inode->uid;
121 result->gid = inode->gid;
122 result->size = inode->size;
124 result->rdev.major = 0;
125 result->rdev.minor = 0;
127 result->fileid = inode->inum;
128 result->atime.seconds = inode->atime / 1000000;
129 result->atime.nseconds = (inode->atime % 1000000) * 1000;
130 result->mtime.seconds = inode->mtime / 1000000;
131 result->mtime.nseconds = (inode->mtime % 1000000) * 1000;
132 result->ctime.seconds = inode->ctime / 1000000;
133 result->ctime.nseconds = (inode->ctime % 1000000) * 1000;
135 switch (inode->type) {
136 case BLUESKY_SYMLINK:
137 result->size = strlen(inode->symlink_contents);
144 void encode_pre_wcc(struct wcc_data *wcc, BlueSkyInode *inode)
146 wcc->before.present = TRUE;
147 wcc->before.pre_op_attr_u.attributes.size = inode->size;
148 wcc->before.pre_op_attr_u.attributes.mtime.seconds = inode->mtime / 1000000;
149 wcc->before.pre_op_attr_u.attributes.mtime.nseconds = (inode->mtime % 1000000) * 1000;
150 wcc->before.pre_op_attr_u.attributes.ctime.seconds = inode->ctime / 1000000;
151 wcc->before.pre_op_attr_u.attributes.ctime.nseconds = (inode->ctime % 1000000) * 1000;
154 void nfsproc3_null_3_svc(void *argp, RPCRequest *req)
156 async_rpc_send_reply(req, NULL);
159 void nfsproc3_getattr_3_svc(nfs_fh3 *argp, RPCRequest *req)
162 memset(&result, 0, sizeof(result));
164 BlueSkyInode *inode = lookup_fh(req, argp);
166 result.status = NFS3_OK;
167 g_mutex_lock(inode->lock);
168 encode_fattr3(&result.getattr3res_u.attributes, inode);
169 g_mutex_unlock(inode->lock);
171 result.status = NFS3ERR_STALE;
174 async_rpc_send_reply(req, &result);
177 void nfsproc3_setattr_3_svc(setattr3args *argp, RPCRequest *req)
180 memset(&result, 0, sizeof(result));
182 result.wccstat3_u.wcc.before.present = FALSE;
183 result.wccstat3_u.wcc.after.present = FALSE;
184 BlueSkyInode *inode = lookup_fh(req, &argp->object);
186 result.status = NFS3ERR_STALE;
187 async_rpc_send_reply(req, &result);
191 g_mutex_lock(inode->lock);
192 encode_pre_wcc(&result.wccstat3_u.wcc, inode);
193 if (argp->guard.check) {
194 if (inode->ctime != decode_nfstime3(&argp->guard.sattrguard3_u.ctime)) {
195 result.status = NFS3ERR_NOT_SYNC;
196 result.wccstat3_u.wcc.after.present = TRUE;
197 encode_fattr3(&result.wccstat3_u.wcc.after.post_op_attr_u.attributes, inode);
198 g_mutex_unlock(inode->lock);
199 async_rpc_send_reply(req, &result);
204 set_attributes(inode, &argp->new_attributes);
206 result.wccstat3_u.wcc.after.present = TRUE;
207 encode_fattr3(&result.wccstat3_u.wcc.after.post_op_attr_u.attributes,
209 result.status = NFS3_OK;
211 bluesky_inode_do_sync(inode);
213 g_mutex_unlock(inode->lock);
214 async_rpc_send_reply(req, &result);
217 void nfsproc3_lookup_3_svc(diropargs3 *argp, RPCRequest *req)
220 memset(&result, 0, sizeof(result));
222 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
224 result.status = NFS3ERR_STALE;
225 result.lookup3res_u.resfail.present = FALSE;
226 async_rpc_send_reply(req, &result);
230 g_mutex_lock(dir->lock);
231 result.lookup3res_u.resfail.present = TRUE;
232 encode_fattr3(&result.lookup3res_u.resfail.post_op_attr_u.attributes, dir);
233 if (!validate_filename(argp->name)) {
234 if (strlen(argp->name) > 255)
235 result.status = NFS3ERR_NAMETOOLONG;
237 result.status = NFS3ERR_NOENT;
238 g_mutex_unlock(dir->lock);
239 async_rpc_send_reply(req, &result);
243 /* TODO: Special-case "." and "..". */
244 uint64_t inum = bluesky_directory_lookup(dir, argp->name);
246 result.status = NFS3ERR_NOENT;
247 g_mutex_unlock(dir->lock);
248 async_rpc_send_reply(req, &result);
252 result.lookup3res_u.resok.dir_attributes.present = TRUE;
253 encode_fattr3(&result.lookup3res_u.resok.dir_attributes.post_op_attr_u.attributes, dir);
254 g_mutex_unlock(dir->lock);
256 BlueSkyInode *inode = bluesky_get_inode(fs, inum);
258 result.status = NFS3ERR_NOENT;
259 async_rpc_send_reply(req, &result);
262 g_mutex_lock(inode->lock);
263 schedule_inode_unref(req, inode);
265 result.status = NFS3_OK;
266 result.lookup3res_u.resok.obj_attributes.present = TRUE;
267 encode_fattr3(&result.lookup3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
270 fh_bytes = GUINT64_TO_BE(inum);
271 result.lookup3res_u.resok.object.data.data_len = 8;
272 result.lookup3res_u.resok.object.data.data_val = (char *)&fh_bytes;
274 g_mutex_unlock(inode->lock);
275 async_rpc_send_reply(req, &result);
278 void nfsproc3_access_3_svc(access3args *argp, RPCRequest *req)
281 memset(&result, 0, sizeof(result));
283 BlueSkyInode *inode = lookup_fh(req, &argp->object);
285 result.status = NFS3ERR_STALE;
286 result.access3res_u.resfail.present = FALSE;
287 async_rpc_send_reply(req, &result);
291 g_mutex_lock(inode->lock);
292 result.status = NFS3_OK;
293 result.access3res_u.resok.obj_attributes.present = TRUE;
294 encode_fattr3(&result.access3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
295 result.access3res_u.resok.access = argp->access;
296 g_mutex_unlock(inode->lock);
298 async_rpc_send_reply(req, &result);
301 void nfsproc3_readlink_3_svc(nfs_fh3 *argp, RPCRequest *req)
304 memset(&result, 0, sizeof(result));
306 BlueSkyInode *inode = lookup_fh(req, argp);
308 g_mutex_lock(inode->lock);
309 if (inode->type == BLUESKY_SYMLINK) {
310 result.status = NFS3_OK;
311 result.readlink3res_u.resok.symlink_attributes.present = TRUE;
312 encode_fattr3(&result.readlink3res_u.resok.symlink_attributes.post_op_attr_u.attributes, inode);
313 result.readlink3res_u.resok.data = inode->symlink_contents;
315 result.status = NFS3ERR_INVAL;
316 result.readlink3res_u.resfail.present = TRUE;
317 encode_fattr3(&result.readlink3res_u.resfail.post_op_attr_u.attributes, inode);
319 g_mutex_unlock(inode->lock);
321 result.status = NFS3ERR_STALE;
324 async_rpc_send_reply(req, &result);
327 void nfsproc3_read_3_svc(read3args *argp, RPCRequest *req)
330 memset(&result, 0, sizeof(result));
331 char buf[NFS_MAXSIZE];
333 bluesky_flushd_invoke_conditional(fs);
335 BlueSkyInode *inode = lookup_fh(req, &argp->file);
337 result.status = NFS3ERR_STALE;
338 result.read3res_u.resfail.present = FALSE;
339 async_rpc_send_reply(req, &result);
343 g_mutex_lock(inode->lock);
345 int count = argp->count;
346 if (argp->offset >= inode->size) {
348 result.read3res_u.resok.eof = TRUE;
350 count = MIN(count, NFS_MAXSIZE);
351 count = MIN(count, inode->size - argp->offset);
352 if (argp->offset + count == inode->size)
353 result.read3res_u.resok.eof = TRUE;
355 result.read3res_u.resok.eof = FALSE;
357 bluesky_file_read(inode, argp->offset, buf, count);
360 result.status = NFS3_OK;
361 result.read3res_u.resok.file_attributes.present = TRUE;
362 encode_fattr3(&result.read3res_u.resok.file_attributes.post_op_attr_u.attributes, inode);
363 result.read3res_u.resok.count = count;
364 result.read3res_u.resok.data.data_val = buf;
365 result.read3res_u.resok.data.data_len = count;
367 g_mutex_unlock(inode->lock);
369 async_rpc_send_reply(req, &result);
372 void nfsproc3_write_3_svc(write3args *argp, RPCRequest *req)
375 memset(&result, 0, sizeof(result));
377 memset(&wcc, 0, sizeof(wcc));
379 bluesky_flushd_invoke_conditional(fs);
381 BlueSkyInode *inode = lookup_fh(req, &argp->file);
383 result.status = NFS3ERR_STALE;
384 result.write3res_u.resfail = wcc;
385 async_rpc_send_reply(req, &result);
390 /* FIXME: Hack to throttle writes when there is too much dirty data still
391 * to be written out. */
392 while (g_atomic_int_get(&fs->cache_dirty) > 4096
393 || g_atomic_int_get(&fs->cache_total) > 8192) {
394 g_print("Too many dirty pages (%d) or total pages (%d); throttling writes...\n",
395 g_atomic_int_get(&fs->cache_dirty),
396 g_atomic_int_get(&fs->cache_total));
397 struct timespec delay;
400 nanosleep(&delay, NULL);
404 g_mutex_lock(inode->lock);
406 encode_pre_wcc(&wcc, inode);
407 if (inode->type != BLUESKY_REGULAR) {
408 result.status = NFS3ERR_INVAL;
409 result.write3res_u.resfail = wcc;
410 g_mutex_unlock(inode->lock);
411 async_rpc_send_reply(req, &result);
415 uint64_t lastbyte = argp->offset + argp->count;
416 if (lastbyte > inode->size) {
417 bluesky_file_truncate(inode, lastbyte);
420 if (argp->data.data_len < argp->count) {
423 bluesky_file_write(inode, argp->offset,
424 argp->data.data_val, argp->count);
427 wcc.after.present = TRUE;
428 encode_fattr3(&wcc.after.post_op_attr_u.attributes, inode);
429 result.write3res_u.resok.file_wcc = wcc;
430 result.write3res_u.resok.count = argp->count;
431 result.write3res_u.resok.committed = FILE_SYNC;
433 bluesky_inode_do_sync(inode);
434 g_mutex_unlock(inode->lock);
436 async_rpc_send_reply(req, &result);
439 void nfsproc3_create_3_svc(create3args *argp, RPCRequest *req)
442 memset(&result, 0, sizeof(result));
444 memset(&wcc, 0, sizeof(wcc));
446 BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
448 result.status = NFS3ERR_STALE;
449 result.diropres3_u.resfail = wcc;
450 async_rpc_send_reply(req, &result);
454 g_mutex_lock(dir->lock);
456 encode_pre_wcc(&wcc, dir);
457 if (dir->type != BLUESKY_DIRECTORY) {
458 result.status = NFS3ERR_NOTDIR;
459 result.diropres3_u.resfail = wcc;
460 g_mutex_unlock(dir->lock);
461 async_rpc_send_reply(req, &result);
465 if (!validate_filename(argp->where.name)
466 || strcmp(argp->where.name, ".") == 0
467 || strcmp(argp->where.name, "..") == 0)
469 result.status = NFS3ERR_EXIST;
470 result.diropres3_u.resfail = wcc;
471 g_mutex_unlock(dir->lock);
472 async_rpc_send_reply(req, &result);
476 g_mutex_lock(fs->lock);
478 file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_REGULAR);
481 int64_t time = bluesky_get_current_time();
486 g_mutex_lock(file->lock);
487 bluesky_insert_inode(fs, file);
488 g_mutex_unlock(fs->lock);
489 bluesky_directory_insert(dir, argp->where.name, file->inum);
491 bluesky_inode_update_ctime(dir, TRUE);
492 bluesky_inode_update_ctime(file, FALSE);
494 wcc.after.present = TRUE;
495 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
496 result.diropres3_u.resok.obj_attributes.present = TRUE;
497 encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
498 result.diropres3_u.resok.dir_wcc = wcc;
501 fh_bytes = GUINT64_TO_BE(file->inum);
502 result.diropres3_u.resok.obj.present = TRUE;
503 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
504 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
506 bluesky_inode_do_sync(file);
507 bluesky_inode_do_sync(dir);
508 g_mutex_unlock(file->lock);
509 g_mutex_unlock(dir->lock);
511 async_rpc_send_reply(req, &result);
514 void nfsproc3_mkdir_3_svc(mkdir3args *argp, RPCRequest *req)
517 memset(&result, 0, sizeof(result));
519 memset(&wcc, 0, sizeof(wcc));
521 BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
523 result.status = NFS3ERR_STALE;
524 result.diropres3_u.resfail = wcc;
525 async_rpc_send_reply(req, &result);
529 g_mutex_lock(dir->lock);
531 encode_pre_wcc(&wcc, dir);
532 if (dir->type != BLUESKY_DIRECTORY) {
533 result.status = NFS3ERR_NOTDIR;
534 result.diropres3_u.resfail = wcc;
535 g_mutex_unlock(dir->lock);
536 async_rpc_send_reply(req, &result);
540 if (!validate_filename(argp->where.name)
541 || strcmp(argp->where.name, ".") == 0
542 || strcmp(argp->where.name, "..") == 0)
544 result.status = NFS3ERR_EXIST;
545 result.diropres3_u.resfail = wcc;
546 g_mutex_unlock(dir->lock);
547 async_rpc_send_reply(req, &result);
551 g_mutex_lock(fs->lock);
553 file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_DIRECTORY);
556 int64_t time = bluesky_get_current_time();
561 g_mutex_lock(file->lock);
562 bluesky_insert_inode(fs, file);
563 g_mutex_unlock(fs->lock);
564 bluesky_directory_insert(dir, argp->where.name, file->inum);
565 set_attributes(file, &argp->attributes);
567 bluesky_inode_update_ctime(dir, TRUE);
568 bluesky_inode_update_ctime(file, FALSE);
570 wcc.after.present = TRUE;
571 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
572 result.diropres3_u.resok.obj_attributes.present = TRUE;
573 encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
574 result.diropres3_u.resok.dir_wcc = wcc;
577 fh_bytes = GUINT64_TO_BE(file->inum);
578 result.diropres3_u.resok.obj.present = TRUE;
579 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
580 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
582 bluesky_inode_do_sync(file);
583 bluesky_inode_do_sync(dir);
584 g_mutex_unlock(file->lock);
585 g_mutex_unlock(dir->lock);
586 async_rpc_send_reply(req, &result);
589 void nfsproc3_symlink_3_svc(symlink3args *argp, RPCRequest *req)
592 memset(&result, 0, sizeof(result));
594 memset(&wcc, 0, sizeof(wcc));
596 BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
598 result.status = NFS3ERR_STALE;
599 result.diropres3_u.resfail = wcc;
600 async_rpc_send_reply(req, &result);
603 g_mutex_lock(dir->lock);
605 encode_pre_wcc(&wcc, dir);
606 if (dir->type != BLUESKY_DIRECTORY) {
607 result.status = NFS3ERR_NOTDIR;
608 result.diropres3_u.resfail = wcc;
609 g_mutex_unlock(dir->lock);
610 async_rpc_send_reply(req, &result);
614 if (!validate_filename(argp->where.name)
615 || strcmp(argp->where.name, ".") == 0
616 || strcmp(argp->where.name, "..") == 0)
618 result.status = NFS3ERR_EXIST;
619 result.diropres3_u.resfail = wcc;
620 g_mutex_unlock(dir->lock);
621 async_rpc_send_reply(req, &result);
625 g_mutex_lock(fs->lock);
627 file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_SYMLINK);
630 int64_t time = bluesky_get_current_time();
635 file->symlink_contents = g_strdup(argp->symlink.symlink_data);
636 g_mutex_lock(file->lock);
637 bluesky_insert_inode(fs, file);
638 g_mutex_unlock(fs->lock);
639 bluesky_directory_insert(dir, argp->where.name, file->inum);
641 bluesky_inode_update_ctime(dir, TRUE);
642 bluesky_inode_update_ctime(file, FALSE);
644 wcc.after.present = TRUE;
645 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
646 result.diropres3_u.resok.obj_attributes.present = TRUE;
647 encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
648 result.diropres3_u.resok.dir_wcc = wcc;
651 fh_bytes = GUINT64_TO_BE(file->inum);
652 result.diropres3_u.resok.obj.present = TRUE;
653 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
654 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
656 bluesky_inode_do_sync(file);
657 bluesky_inode_do_sync(dir);
658 g_mutex_unlock(file->lock);
659 g_mutex_unlock(dir->lock);
660 async_rpc_send_reply(req, &result);
663 void nfsproc3_mknod_3_svc(mknod3args *argp, RPCRequest *req)
666 memset(&result, 0, sizeof(result));
668 result.status = NFS3ERR_NOTSUPP;
670 async_rpc_send_reply(req, &result);
673 void nfsproc3_remove_3_svc(diropargs3 *argp, RPCRequest *req)
676 memset(&result, 0, sizeof(result));
678 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
680 result.status = NFS3ERR_STALE;
681 async_rpc_send_reply(req, &result);
685 g_mutex_lock(dir->lock);
687 encode_pre_wcc(&result.wccstat3_u.wcc, dir);
689 if (!validate_filename(argp->name)
690 || strcmp(argp->name, ".") == 0
691 || strcmp(argp->name, "..") == 0)
693 result.status = NFS3ERR_NOENT;
694 g_mutex_unlock(dir->lock);
695 async_rpc_send_reply(req, &result);
699 /* TODO: Decrement link count, deallocate inode if needed. */
701 bluesky_directory_remove(dir, argp->name);
703 result.status = NFS3_OK;
704 result.wccstat3_u.wcc.after.present = TRUE;
705 encode_fattr3(&result.wccstat3_u.wcc.after.post_op_attr_u.attributes,
708 bluesky_inode_do_sync(dir);
709 g_mutex_unlock(dir->lock);
710 async_rpc_send_reply(req, &result);
713 void nfsproc3_rmdir_3_svc(diropargs3 *argp, RPCRequest *req)
716 memset(&result, 0, sizeof(result));
718 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
720 result.status = NFS3ERR_STALE;
721 async_rpc_send_reply(req, &result);
725 g_mutex_lock(dir->lock);
727 encode_pre_wcc(&result.wccstat3_u.wcc, dir);
729 if (!validate_filename(argp->name)
730 || strcmp(argp->name, ".") == 0
731 || strcmp(argp->name, "..") == 0)
733 result.status = NFS3ERR_NOENT;
734 g_mutex_unlock(dir->lock);
735 async_rpc_send_reply(req, &result);
739 uint64_t inum = bluesky_directory_lookup(dir, argp->name);
740 BlueSkyInode *inode = bluesky_get_inode(fs, inum);
742 result.status = NFS3ERR_NOENT;
743 g_mutex_unlock(dir->lock);
744 async_rpc_send_reply(req, &result);
747 g_mutex_lock(inode->lock);
748 schedule_inode_unref(req, inode);
750 if (inode->type != BLUESKY_DIRECTORY) {
751 result.status = NFS3ERR_NOTDIR;
752 g_mutex_unlock(inode->lock);
753 g_mutex_unlock(dir->lock);
754 async_rpc_send_reply(req, &result);
757 if (g_sequence_get_length(inode->dirents) > 0) {
758 printf("Directory not empty: %d entries\n",
759 g_sequence_get_length(inode->dirents));
760 result.status = NFS3ERR_NOTEMPTY;
761 g_mutex_unlock(inode->lock);
762 g_mutex_unlock(dir->lock);
763 async_rpc_send_reply(req, &result);
767 /* TODO: Decrement link count, deallocate inode if needed. */
769 bluesky_directory_remove(dir, argp->name);
771 result.status = NFS3_OK;
772 result.wccstat3_u.wcc.after.present = TRUE;
773 encode_fattr3(&result.wccstat3_u.wcc.after.post_op_attr_u.attributes,
776 bluesky_inode_do_sync(dir);
777 bluesky_inode_do_sync(inode);
778 g_mutex_unlock(inode->lock);
779 g_mutex_unlock(dir->lock);
780 async_rpc_send_reply(req, &result);
783 void nfsproc3_rename_3_svc(rename3args *argp, RPCRequest *req)
786 memset(&result, 0, sizeof(result));
787 wcc_data *wcc1 = &result.rename3res_u.res.fromdir_wcc;
788 wcc_data *wcc2 = &result.rename3res_u.res.todir_wcc;
790 BlueSkyInode *dir1 = lookup_fh(req, &argp->from.dir);
792 result.status = NFS3ERR_STALE;
793 async_rpc_send_reply(req, &result);
797 BlueSkyInode *dir2 = lookup_fh(req, &argp->to.dir);
799 result.status = NFS3ERR_STALE;
800 async_rpc_send_reply(req, &result);
804 if (dir1->inum < dir2->inum) {
805 g_mutex_lock(dir1->lock);
806 g_mutex_lock(dir2->lock);
807 } else if (dir1->inum > dir2->inum) {
808 g_mutex_lock(dir2->lock);
809 g_mutex_lock(dir1->lock);
811 encode_pre_wcc(wcc1, dir1);
812 encode_pre_wcc(wcc2, dir1);
814 gboolean status = bluesky_rename(dir1, argp->from.name,
818 wcc1->after.present = TRUE;
819 encode_fattr3(&wcc1->after.post_op_attr_u.attributes, dir1);
820 wcc2->after.present = TRUE;
821 encode_fattr3(&wcc2->after.post_op_attr_u.attributes, dir2);
823 result.status = NFS3_OK;
825 result.status = NFS3ERR_PERM;
827 bluesky_inode_do_sync(dir2);
828 bluesky_inode_do_sync(dir1);
830 g_mutex_unlock(dir1->lock);
831 if (dir1->inum != dir2->inum)
832 g_mutex_unlock(dir2->lock);
833 async_rpc_send_reply(req, &result);
836 void nfsproc3_link_3_svc(link3args *argp, RPCRequest *req)
839 memset(&result, 0, sizeof(result));
841 memset(&wcc, 0, sizeof(wcc));
843 BlueSkyInode *inode = lookup_fh(req, &argp->file);
845 result.status = NFS3ERR_STALE;
846 result.link3res_u.res.linkdir_wcc = wcc;
847 async_rpc_send_reply(req, &result);
850 g_mutex_lock(inode->lock);
852 BlueSkyInode *dir = lookup_fh(req, &argp->link.dir);
854 result.status = NFS3ERR_STALE;
855 result.link3res_u.res.linkdir_wcc = wcc;
856 g_mutex_unlock(inode->lock);
857 async_rpc_send_reply(req, &result);
860 g_mutex_lock(dir->lock);
862 encode_pre_wcc(&wcc, dir);
863 if (dir->type != BLUESKY_DIRECTORY) {
864 result.status = NFS3ERR_NOTDIR;
865 result.link3res_u.res.linkdir_wcc = wcc;
866 g_mutex_unlock(inode->lock);
867 g_mutex_unlock(dir->lock);
868 async_rpc_send_reply(req, &result);
872 if (!validate_filename(argp->link.name)
873 || strcmp(argp->link.name, ".") == 0
874 || strcmp(argp->link.name, "..") == 0
875 || bluesky_directory_lookup(dir, argp->link.name) != 0)
877 result.status = NFS3ERR_EXIST;
878 result.link3res_u.res.linkdir_wcc = wcc;
879 g_mutex_unlock(inode->lock);
880 g_mutex_unlock(dir->lock);
881 async_rpc_send_reply(req, &result);
885 if (!bluesky_directory_insert(dir, argp->link.name, inode->inum)) {
886 result.status = NFS3ERR_EXIST;
887 result.link3res_u.res.linkdir_wcc = wcc;
888 g_mutex_unlock(inode->lock);
889 g_mutex_unlock(dir->lock);
890 async_rpc_send_reply(req, &result);
894 bluesky_inode_update_ctime(inode, FALSE);
895 bluesky_inode_update_ctime(dir, TRUE);
897 result.status = NFS3_OK;
898 wcc.after.present = TRUE;
899 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
900 result.link3res_u.res.file_attributes.present = TRUE;
901 encode_fattr3(&result.link3res_u.res.file_attributes.post_op_attr_u.attributes, inode);
902 result.link3res_u.res.linkdir_wcc = wcc;
904 bluesky_inode_do_sync(inode);
905 bluesky_inode_do_sync(dir);
906 g_mutex_unlock(inode->lock);
907 g_mutex_unlock(dir->lock);
908 async_rpc_send_reply(req, &result);
911 gint bluesky_dirent_compare(gconstpointer a, gconstpointer b,
914 #define MAX_READDIR_DIRENTS 64
915 void nfsproc3_readdir_3_svc(readdir3args *argp, RPCRequest *req)
918 memset(&result, 0, sizeof(result));
920 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
922 result.status = NFS3ERR_STALE;
923 result.readdir3res_u.resfail.present = FALSE;
924 async_rpc_send_reply(req, &result);
927 g_mutex_lock(dir->lock);
929 result.status = NFS3_OK;
930 result.readdir3res_u.resok.dir_attributes.present = TRUE;
931 encode_fattr3(&result.readdir3res_u.resok.dir_attributes.post_op_attr_u.attributes, dir);
932 memset(result.readdir3res_u.resok.cookieverf, 0,
933 sizeof(result.readdir3res_u.resok.cookieverf));
935 entry3 dirents[MAX_READDIR_DIRENTS];
938 BlueSkyDirent start = {NULL, NULL, argp->cookie, 0};
939 GSequenceIter *i = g_sequence_search(dir->dirents, &start,
940 bluesky_dirent_compare, NULL);
942 while (count < MAX_READDIR_DIRENTS && !g_sequence_iter_is_end(i)) {
943 BlueSkyDirent *d = g_sequence_get(i);
944 dirents[count].fileid = d->inum;
945 dirents[count].name = d->name;
946 dirents[count].cookie = d->cookie;
947 dirents[count].nextentry = NULL;
949 dirents[count - 1].nextentry = &dirents[count];
950 i = g_sequence_iter_next(i);
955 result.readdir3res_u.resok.reply.entries = &dirents[0];
957 result.readdir3res_u.resok.reply.entries = NULL;
958 result.readdir3res_u.resok.reply.eof = g_sequence_iter_is_end(i);
960 g_mutex_unlock(dir->lock);
961 async_rpc_send_reply(req, &result);
964 void nfsproc3_readdirplus_3_svc(readdirplus3args *argp, RPCRequest *req)
966 /* XDR-encoded sizes:
967 * post_op_attr: 88 bytes
968 * base readdirplus3resok: 88 + 16 bytes
969 * base directory entry: 24 bytes + filename
970 * attributes/fh3: 88 + 8 + filehandle size
972 size_t dircount = 88 + 16, attrcount = 0;
973 readdirplus3res result;
974 memset(&result, 0, sizeof(result));
976 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
978 result.status = NFS3ERR_STALE;
979 result.readdirplus3res_u.resfail.present = FALSE;
980 async_rpc_send_reply(req, &result);
983 g_mutex_lock(dir->lock);
985 result.status = NFS3_OK;
986 result.readdirplus3res_u.resok.dir_attributes.present = TRUE;
987 encode_fattr3(&result.readdirplus3res_u.resok.dir_attributes.post_op_attr_u.attributes, dir);
988 memset(result.readdirplus3res_u.resok.cookieverf, 0,
989 sizeof(result.readdirplus3res_u.resok.cookieverf));
991 entryplus3 dirents[MAX_READDIR_DIRENTS];
992 uint64_t fh_bytes[MAX_READDIR_DIRENTS];
996 BlueSkyDirent start = {NULL, NULL, argp->cookie, 0};
998 /* Perform a prefetch pass on inodes: for all the inodes we think we will
999 * return information about, try to load each one but don't wait. This
1000 * should let multiple inodes be fetched in parallel, instead of
1001 * sequentially in the loop that follows. */
1002 i = g_sequence_search(dir->dirents, &start, bluesky_dirent_compare, NULL);
1003 while (count < MAX_READDIR_DIRENTS
1004 && !g_sequence_iter_is_end(i)
1005 && dircount <= argp->dircount
1006 && dircount + attrcount <= argp->maxcount)
1008 BlueSkyDirent *d = g_sequence_get(i);
1009 BlueSkyInode *inode = bluesky_get_inode(fs, d->inum);
1011 bluesky_inode_unref(inode);
1012 dircount += 24 + ((strlen(d->name) + 3) & ~3);
1013 attrcount += 88 + 8 + 8;
1014 i = g_sequence_iter_next(i);
1017 i = g_sequence_search(dir->dirents, &start, bluesky_dirent_compare, NULL);
1021 while (count < MAX_READDIR_DIRENTS && !g_sequence_iter_is_end(i)) {
1022 BlueSkyDirent *d = g_sequence_get(i);
1023 BlueSkyInode *inode = bluesky_get_inode(fs, d->inum);
1024 if (inode != NULL) {
1025 g_mutex_lock(inode->lock);
1026 dircount += 24 + ((strlen(d->name) + 3) & ~3);
1027 attrcount += 88 + 8 + 8;
1028 if (dircount > argp->dircount
1029 || dircount + attrcount > argp->maxcount)
1031 g_mutex_unlock(inode->lock);
1032 bluesky_inode_unref(inode);
1035 dirents[count].fileid = d->inum;
1036 dirents[count].name = d->name;
1037 dirents[count].cookie = d->cookie;
1038 dirents[count].nextentry = NULL;
1039 dirents[count].name_attributes.present = TRUE;
1040 encode_fattr3(&dirents[count].name_attributes.post_op_attr_u.attributes, inode);
1041 fh_bytes[count] = GUINT64_TO_BE(d->inum);
1042 dirents[count].name_handle.present = TRUE;
1043 dirents[count].name_handle.post_op_fh3_u.handle.data.data_len = 8;
1044 dirents[count].name_handle.post_op_fh3_u.handle.data.data_val
1045 = (char *)&fh_bytes[count];
1047 dirents[count - 1].nextentry = &dirents[count];
1049 g_mutex_unlock(inode->lock);
1050 bluesky_inode_unref(inode);
1052 i = g_sequence_iter_next(i);
1056 result.readdirplus3res_u.resok.reply.entries = &dirents[0];
1058 result.readdirplus3res_u.resok.reply.entries = NULL;
1059 result.readdirplus3res_u.resok.reply.eof = g_sequence_iter_is_end(i);
1061 g_mutex_unlock(dir->lock);
1062 async_rpc_send_reply(req, &result);
1065 void nfsproc3_fsstat_3_svc(nfs_fh3 *argp, RPCRequest *req)
1068 memset(&result, 0, sizeof(result));
1070 BlueSkyInode *inode = lookup_fh(req, argp);
1071 if (inode == NULL) {
1072 result.status = NFS3ERR_STALE;
1073 result.fsstat3res_u.resfail.present = FALSE;
1074 async_rpc_send_reply(req, &result);
1077 g_mutex_lock(inode->lock);
1079 result.status = NFS3_OK;
1080 result.fsstat3res_u.resok.obj_attributes.present = TRUE;
1081 encode_fattr3(&result.fsstat3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
1083 result.fsstat3res_u.resok.tbytes = (1 << 30);
1084 result.fsstat3res_u.resok.fbytes = (1 << 30);
1085 result.fsstat3res_u.resok.abytes = (1 << 30);
1086 result.fsstat3res_u.resok.tfiles = 0;
1087 result.fsstat3res_u.resok.ffiles = 0;
1088 result.fsstat3res_u.resok.afiles = 0;
1089 result.fsstat3res_u.resok.invarsec = 0;
1091 g_mutex_unlock(inode->lock);
1092 async_rpc_send_reply(req, &result);
1095 void nfsproc3_fsinfo_3_svc(nfs_fh3 *argp, RPCRequest *req)
1098 memset(&result, 0, sizeof(result));
1100 BlueSkyInode *inode = bluesky_get_inode(fs, 1);
1101 g_mutex_lock(inode->lock);
1102 result.status = NFS3_OK;
1103 result.fsinfo3res_u.resok.obj_attributes.present = TRUE;
1104 encode_fattr3(&result.fsinfo3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
1105 result.fsinfo3res_u.resok.rtmax = NFS_MAXSIZE;
1106 result.fsinfo3res_u.resok.rtpref = NFS_MAXSIZE;
1107 result.fsinfo3res_u.resok.rtmult = NFS_BLOCKSIZE;
1108 result.fsinfo3res_u.resok.wtmax = NFS_MAXSIZE;
1109 result.fsinfo3res_u.resok.wtpref = NFS_MAXSIZE;
1110 result.fsinfo3res_u.resok.wtmult = NFS_BLOCKSIZE;
1111 result.fsinfo3res_u.resok.dtpref = NFS_BLOCKSIZE;
1112 result.fsinfo3res_u.resok.maxfilesize = 0x7fffffffffffffffULL;
1113 result.fsinfo3res_u.resok.time_delta.seconds = 0;
1114 result.fsinfo3res_u.resok.time_delta.nseconds = 1000;
1115 result.fsinfo3res_u.resok.properties
1116 = FSF3_LINK | FSF3_SYMLINK | FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
1118 g_mutex_unlock(inode->lock);
1119 bluesky_inode_unref(inode);
1120 async_rpc_send_reply(req, &result);
1123 void nfsproc3_pathconf_3_svc(nfs_fh3 *argp, RPCRequest *req)
1125 pathconf3res result;
1126 memset(&result, 0, sizeof(result));
1128 BlueSkyInode *inode = bluesky_get_inode(fs, 1);
1129 g_mutex_lock(inode->lock);
1130 result.status = NFS3_OK;
1131 result.pathconf3res_u.resok.obj_attributes.present = TRUE;
1132 encode_fattr3(&result.pathconf3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
1133 result.pathconf3res_u.resok.linkmax = 0xffffffff;
1134 result.pathconf3res_u.resok.name_max = 255;
1135 result.pathconf3res_u.resok.no_trunc = TRUE;
1136 result.pathconf3res_u.resok.chown_restricted = TRUE;
1137 result.pathconf3res_u.resok.case_insensitive = FALSE;
1138 result.pathconf3res_u.resok.case_preserving = TRUE;
1140 g_mutex_unlock(inode->lock);
1141 bluesky_inode_unref(inode);
1142 async_rpc_send_reply(req, &result);
1145 void nfsproc3_commit_3_svc(commit3args *argp, RPCRequest *req)
1148 memset(&result, 0, sizeof(result));
1150 result.status = NFS3_OK;
1152 BlueSkyInode *inode = lookup_fh(req, &argp->file);
1153 if (inode == NULL) {
1154 result.status = NFS3ERR_STALE;
1155 async_rpc_send_reply(req, &result);
1159 g_mutex_lock(inode->lock);
1160 encode_pre_wcc(&result.commit3res_u.resok.file_wcc, inode);
1162 bluesky_inode_do_sync(inode);
1164 result.commit3res_u.resok.file_wcc.after.present = TRUE;
1165 encode_fattr3(&result.commit3res_u.resok.file_wcc.after.post_op_attr_u.attributes, inode);
1167 g_mutex_unlock(inode->lock);
1169 async_rpc_send_reply(req, &result);