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 = UNSTABLE;
432 memcpy(result.write3res_u.resok.verf,
433 nfsd_instance_verf_cookie, NFS3_WRITEVERFSIZE);
435 if (argp->stable != UNSTABLE) {
436 bluesky_inode_do_sync(inode);
437 result.write3res_u.resok.committed = FILE_SYNC;
440 g_mutex_unlock(inode->lock);
442 async_rpc_send_reply(req, &result);
445 void nfsproc3_create_3_svc(create3args *argp, RPCRequest *req)
448 memset(&result, 0, sizeof(result));
450 memset(&wcc, 0, sizeof(wcc));
452 BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
454 result.status = NFS3ERR_STALE;
455 result.diropres3_u.resfail = wcc;
456 async_rpc_send_reply(req, &result);
460 g_mutex_lock(dir->lock);
462 encode_pre_wcc(&wcc, dir);
463 if (dir->type != BLUESKY_DIRECTORY) {
464 result.status = NFS3ERR_NOTDIR;
465 result.diropres3_u.resfail = wcc;
466 g_mutex_unlock(dir->lock);
467 async_rpc_send_reply(req, &result);
471 if (!validate_filename(argp->where.name)
472 || strcmp(argp->where.name, ".") == 0
473 || strcmp(argp->where.name, "..") == 0)
475 result.status = NFS3ERR_EXIST;
476 result.diropres3_u.resfail = wcc;
477 g_mutex_unlock(dir->lock);
478 async_rpc_send_reply(req, &result);
482 g_mutex_lock(fs->lock);
484 file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_REGULAR);
487 int64_t time = bluesky_get_current_time();
492 g_mutex_lock(file->lock);
493 bluesky_insert_inode(fs, file);
494 g_mutex_unlock(fs->lock);
495 bluesky_directory_insert(dir, argp->where.name, file->inum);
497 bluesky_inode_update_ctime(dir, TRUE);
498 bluesky_inode_update_ctime(file, FALSE);
500 wcc.after.present = TRUE;
501 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
502 result.diropres3_u.resok.obj_attributes.present = TRUE;
503 encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
504 result.diropres3_u.resok.dir_wcc = wcc;
507 fh_bytes = GUINT64_TO_BE(file->inum);
508 result.diropres3_u.resok.obj.present = TRUE;
509 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
510 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
512 bluesky_inode_do_sync(file);
513 bluesky_inode_do_sync(dir);
514 g_mutex_unlock(file->lock);
515 g_mutex_unlock(dir->lock);
517 async_rpc_send_reply(req, &result);
520 void nfsproc3_mkdir_3_svc(mkdir3args *argp, RPCRequest *req)
523 memset(&result, 0, sizeof(result));
525 memset(&wcc, 0, sizeof(wcc));
527 BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
529 result.status = NFS3ERR_STALE;
530 result.diropres3_u.resfail = wcc;
531 async_rpc_send_reply(req, &result);
535 g_mutex_lock(dir->lock);
537 encode_pre_wcc(&wcc, dir);
538 if (dir->type != BLUESKY_DIRECTORY) {
539 result.status = NFS3ERR_NOTDIR;
540 result.diropres3_u.resfail = wcc;
541 g_mutex_unlock(dir->lock);
542 async_rpc_send_reply(req, &result);
546 if (!validate_filename(argp->where.name)
547 || strcmp(argp->where.name, ".") == 0
548 || strcmp(argp->where.name, "..") == 0)
550 result.status = NFS3ERR_EXIST;
551 result.diropres3_u.resfail = wcc;
552 g_mutex_unlock(dir->lock);
553 async_rpc_send_reply(req, &result);
557 g_mutex_lock(fs->lock);
559 file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_DIRECTORY);
562 int64_t time = bluesky_get_current_time();
567 g_mutex_lock(file->lock);
568 bluesky_insert_inode(fs, file);
569 g_mutex_unlock(fs->lock);
570 bluesky_directory_insert(dir, argp->where.name, file->inum);
571 set_attributes(file, &argp->attributes);
573 bluesky_inode_update_ctime(dir, TRUE);
574 bluesky_inode_update_ctime(file, FALSE);
576 wcc.after.present = TRUE;
577 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
578 result.diropres3_u.resok.obj_attributes.present = TRUE;
579 encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
580 result.diropres3_u.resok.dir_wcc = wcc;
583 fh_bytes = GUINT64_TO_BE(file->inum);
584 result.diropres3_u.resok.obj.present = TRUE;
585 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
586 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
588 bluesky_inode_do_sync(file);
589 bluesky_inode_do_sync(dir);
590 g_mutex_unlock(file->lock);
591 g_mutex_unlock(dir->lock);
592 async_rpc_send_reply(req, &result);
595 void nfsproc3_symlink_3_svc(symlink3args *argp, RPCRequest *req)
598 memset(&result, 0, sizeof(result));
600 memset(&wcc, 0, sizeof(wcc));
602 BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
604 result.status = NFS3ERR_STALE;
605 result.diropres3_u.resfail = wcc;
606 async_rpc_send_reply(req, &result);
609 g_mutex_lock(dir->lock);
611 encode_pre_wcc(&wcc, dir);
612 if (dir->type != BLUESKY_DIRECTORY) {
613 result.status = NFS3ERR_NOTDIR;
614 result.diropres3_u.resfail = wcc;
615 g_mutex_unlock(dir->lock);
616 async_rpc_send_reply(req, &result);
620 if (!validate_filename(argp->where.name)
621 || strcmp(argp->where.name, ".") == 0
622 || strcmp(argp->where.name, "..") == 0)
624 result.status = NFS3ERR_EXIST;
625 result.diropres3_u.resfail = wcc;
626 g_mutex_unlock(dir->lock);
627 async_rpc_send_reply(req, &result);
631 g_mutex_lock(fs->lock);
633 file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_SYMLINK);
636 int64_t time = bluesky_get_current_time();
641 file->symlink_contents = g_strdup(argp->symlink.symlink_data);
642 g_mutex_lock(file->lock);
643 bluesky_insert_inode(fs, file);
644 g_mutex_unlock(fs->lock);
645 bluesky_directory_insert(dir, argp->where.name, file->inum);
647 bluesky_inode_update_ctime(dir, TRUE);
648 bluesky_inode_update_ctime(file, FALSE);
650 wcc.after.present = TRUE;
651 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
652 result.diropres3_u.resok.obj_attributes.present = TRUE;
653 encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
654 result.diropres3_u.resok.dir_wcc = wcc;
657 fh_bytes = GUINT64_TO_BE(file->inum);
658 result.diropres3_u.resok.obj.present = TRUE;
659 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
660 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
662 bluesky_inode_do_sync(file);
663 bluesky_inode_do_sync(dir);
664 g_mutex_unlock(file->lock);
665 g_mutex_unlock(dir->lock);
666 async_rpc_send_reply(req, &result);
669 void nfsproc3_mknod_3_svc(mknod3args *argp, RPCRequest *req)
672 memset(&result, 0, sizeof(result));
674 result.status = NFS3ERR_NOTSUPP;
676 async_rpc_send_reply(req, &result);
679 void nfsproc3_remove_3_svc(diropargs3 *argp, RPCRequest *req)
682 memset(&result, 0, sizeof(result));
684 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
686 result.status = NFS3ERR_STALE;
687 async_rpc_send_reply(req, &result);
691 g_mutex_lock(dir->lock);
693 encode_pre_wcc(&result.wccstat3_u.wcc, dir);
695 if (!validate_filename(argp->name)
696 || strcmp(argp->name, ".") == 0
697 || strcmp(argp->name, "..") == 0)
699 result.status = NFS3ERR_NOENT;
700 g_mutex_unlock(dir->lock);
701 async_rpc_send_reply(req, &result);
705 /* TODO: Decrement link count, deallocate inode if needed. */
707 bluesky_directory_remove(dir, argp->name);
709 result.status = NFS3_OK;
710 result.wccstat3_u.wcc.after.present = TRUE;
711 encode_fattr3(&result.wccstat3_u.wcc.after.post_op_attr_u.attributes,
714 bluesky_inode_do_sync(dir);
715 g_mutex_unlock(dir->lock);
716 async_rpc_send_reply(req, &result);
719 void nfsproc3_rmdir_3_svc(diropargs3 *argp, RPCRequest *req)
722 memset(&result, 0, sizeof(result));
724 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
726 result.status = NFS3ERR_STALE;
727 async_rpc_send_reply(req, &result);
731 g_mutex_lock(dir->lock);
733 encode_pre_wcc(&result.wccstat3_u.wcc, dir);
735 if (!validate_filename(argp->name)
736 || strcmp(argp->name, ".") == 0
737 || strcmp(argp->name, "..") == 0)
739 result.status = NFS3ERR_NOENT;
740 g_mutex_unlock(dir->lock);
741 async_rpc_send_reply(req, &result);
745 uint64_t inum = bluesky_directory_lookup(dir, argp->name);
746 BlueSkyInode *inode = bluesky_get_inode(fs, inum);
748 result.status = NFS3ERR_NOENT;
749 g_mutex_unlock(dir->lock);
750 async_rpc_send_reply(req, &result);
753 g_mutex_lock(inode->lock);
754 schedule_inode_unref(req, inode);
756 if (inode->type != BLUESKY_DIRECTORY) {
757 result.status = NFS3ERR_NOTDIR;
758 g_mutex_unlock(inode->lock);
759 g_mutex_unlock(dir->lock);
760 async_rpc_send_reply(req, &result);
763 if (g_sequence_get_length(inode->dirents) > 0) {
764 printf("Directory not empty: %d entries\n",
765 g_sequence_get_length(inode->dirents));
766 result.status = NFS3ERR_NOTEMPTY;
767 g_mutex_unlock(inode->lock);
768 g_mutex_unlock(dir->lock);
769 async_rpc_send_reply(req, &result);
773 /* TODO: Decrement link count, deallocate inode if needed. */
775 bluesky_directory_remove(dir, argp->name);
777 result.status = NFS3_OK;
778 result.wccstat3_u.wcc.after.present = TRUE;
779 encode_fattr3(&result.wccstat3_u.wcc.after.post_op_attr_u.attributes,
782 bluesky_inode_do_sync(dir);
783 bluesky_inode_do_sync(inode);
784 g_mutex_unlock(inode->lock);
785 g_mutex_unlock(dir->lock);
786 async_rpc_send_reply(req, &result);
789 void nfsproc3_rename_3_svc(rename3args *argp, RPCRequest *req)
792 memset(&result, 0, sizeof(result));
793 wcc_data *wcc1 = &result.rename3res_u.res.fromdir_wcc;
794 wcc_data *wcc2 = &result.rename3res_u.res.todir_wcc;
796 BlueSkyInode *dir1 = lookup_fh(req, &argp->from.dir);
798 result.status = NFS3ERR_STALE;
799 async_rpc_send_reply(req, &result);
803 BlueSkyInode *dir2 = lookup_fh(req, &argp->to.dir);
805 result.status = NFS3ERR_STALE;
806 async_rpc_send_reply(req, &result);
810 if (dir1->inum < dir2->inum) {
811 g_mutex_lock(dir1->lock);
812 g_mutex_lock(dir2->lock);
813 } else if (dir1->inum > dir2->inum) {
814 g_mutex_lock(dir2->lock);
815 g_mutex_lock(dir1->lock);
817 encode_pre_wcc(wcc1, dir1);
818 encode_pre_wcc(wcc2, dir1);
820 gboolean status = bluesky_rename(dir1, argp->from.name,
824 wcc1->after.present = TRUE;
825 encode_fattr3(&wcc1->after.post_op_attr_u.attributes, dir1);
826 wcc2->after.present = TRUE;
827 encode_fattr3(&wcc2->after.post_op_attr_u.attributes, dir2);
829 result.status = NFS3_OK;
831 result.status = NFS3ERR_PERM;
833 bluesky_inode_do_sync(dir2);
834 bluesky_inode_do_sync(dir1);
836 g_mutex_unlock(dir1->lock);
837 if (dir1->inum != dir2->inum)
838 g_mutex_unlock(dir2->lock);
839 async_rpc_send_reply(req, &result);
842 void nfsproc3_link_3_svc(link3args *argp, RPCRequest *req)
845 memset(&result, 0, sizeof(result));
847 memset(&wcc, 0, sizeof(wcc));
849 BlueSkyInode *inode = lookup_fh(req, &argp->file);
851 result.status = NFS3ERR_STALE;
852 result.link3res_u.res.linkdir_wcc = wcc;
853 async_rpc_send_reply(req, &result);
856 g_mutex_lock(inode->lock);
858 BlueSkyInode *dir = lookup_fh(req, &argp->link.dir);
860 result.status = NFS3ERR_STALE;
861 result.link3res_u.res.linkdir_wcc = wcc;
862 g_mutex_unlock(inode->lock);
863 async_rpc_send_reply(req, &result);
866 g_mutex_lock(dir->lock);
868 encode_pre_wcc(&wcc, dir);
869 if (dir->type != BLUESKY_DIRECTORY) {
870 result.status = NFS3ERR_NOTDIR;
871 result.link3res_u.res.linkdir_wcc = wcc;
872 g_mutex_unlock(inode->lock);
873 g_mutex_unlock(dir->lock);
874 async_rpc_send_reply(req, &result);
878 if (!validate_filename(argp->link.name)
879 || strcmp(argp->link.name, ".") == 0
880 || strcmp(argp->link.name, "..") == 0
881 || bluesky_directory_lookup(dir, argp->link.name) != 0)
883 result.status = NFS3ERR_EXIST;
884 result.link3res_u.res.linkdir_wcc = wcc;
885 g_mutex_unlock(inode->lock);
886 g_mutex_unlock(dir->lock);
887 async_rpc_send_reply(req, &result);
891 if (!bluesky_directory_insert(dir, argp->link.name, inode->inum)) {
892 result.status = NFS3ERR_EXIST;
893 result.link3res_u.res.linkdir_wcc = wcc;
894 g_mutex_unlock(inode->lock);
895 g_mutex_unlock(dir->lock);
896 async_rpc_send_reply(req, &result);
900 bluesky_inode_update_ctime(inode, FALSE);
901 bluesky_inode_update_ctime(dir, TRUE);
903 result.status = NFS3_OK;
904 wcc.after.present = TRUE;
905 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
906 result.link3res_u.res.file_attributes.present = TRUE;
907 encode_fattr3(&result.link3res_u.res.file_attributes.post_op_attr_u.attributes, inode);
908 result.link3res_u.res.linkdir_wcc = wcc;
910 bluesky_inode_do_sync(inode);
911 bluesky_inode_do_sync(dir);
912 g_mutex_unlock(inode->lock);
913 g_mutex_unlock(dir->lock);
914 async_rpc_send_reply(req, &result);
917 gint bluesky_dirent_compare(gconstpointer a, gconstpointer b,
920 #define MAX_READDIR_DIRENTS 64
921 void nfsproc3_readdir_3_svc(readdir3args *argp, RPCRequest *req)
924 memset(&result, 0, sizeof(result));
926 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
928 result.status = NFS3ERR_STALE;
929 result.readdir3res_u.resfail.present = FALSE;
930 async_rpc_send_reply(req, &result);
933 g_mutex_lock(dir->lock);
935 result.status = NFS3_OK;
936 result.readdir3res_u.resok.dir_attributes.present = TRUE;
937 encode_fattr3(&result.readdir3res_u.resok.dir_attributes.post_op_attr_u.attributes, dir);
938 memset(result.readdir3res_u.resok.cookieverf, 0,
939 sizeof(result.readdir3res_u.resok.cookieverf));
941 entry3 dirents[MAX_READDIR_DIRENTS];
944 BlueSkyDirent start = {NULL, NULL, argp->cookie, 0};
945 GSequenceIter *i = g_sequence_search(dir->dirents, &start,
946 bluesky_dirent_compare, NULL);
948 while (count < MAX_READDIR_DIRENTS && !g_sequence_iter_is_end(i)) {
949 BlueSkyDirent *d = g_sequence_get(i);
950 dirents[count].fileid = d->inum;
951 dirents[count].name = d->name;
952 dirents[count].cookie = d->cookie;
953 dirents[count].nextentry = NULL;
955 dirents[count - 1].nextentry = &dirents[count];
956 i = g_sequence_iter_next(i);
961 result.readdir3res_u.resok.reply.entries = &dirents[0];
963 result.readdir3res_u.resok.reply.entries = NULL;
964 result.readdir3res_u.resok.reply.eof = g_sequence_iter_is_end(i);
966 g_mutex_unlock(dir->lock);
967 async_rpc_send_reply(req, &result);
970 void nfsproc3_readdirplus_3_svc(readdirplus3args *argp, RPCRequest *req)
972 /* XDR-encoded sizes:
973 * post_op_attr: 88 bytes
974 * base readdirplus3resok: 88 + 16 bytes
975 * base directory entry: 24 bytes + filename
976 * attributes/fh3: 88 + 8 + filehandle size
978 size_t dircount = 88 + 16, attrcount = 0;
979 readdirplus3res result;
980 memset(&result, 0, sizeof(result));
982 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
984 result.status = NFS3ERR_STALE;
985 result.readdirplus3res_u.resfail.present = FALSE;
986 async_rpc_send_reply(req, &result);
989 g_mutex_lock(dir->lock);
991 result.status = NFS3_OK;
992 result.readdirplus3res_u.resok.dir_attributes.present = TRUE;
993 encode_fattr3(&result.readdirplus3res_u.resok.dir_attributes.post_op_attr_u.attributes, dir);
994 memset(result.readdirplus3res_u.resok.cookieverf, 0,
995 sizeof(result.readdirplus3res_u.resok.cookieverf));
997 entryplus3 dirents[MAX_READDIR_DIRENTS];
998 uint64_t fh_bytes[MAX_READDIR_DIRENTS];
1002 BlueSkyDirent start = {NULL, NULL, argp->cookie, 0};
1004 /* Perform a prefetch pass on inodes: for all the inodes we think we will
1005 * return information about, try to load each one but don't wait. This
1006 * should let multiple inodes be fetched in parallel, instead of
1007 * sequentially in the loop that follows. */
1008 i = g_sequence_search(dir->dirents, &start, bluesky_dirent_compare, NULL);
1009 while (count < MAX_READDIR_DIRENTS
1010 && !g_sequence_iter_is_end(i)
1011 && dircount <= argp->dircount
1012 && dircount + attrcount <= argp->maxcount)
1014 BlueSkyDirent *d = g_sequence_get(i);
1015 BlueSkyInode *inode = bluesky_get_inode(fs, d->inum);
1017 bluesky_inode_unref(inode);
1018 dircount += 24 + ((strlen(d->name) + 3) & ~3);
1019 attrcount += 88 + 8 + 8;
1020 i = g_sequence_iter_next(i);
1023 i = g_sequence_search(dir->dirents, &start, bluesky_dirent_compare, NULL);
1027 while (count < MAX_READDIR_DIRENTS && !g_sequence_iter_is_end(i)) {
1028 BlueSkyDirent *d = g_sequence_get(i);
1029 BlueSkyInode *inode = bluesky_get_inode(fs, d->inum);
1030 if (inode != NULL) {
1031 g_mutex_lock(inode->lock);
1032 dircount += 24 + ((strlen(d->name) + 3) & ~3);
1033 attrcount += 88 + 8 + 8;
1034 if (dircount > argp->dircount
1035 || dircount + attrcount > argp->maxcount)
1037 g_mutex_unlock(inode->lock);
1038 bluesky_inode_unref(inode);
1041 dirents[count].fileid = d->inum;
1042 dirents[count].name = d->name;
1043 dirents[count].cookie = d->cookie;
1044 dirents[count].nextentry = NULL;
1045 dirents[count].name_attributes.present = TRUE;
1046 encode_fattr3(&dirents[count].name_attributes.post_op_attr_u.attributes, inode);
1047 fh_bytes[count] = GUINT64_TO_BE(d->inum);
1048 dirents[count].name_handle.present = TRUE;
1049 dirents[count].name_handle.post_op_fh3_u.handle.data.data_len = 8;
1050 dirents[count].name_handle.post_op_fh3_u.handle.data.data_val
1051 = (char *)&fh_bytes[count];
1053 dirents[count - 1].nextentry = &dirents[count];
1055 g_mutex_unlock(inode->lock);
1056 bluesky_inode_unref(inode);
1058 i = g_sequence_iter_next(i);
1062 result.readdirplus3res_u.resok.reply.entries = &dirents[0];
1064 result.readdirplus3res_u.resok.reply.entries = NULL;
1065 result.readdirplus3res_u.resok.reply.eof = g_sequence_iter_is_end(i);
1067 g_mutex_unlock(dir->lock);
1068 async_rpc_send_reply(req, &result);
1071 void nfsproc3_fsstat_3_svc(nfs_fh3 *argp, RPCRequest *req)
1074 memset(&result, 0, sizeof(result));
1076 BlueSkyInode *inode = lookup_fh(req, argp);
1077 if (inode == NULL) {
1078 result.status = NFS3ERR_STALE;
1079 result.fsstat3res_u.resfail.present = FALSE;
1080 async_rpc_send_reply(req, &result);
1083 g_mutex_lock(inode->lock);
1085 result.status = NFS3_OK;
1086 result.fsstat3res_u.resok.obj_attributes.present = TRUE;
1087 encode_fattr3(&result.fsstat3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
1089 result.fsstat3res_u.resok.tbytes = (1 << 30);
1090 result.fsstat3res_u.resok.fbytes = (1 << 30);
1091 result.fsstat3res_u.resok.abytes = (1 << 30);
1092 result.fsstat3res_u.resok.tfiles = 0;
1093 result.fsstat3res_u.resok.ffiles = 0;
1094 result.fsstat3res_u.resok.afiles = 0;
1095 result.fsstat3res_u.resok.invarsec = 0;
1097 g_mutex_unlock(inode->lock);
1098 async_rpc_send_reply(req, &result);
1101 void nfsproc3_fsinfo_3_svc(nfs_fh3 *argp, RPCRequest *req)
1104 memset(&result, 0, sizeof(result));
1106 BlueSkyInode *inode = bluesky_get_inode(fs, 1);
1107 g_mutex_lock(inode->lock);
1108 result.status = NFS3_OK;
1109 result.fsinfo3res_u.resok.obj_attributes.present = TRUE;
1110 encode_fattr3(&result.fsinfo3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
1111 result.fsinfo3res_u.resok.rtmax = NFS_MAXSIZE;
1112 result.fsinfo3res_u.resok.rtpref = NFS_MAXSIZE;
1113 result.fsinfo3res_u.resok.rtmult = NFS_BLOCKSIZE;
1114 result.fsinfo3res_u.resok.wtmax = NFS_MAXSIZE;
1115 result.fsinfo3res_u.resok.wtpref = NFS_MAXSIZE;
1116 result.fsinfo3res_u.resok.wtmult = NFS_BLOCKSIZE;
1117 result.fsinfo3res_u.resok.dtpref = NFS_BLOCKSIZE;
1118 result.fsinfo3res_u.resok.maxfilesize = 0x7fffffffffffffffULL;
1119 result.fsinfo3res_u.resok.time_delta.seconds = 0;
1120 result.fsinfo3res_u.resok.time_delta.nseconds = 1000;
1121 result.fsinfo3res_u.resok.properties
1122 = FSF3_LINK | FSF3_SYMLINK | FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
1124 g_mutex_unlock(inode->lock);
1125 bluesky_inode_unref(inode);
1126 async_rpc_send_reply(req, &result);
1129 void nfsproc3_pathconf_3_svc(nfs_fh3 *argp, RPCRequest *req)
1131 pathconf3res result;
1132 memset(&result, 0, sizeof(result));
1134 BlueSkyInode *inode = bluesky_get_inode(fs, 1);
1135 g_mutex_lock(inode->lock);
1136 result.status = NFS3_OK;
1137 result.pathconf3res_u.resok.obj_attributes.present = TRUE;
1138 encode_fattr3(&result.pathconf3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
1139 result.pathconf3res_u.resok.linkmax = 0xffffffff;
1140 result.pathconf3res_u.resok.name_max = 255;
1141 result.pathconf3res_u.resok.no_trunc = TRUE;
1142 result.pathconf3res_u.resok.chown_restricted = TRUE;
1143 result.pathconf3res_u.resok.case_insensitive = FALSE;
1144 result.pathconf3res_u.resok.case_preserving = TRUE;
1146 g_mutex_unlock(inode->lock);
1147 bluesky_inode_unref(inode);
1148 async_rpc_send_reply(req, &result);
1151 void nfsproc3_commit_3_svc(commit3args *argp, RPCRequest *req)
1154 memset(&result, 0, sizeof(result));
1156 result.status = NFS3_OK;
1158 BlueSkyInode *inode = lookup_fh(req, &argp->file);
1159 if (inode == NULL) {
1160 result.status = NFS3ERR_STALE;
1161 async_rpc_send_reply(req, &result);
1165 g_mutex_lock(inode->lock);
1166 encode_pre_wcc(&result.commit3res_u.resok.file_wcc, inode);
1168 bluesky_inode_do_sync(inode);
1170 result.commit3res_u.resok.file_wcc.after.present = TRUE;
1171 encode_fattr3(&result.commit3res_u.resok.file_wcc.after.post_op_attr_u.attributes, inode);
1172 memcpy(result.commit3res_u.resok.verf,
1173 nfsd_instance_verf_cookie, NFS3_WRITEVERFSIZE);
1175 g_mutex_unlock(inode->lock);
1177 async_rpc_send_reply(req, &result);