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 g_mutex_unlock(inode->lock);
212 async_rpc_send_reply(req, &result);
215 void nfsproc3_lookup_3_svc(diropargs3 *argp, RPCRequest *req)
218 memset(&result, 0, sizeof(result));
220 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
222 result.status = NFS3ERR_STALE;
223 result.lookup3res_u.resfail.present = FALSE;
224 async_rpc_send_reply(req, &result);
228 g_mutex_lock(dir->lock);
229 result.lookup3res_u.resfail.present = TRUE;
230 encode_fattr3(&result.lookup3res_u.resfail.post_op_attr_u.attributes, dir);
231 if (!validate_filename(argp->name)) {
232 if (strlen(argp->name) > 255)
233 result.status = NFS3ERR_NAMETOOLONG;
235 result.status = NFS3ERR_NOENT;
236 g_mutex_unlock(dir->lock);
237 async_rpc_send_reply(req, &result);
241 /* TODO: Special-case "." and "..". */
242 uint64_t inum = bluesky_directory_lookup(dir, argp->name);
244 result.status = NFS3ERR_NOENT;
245 g_mutex_unlock(dir->lock);
246 async_rpc_send_reply(req, &result);
250 result.lookup3res_u.resok.dir_attributes.present = TRUE;
251 encode_fattr3(&result.lookup3res_u.resok.dir_attributes.post_op_attr_u.attributes, dir);
252 g_mutex_unlock(dir->lock);
254 BlueSkyInode *inode = bluesky_get_inode(fs, inum);
256 result.status = NFS3ERR_NOENT;
257 async_rpc_send_reply(req, &result);
260 g_mutex_lock(inode->lock);
261 schedule_inode_unref(req, inode);
263 result.status = NFS3_OK;
264 result.lookup3res_u.resok.obj_attributes.present = TRUE;
265 encode_fattr3(&result.lookup3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
268 fh_bytes = GUINT64_TO_BE(inum);
269 result.lookup3res_u.resok.object.data.data_len = 8;
270 result.lookup3res_u.resok.object.data.data_val = (char *)&fh_bytes;
272 g_mutex_unlock(inode->lock);
273 async_rpc_send_reply(req, &result);
276 void nfsproc3_access_3_svc(access3args *argp, RPCRequest *req)
279 memset(&result, 0, sizeof(result));
281 BlueSkyInode *inode = lookup_fh(req, &argp->object);
283 result.status = NFS3ERR_STALE;
284 result.access3res_u.resfail.present = FALSE;
285 async_rpc_send_reply(req, &result);
289 g_mutex_lock(inode->lock);
290 result.status = NFS3_OK;
291 result.access3res_u.resok.obj_attributes.present = TRUE;
292 encode_fattr3(&result.access3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
293 result.access3res_u.resok.access = argp->access;
294 g_mutex_unlock(inode->lock);
296 async_rpc_send_reply(req, &result);
299 void nfsproc3_readlink_3_svc(nfs_fh3 *argp, RPCRequest *req)
302 memset(&result, 0, sizeof(result));
304 BlueSkyInode *inode = lookup_fh(req, argp);
306 g_mutex_lock(inode->lock);
307 if (inode->type == BLUESKY_SYMLINK) {
308 result.status = NFS3_OK;
309 result.readlink3res_u.resok.symlink_attributes.present = TRUE;
310 encode_fattr3(&result.readlink3res_u.resok.symlink_attributes.post_op_attr_u.attributes, inode);
311 result.readlink3res_u.resok.data = inode->symlink_contents;
313 result.status = NFS3ERR_INVAL;
314 result.readlink3res_u.resfail.present = TRUE;
315 encode_fattr3(&result.readlink3res_u.resfail.post_op_attr_u.attributes, inode);
317 g_mutex_unlock(inode->lock);
319 result.status = NFS3ERR_STALE;
322 async_rpc_send_reply(req, &result);
325 void nfsproc3_read_3_svc(read3args *argp, RPCRequest *req)
328 memset(&result, 0, sizeof(result));
329 char buf[NFS_MAXSIZE];
331 bluesky_flushd_invoke_conditional(fs);
333 BlueSkyInode *inode = lookup_fh(req, &argp->file);
335 result.status = NFS3ERR_STALE;
336 result.read3res_u.resfail.present = FALSE;
337 async_rpc_send_reply(req, &result);
341 g_mutex_lock(inode->lock);
343 int count = argp->count;
344 if (argp->offset >= inode->size) {
346 result.read3res_u.resok.eof = TRUE;
348 count = MIN(count, NFS_MAXSIZE);
349 count = MIN(count, inode->size - argp->offset);
350 if (argp->offset + count == inode->size)
351 result.read3res_u.resok.eof = TRUE;
353 result.read3res_u.resok.eof = FALSE;
355 bluesky_file_read(inode, argp->offset, buf, count);
358 result.status = NFS3_OK;
359 result.read3res_u.resok.file_attributes.present = TRUE;
360 encode_fattr3(&result.read3res_u.resok.file_attributes.post_op_attr_u.attributes, inode);
361 result.read3res_u.resok.count = count;
362 result.read3res_u.resok.data.data_val = buf;
363 result.read3res_u.resok.data.data_len = count;
365 g_mutex_unlock(inode->lock);
367 async_rpc_send_reply(req, &result);
370 void nfsproc3_write_3_svc(write3args *argp, RPCRequest *req)
373 memset(&result, 0, sizeof(result));
375 memset(&wcc, 0, sizeof(wcc));
377 bluesky_flushd_invoke_conditional(fs);
379 BlueSkyInode *inode = lookup_fh(req, &argp->file);
381 result.status = NFS3ERR_STALE;
382 result.write3res_u.resfail = wcc;
383 async_rpc_send_reply(req, &result);
388 /* FIXME: Hack to throttle writes when there is too much dirty data still
389 * to be written out. */
390 while (g_atomic_int_get(&fs->cache_dirty) > 4096
391 || g_atomic_int_get(&fs->cache_total) > 8192) {
392 g_print("Too many dirty pages (%d) or total pages (%d); throttling writes...\n",
393 g_atomic_int_get(&fs->cache_dirty),
394 g_atomic_int_get(&fs->cache_total));
395 struct timespec delay;
398 nanosleep(&delay, NULL);
402 g_mutex_lock(inode->lock);
404 encode_pre_wcc(&wcc, inode);
405 if (inode->type != BLUESKY_REGULAR) {
406 result.status = NFS3ERR_INVAL;
407 result.write3res_u.resfail = wcc;
408 g_mutex_unlock(inode->lock);
409 async_rpc_send_reply(req, &result);
413 uint64_t lastbyte = argp->offset + argp->count;
414 if (lastbyte > inode->size) {
415 bluesky_file_truncate(inode, lastbyte);
418 if (argp->data.data_len < argp->count) {
421 bluesky_file_write(inode, argp->offset,
422 argp->data.data_val, argp->count);
425 wcc.after.present = TRUE;
426 encode_fattr3(&wcc.after.post_op_attr_u.attributes, inode);
427 result.write3res_u.resok.file_wcc = wcc;
428 result.write3res_u.resok.count = argp->count;
429 result.write3res_u.resok.committed = FILE_SYNC;
431 g_mutex_unlock(inode->lock);
433 async_rpc_send_reply(req, &result);
436 void nfsproc3_create_3_svc(create3args *argp, RPCRequest *req)
439 memset(&result, 0, sizeof(result));
441 memset(&wcc, 0, sizeof(wcc));
443 BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
445 result.status = NFS3ERR_STALE;
446 result.diropres3_u.resfail = wcc;
447 async_rpc_send_reply(req, &result);
451 g_mutex_lock(dir->lock);
453 encode_pre_wcc(&wcc, dir);
454 if (dir->type != BLUESKY_DIRECTORY) {
455 result.status = NFS3ERR_NOTDIR;
456 result.diropres3_u.resfail = wcc;
457 g_mutex_unlock(dir->lock);
458 async_rpc_send_reply(req, &result);
462 if (!validate_filename(argp->where.name)
463 || strcmp(argp->where.name, ".") == 0
464 || strcmp(argp->where.name, "..") == 0)
466 result.status = NFS3ERR_EXIST;
467 result.diropres3_u.resfail = wcc;
468 g_mutex_unlock(dir->lock);
469 async_rpc_send_reply(req, &result);
473 g_mutex_lock(fs->lock);
475 file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_REGULAR);
478 int64_t time = bluesky_get_current_time();
483 g_mutex_lock(file->lock);
484 bluesky_insert_inode(fs, file);
485 g_mutex_unlock(fs->lock);
486 bluesky_directory_insert(dir, argp->where.name, file->inum);
488 bluesky_inode_update_ctime(dir, TRUE);
490 wcc.after.present = TRUE;
491 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
492 result.diropres3_u.resok.obj_attributes.present = TRUE;
493 encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
494 result.diropres3_u.resok.dir_wcc = wcc;
497 fh_bytes = GUINT64_TO_BE(file->inum);
498 result.diropres3_u.resok.obj.present = TRUE;
499 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
500 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
502 g_mutex_unlock(file->lock);
503 g_mutex_unlock(dir->lock);
505 async_rpc_send_reply(req, &result);
508 void nfsproc3_mkdir_3_svc(mkdir3args *argp, RPCRequest *req)
511 memset(&result, 0, sizeof(result));
513 memset(&wcc, 0, sizeof(wcc));
515 BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
517 result.status = NFS3ERR_STALE;
518 result.diropres3_u.resfail = wcc;
519 async_rpc_send_reply(req, &result);
523 g_mutex_lock(dir->lock);
525 encode_pre_wcc(&wcc, dir);
526 if (dir->type != BLUESKY_DIRECTORY) {
527 result.status = NFS3ERR_NOTDIR;
528 result.diropres3_u.resfail = wcc;
529 g_mutex_unlock(dir->lock);
530 async_rpc_send_reply(req, &result);
534 if (!validate_filename(argp->where.name)
535 || strcmp(argp->where.name, ".") == 0
536 || strcmp(argp->where.name, "..") == 0)
538 result.status = NFS3ERR_EXIST;
539 result.diropres3_u.resfail = wcc;
540 g_mutex_unlock(dir->lock);
541 async_rpc_send_reply(req, &result);
545 g_mutex_lock(fs->lock);
547 file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_DIRECTORY);
550 int64_t time = bluesky_get_current_time();
555 g_mutex_lock(file->lock);
556 bluesky_insert_inode(fs, file);
557 g_mutex_unlock(fs->lock);
558 bluesky_directory_insert(dir, argp->where.name, file->inum);
559 set_attributes(file, &argp->attributes);
561 bluesky_inode_update_ctime(dir, TRUE);
563 wcc.after.present = TRUE;
564 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
565 result.diropres3_u.resok.obj_attributes.present = TRUE;
566 encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
567 result.diropres3_u.resok.dir_wcc = wcc;
570 fh_bytes = GUINT64_TO_BE(file->inum);
571 result.diropres3_u.resok.obj.present = TRUE;
572 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
573 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
575 g_mutex_unlock(file->lock);
576 g_mutex_unlock(dir->lock);
577 async_rpc_send_reply(req, &result);
580 void nfsproc3_symlink_3_svc(symlink3args *argp, RPCRequest *req)
583 memset(&result, 0, sizeof(result));
585 memset(&wcc, 0, sizeof(wcc));
587 BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
589 result.status = NFS3ERR_STALE;
590 result.diropres3_u.resfail = wcc;
591 async_rpc_send_reply(req, &result);
594 g_mutex_lock(dir->lock);
596 encode_pre_wcc(&wcc, dir);
597 if (dir->type != BLUESKY_DIRECTORY) {
598 result.status = NFS3ERR_NOTDIR;
599 result.diropres3_u.resfail = wcc;
600 g_mutex_unlock(dir->lock);
601 async_rpc_send_reply(req, &result);
605 if (!validate_filename(argp->where.name)
606 || strcmp(argp->where.name, ".") == 0
607 || strcmp(argp->where.name, "..") == 0)
609 result.status = NFS3ERR_EXIST;
610 result.diropres3_u.resfail = wcc;
611 g_mutex_unlock(dir->lock);
612 async_rpc_send_reply(req, &result);
616 g_mutex_lock(fs->lock);
618 file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_SYMLINK);
621 int64_t time = bluesky_get_current_time();
626 file->symlink_contents = g_strdup(argp->symlink.symlink_data);
627 g_mutex_lock(file->lock);
628 bluesky_insert_inode(fs, file);
629 g_mutex_unlock(fs->lock);
630 bluesky_directory_insert(dir, argp->where.name, file->inum);
632 bluesky_inode_update_ctime(dir, TRUE);
634 wcc.after.present = TRUE;
635 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
636 result.diropres3_u.resok.obj_attributes.present = TRUE;
637 encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
638 result.diropres3_u.resok.dir_wcc = wcc;
641 fh_bytes = GUINT64_TO_BE(file->inum);
642 result.diropres3_u.resok.obj.present = TRUE;
643 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
644 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
646 g_mutex_unlock(file->lock);
647 g_mutex_unlock(dir->lock);
648 async_rpc_send_reply(req, &result);
651 void nfsproc3_mknod_3_svc(mknod3args *argp, RPCRequest *req)
654 memset(&result, 0, sizeof(result));
656 result.status = NFS3ERR_NOTSUPP;
658 async_rpc_send_reply(req, &result);
661 void nfsproc3_remove_3_svc(diropargs3 *argp, RPCRequest *req)
664 memset(&result, 0, sizeof(result));
666 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
668 result.status = NFS3ERR_STALE;
669 async_rpc_send_reply(req, &result);
673 g_mutex_lock(dir->lock);
675 encode_pre_wcc(&result.wccstat3_u.wcc, dir);
677 if (!validate_filename(argp->name)
678 || strcmp(argp->name, ".") == 0
679 || strcmp(argp->name, "..") == 0)
681 result.status = NFS3ERR_NOENT;
682 g_mutex_unlock(dir->lock);
683 async_rpc_send_reply(req, &result);
687 /* TODO: Decrement link count, deallocate inode if needed. */
689 bluesky_directory_remove(dir, argp->name);
691 result.status = NFS3_OK;
692 result.wccstat3_u.wcc.after.present = TRUE;
693 encode_fattr3(&result.wccstat3_u.wcc.after.post_op_attr_u.attributes,
696 g_mutex_unlock(dir->lock);
697 async_rpc_send_reply(req, &result);
700 void nfsproc3_rmdir_3_svc(diropargs3 *argp, RPCRequest *req)
703 memset(&result, 0, sizeof(result));
705 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
707 result.status = NFS3ERR_STALE;
708 async_rpc_send_reply(req, &result);
712 g_mutex_lock(dir->lock);
714 encode_pre_wcc(&result.wccstat3_u.wcc, dir);
716 if (!validate_filename(argp->name)
717 || strcmp(argp->name, ".") == 0
718 || strcmp(argp->name, "..") == 0)
720 result.status = NFS3ERR_NOENT;
721 g_mutex_unlock(dir->lock);
722 async_rpc_send_reply(req, &result);
726 uint64_t inum = bluesky_directory_lookup(dir, argp->name);
727 BlueSkyInode *inode = bluesky_get_inode(fs, inum);
729 result.status = NFS3ERR_NOENT;
730 g_mutex_unlock(dir->lock);
731 async_rpc_send_reply(req, &result);
734 g_mutex_lock(inode->lock);
735 schedule_inode_unref(req, inode);
737 if (inode->type != BLUESKY_DIRECTORY) {
738 result.status = NFS3ERR_NOTDIR;
739 g_mutex_unlock(inode->lock);
740 g_mutex_unlock(dir->lock);
741 async_rpc_send_reply(req, &result);
744 if (g_sequence_get_length(inode->dirents) > 0) {
745 printf("Directory not empty: %d entries\n",
746 g_sequence_get_length(inode->dirents));
747 result.status = NFS3ERR_NOTEMPTY;
748 g_mutex_unlock(inode->lock);
749 g_mutex_unlock(dir->lock);
750 async_rpc_send_reply(req, &result);
754 /* TODO: Decrement link count, deallocate inode if needed. */
756 bluesky_directory_remove(dir, argp->name);
758 result.status = NFS3_OK;
759 result.wccstat3_u.wcc.after.present = TRUE;
760 encode_fattr3(&result.wccstat3_u.wcc.after.post_op_attr_u.attributes,
763 g_mutex_unlock(inode->lock);
764 g_mutex_unlock(dir->lock);
765 async_rpc_send_reply(req, &result);
768 void nfsproc3_rename_3_svc(rename3args *argp, RPCRequest *req)
771 memset(&result, 0, sizeof(result));
772 wcc_data *wcc1 = &result.rename3res_u.res.fromdir_wcc;
773 wcc_data *wcc2 = &result.rename3res_u.res.todir_wcc;
775 BlueSkyInode *dir1 = lookup_fh(req, &argp->from.dir);
777 result.status = NFS3ERR_STALE;
778 async_rpc_send_reply(req, &result);
782 BlueSkyInode *dir2 = lookup_fh(req, &argp->to.dir);
784 result.status = NFS3ERR_STALE;
785 async_rpc_send_reply(req, &result);
789 if (dir1->inum < dir2->inum) {
790 g_mutex_lock(dir1->lock);
791 g_mutex_lock(dir2->lock);
792 } else if (dir1->inum > dir2->inum) {
793 g_mutex_lock(dir2->lock);
794 g_mutex_lock(dir1->lock);
796 encode_pre_wcc(wcc1, dir1);
797 encode_pre_wcc(wcc2, dir1);
799 gboolean status = bluesky_rename(dir1, argp->from.name,
803 wcc1->after.present = TRUE;
804 encode_fattr3(&wcc1->after.post_op_attr_u.attributes, dir1);
805 wcc2->after.present = TRUE;
806 encode_fattr3(&wcc2->after.post_op_attr_u.attributes, dir2);
808 result.status = NFS3_OK;
810 result.status = NFS3ERR_PERM;
812 g_mutex_unlock(dir1->lock);
813 if (dir1->inum != dir2->inum)
814 g_mutex_unlock(dir2->lock);
815 async_rpc_send_reply(req, &result);
818 void nfsproc3_link_3_svc(link3args *argp, RPCRequest *req)
821 memset(&result, 0, sizeof(result));
823 memset(&wcc, 0, sizeof(wcc));
825 BlueSkyInode *inode = lookup_fh(req, &argp->file);
827 result.status = NFS3ERR_STALE;
828 result.link3res_u.res.linkdir_wcc = wcc;
829 async_rpc_send_reply(req, &result);
832 g_mutex_lock(inode->lock);
834 BlueSkyInode *dir = lookup_fh(req, &argp->link.dir);
836 result.status = NFS3ERR_STALE;
837 result.link3res_u.res.linkdir_wcc = wcc;
838 g_mutex_unlock(inode->lock);
839 async_rpc_send_reply(req, &result);
842 g_mutex_lock(dir->lock);
844 encode_pre_wcc(&wcc, dir);
845 if (dir->type != BLUESKY_DIRECTORY) {
846 result.status = NFS3ERR_NOTDIR;
847 result.link3res_u.res.linkdir_wcc = wcc;
848 g_mutex_unlock(inode->lock);
849 g_mutex_unlock(dir->lock);
850 async_rpc_send_reply(req, &result);
854 if (!validate_filename(argp->link.name)
855 || strcmp(argp->link.name, ".") == 0
856 || strcmp(argp->link.name, "..") == 0
857 || bluesky_directory_lookup(dir, argp->link.name) != 0)
859 result.status = NFS3ERR_EXIST;
860 result.link3res_u.res.linkdir_wcc = wcc;
861 g_mutex_unlock(inode->lock);
862 g_mutex_unlock(dir->lock);
863 async_rpc_send_reply(req, &result);
867 if (!bluesky_directory_insert(dir, argp->link.name, inode->inum)) {
868 result.status = NFS3ERR_EXIST;
869 result.link3res_u.res.linkdir_wcc = wcc;
870 g_mutex_unlock(inode->lock);
871 g_mutex_unlock(dir->lock);
872 async_rpc_send_reply(req, &result);
876 bluesky_inode_update_ctime(inode, FALSE);
877 bluesky_inode_update_ctime(dir, TRUE);
879 result.status = NFS3_OK;
880 wcc.after.present = TRUE;
881 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
882 result.link3res_u.res.file_attributes.present = TRUE;
883 encode_fattr3(&result.link3res_u.res.file_attributes.post_op_attr_u.attributes, inode);
884 result.link3res_u.res.linkdir_wcc = wcc;
886 g_mutex_unlock(inode->lock);
887 g_mutex_unlock(dir->lock);
888 async_rpc_send_reply(req, &result);
891 gint bluesky_dirent_compare(gconstpointer a, gconstpointer b,
894 #define MAX_READDIR_DIRENTS 64
895 void nfsproc3_readdir_3_svc(readdir3args *argp, RPCRequest *req)
898 memset(&result, 0, sizeof(result));
900 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
902 result.status = NFS3ERR_STALE;
903 result.readdir3res_u.resfail.present = FALSE;
904 async_rpc_send_reply(req, &result);
907 g_mutex_lock(dir->lock);
909 result.status = NFS3_OK;
910 result.readdir3res_u.resok.dir_attributes.present = TRUE;
911 encode_fattr3(&result.readdir3res_u.resok.dir_attributes.post_op_attr_u.attributes, dir);
912 memset(result.readdir3res_u.resok.cookieverf, 0,
913 sizeof(result.readdir3res_u.resok.cookieverf));
915 entry3 dirents[MAX_READDIR_DIRENTS];
918 BlueSkyDirent start = {NULL, NULL, argp->cookie, 0};
919 GSequenceIter *i = g_sequence_search(dir->dirents, &start,
920 bluesky_dirent_compare, NULL);
922 while (count < MAX_READDIR_DIRENTS && !g_sequence_iter_is_end(i)) {
923 BlueSkyDirent *d = g_sequence_get(i);
924 dirents[count].fileid = d->inum;
925 dirents[count].name = d->name;
926 dirents[count].cookie = d->cookie;
927 dirents[count].nextentry = NULL;
929 dirents[count - 1].nextentry = &dirents[count];
930 i = g_sequence_iter_next(i);
935 result.readdir3res_u.resok.reply.entries = &dirents[0];
937 result.readdir3res_u.resok.reply.entries = NULL;
938 result.readdir3res_u.resok.reply.eof = g_sequence_iter_is_end(i);
940 g_mutex_unlock(dir->lock);
941 async_rpc_send_reply(req, &result);
944 void nfsproc3_readdirplus_3_svc(readdirplus3args *argp, RPCRequest *req)
946 /* XDR-encoded sizes:
947 * post_op_attr: 88 bytes
948 * base readdirplus3resok: 88 + 16 bytes
949 * base directory entry: 24 bytes + filename
950 * attributes/fh3: 88 + 8 + filehandle size
952 size_t dircount = 88 + 16, attrcount = 0;
953 readdirplus3res result;
954 memset(&result, 0, sizeof(result));
956 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
958 result.status = NFS3ERR_STALE;
959 result.readdirplus3res_u.resfail.present = FALSE;
960 async_rpc_send_reply(req, &result);
963 g_mutex_lock(dir->lock);
965 result.status = NFS3_OK;
966 result.readdirplus3res_u.resok.dir_attributes.present = TRUE;
967 encode_fattr3(&result.readdirplus3res_u.resok.dir_attributes.post_op_attr_u.attributes, dir);
968 memset(result.readdirplus3res_u.resok.cookieverf, 0,
969 sizeof(result.readdirplus3res_u.resok.cookieverf));
971 entryplus3 dirents[MAX_READDIR_DIRENTS];
972 uint64_t fh_bytes[MAX_READDIR_DIRENTS];
976 BlueSkyDirent start = {NULL, NULL, argp->cookie, 0};
978 /* Perform a prefetch pass on inodes: for all the inodes we think we will
979 * return information about, try to load each one but don't wait. This
980 * should let multiple inodes be fetched in parallel, instead of
981 * sequentially in the loop that follows. */
982 i = g_sequence_search(dir->dirents, &start, bluesky_dirent_compare, NULL);
983 while (count < MAX_READDIR_DIRENTS
984 && !g_sequence_iter_is_end(i)
985 && dircount <= argp->dircount
986 && dircount + attrcount <= argp->maxcount)
988 BlueSkyDirent *d = g_sequence_get(i);
989 BlueSkyInode *inode = bluesky_get_inode(fs, d->inum);
991 bluesky_inode_unref(inode);
992 dircount += 24 + ((strlen(d->name) + 3) & ~3);
993 attrcount += 88 + 8 + 8;
994 i = g_sequence_iter_next(i);
997 i = g_sequence_search(dir->dirents, &start, bluesky_dirent_compare, NULL);
1001 while (count < MAX_READDIR_DIRENTS && !g_sequence_iter_is_end(i)) {
1002 BlueSkyDirent *d = g_sequence_get(i);
1003 BlueSkyInode *inode = bluesky_get_inode(fs, d->inum);
1004 if (inode != NULL) {
1005 g_mutex_lock(inode->lock);
1006 dircount += 24 + ((strlen(d->name) + 3) & ~3);
1007 attrcount += 88 + 8 + 8;
1008 if (dircount > argp->dircount
1009 || dircount + attrcount > argp->maxcount)
1011 g_mutex_unlock(inode->lock);
1012 bluesky_inode_unref(inode);
1015 dirents[count].fileid = d->inum;
1016 dirents[count].name = d->name;
1017 dirents[count].cookie = d->cookie;
1018 dirents[count].nextentry = NULL;
1019 dirents[count].name_attributes.present = TRUE;
1020 encode_fattr3(&dirents[count].name_attributes.post_op_attr_u.attributes, inode);
1021 fh_bytes[count] = GUINT64_TO_BE(d->inum);
1022 dirents[count].name_handle.present = TRUE;
1023 dirents[count].name_handle.post_op_fh3_u.handle.data.data_len = 8;
1024 dirents[count].name_handle.post_op_fh3_u.handle.data.data_val
1025 = (char *)&fh_bytes[count];
1027 dirents[count - 1].nextentry = &dirents[count];
1029 g_mutex_unlock(inode->lock);
1030 bluesky_inode_unref(inode);
1032 i = g_sequence_iter_next(i);
1036 result.readdirplus3res_u.resok.reply.entries = &dirents[0];
1038 result.readdirplus3res_u.resok.reply.entries = NULL;
1039 result.readdirplus3res_u.resok.reply.eof = g_sequence_iter_is_end(i);
1041 g_mutex_unlock(dir->lock);
1042 async_rpc_send_reply(req, &result);
1045 void nfsproc3_fsstat_3_svc(nfs_fh3 *argp, RPCRequest *req)
1048 memset(&result, 0, sizeof(result));
1050 BlueSkyInode *inode = lookup_fh(req, argp);
1051 if (inode == NULL) {
1052 result.status = NFS3ERR_STALE;
1053 result.fsstat3res_u.resfail.present = FALSE;
1054 async_rpc_send_reply(req, &result);
1057 g_mutex_lock(inode->lock);
1059 result.status = NFS3_OK;
1060 result.fsstat3res_u.resok.obj_attributes.present = TRUE;
1061 encode_fattr3(&result.fsstat3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
1063 result.fsstat3res_u.resok.tbytes = (1 << 30);
1064 result.fsstat3res_u.resok.fbytes = (1 << 30);
1065 result.fsstat3res_u.resok.abytes = (1 << 30);
1066 result.fsstat3res_u.resok.tfiles = 0;
1067 result.fsstat3res_u.resok.ffiles = 0;
1068 result.fsstat3res_u.resok.afiles = 0;
1069 result.fsstat3res_u.resok.invarsec = 0;
1071 g_mutex_unlock(inode->lock);
1072 async_rpc_send_reply(req, &result);
1075 void nfsproc3_fsinfo_3_svc(nfs_fh3 *argp, RPCRequest *req)
1078 memset(&result, 0, sizeof(result));
1080 BlueSkyInode *inode = bluesky_get_inode(fs, 1);
1081 g_mutex_lock(inode->lock);
1082 result.status = NFS3_OK;
1083 result.fsinfo3res_u.resok.obj_attributes.present = TRUE;
1084 encode_fattr3(&result.fsinfo3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
1085 result.fsinfo3res_u.resok.rtmax = NFS_MAXSIZE;
1086 result.fsinfo3res_u.resok.rtpref = NFS_MAXSIZE;
1087 result.fsinfo3res_u.resok.rtmult = NFS_BLOCKSIZE;
1088 result.fsinfo3res_u.resok.wtmax = NFS_MAXSIZE;
1089 result.fsinfo3res_u.resok.wtpref = NFS_MAXSIZE;
1090 result.fsinfo3res_u.resok.wtmult = NFS_BLOCKSIZE;
1091 result.fsinfo3res_u.resok.dtpref = NFS_BLOCKSIZE;
1092 result.fsinfo3res_u.resok.maxfilesize = 0x7fffffffffffffffULL;
1093 result.fsinfo3res_u.resok.time_delta.seconds = 0;
1094 result.fsinfo3res_u.resok.time_delta.nseconds = 1000;
1095 result.fsinfo3res_u.resok.properties
1096 = FSF3_LINK | FSF3_SYMLINK | FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
1098 g_mutex_unlock(inode->lock);
1099 bluesky_inode_unref(inode);
1100 async_rpc_send_reply(req, &result);
1103 void nfsproc3_pathconf_3_svc(nfs_fh3 *argp, RPCRequest *req)
1105 pathconf3res result;
1106 memset(&result, 0, sizeof(result));
1108 BlueSkyInode *inode = bluesky_get_inode(fs, 1);
1109 g_mutex_lock(inode->lock);
1110 result.status = NFS3_OK;
1111 result.pathconf3res_u.resok.obj_attributes.present = TRUE;
1112 encode_fattr3(&result.pathconf3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
1113 result.pathconf3res_u.resok.linkmax = 0xffffffff;
1114 result.pathconf3res_u.resok.name_max = 255;
1115 result.pathconf3res_u.resok.no_trunc = TRUE;
1116 result.pathconf3res_u.resok.chown_restricted = TRUE;
1117 result.pathconf3res_u.resok.case_insensitive = FALSE;
1118 result.pathconf3res_u.resok.case_preserving = TRUE;
1120 g_mutex_unlock(inode->lock);
1121 bluesky_inode_unref(inode);
1122 async_rpc_send_reply(req, &result);
1125 void nfsproc3_commit_3_svc(commit3args *argp, RPCRequest *req)
1128 memset(&result, 0, sizeof(result));
1130 result.status = NFS3_OK;
1132 BlueSkyInode *inode = lookup_fh(req, &argp->file);
1133 if (inode == NULL) {
1134 result.status = NFS3ERR_STALE;
1135 async_rpc_send_reply(req, &result);
1139 g_mutex_lock(inode->lock);
1140 encode_pre_wcc(&result.commit3res_u.resok.file_wcc, inode);
1142 //bluesky_inode_do_sync(inode);
1144 result.commit3res_u.resok.file_wcc.after.present = TRUE;
1145 encode_fattr3(&result.commit3res_u.resok.file_wcc.after.post_op_attr_u.attributes, inode);
1147 g_mutex_unlock(inode->lock);
1149 async_rpc_send_reply(req, &result);