From 3e8d61f4972c85f91c45562971c5a817063aab1f Mon Sep 17 00:00:00 2001 From: Michael Vrable Date: Thu, 27 Aug 2009 21:30:23 -0700 Subject: [PATCH] File read and write operations. --- bluesky.h | 5 +++ inode.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++- nfs3/nfs3.c | 37 ++++++++++++++++++- 3 files changed, 141 insertions(+), 4 deletions(-) diff --git a/bluesky.h b/bluesky.h index 793daa4..b5f5ab5 100644 --- a/bluesky.h +++ b/bluesky.h @@ -119,6 +119,11 @@ gboolean bluesky_directory_insert(BlueSkyInode *dir, gchar *name, uint64_t inum); void bluesky_directory_dump(BlueSkyInode *dir); +void bluesky_block_touch(BlueSkyInode *inode, uint64_t i); void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size); +void bluesky_file_write(BlueSkyInode *inode, uint64_t offset, + const char *data, gint len); +void bluesky_file_read(BlueSkyInode *inode, uint64_t offset, + char *buf, gint len); #endif diff --git a/inode.c b/inode.c index 1c6a083..154614d 100644 --- a/inode.c +++ b/inode.c @@ -8,6 +8,7 @@ #include #include +#include #include "bluesky.h" @@ -132,6 +133,29 @@ void bluesky_insert_inode(BlueSkyFS *fs, BlueSkyInode *inode) g_mutex_unlock(fs->lock); } +/* Mark a given block dirty and make sure that data is faulted in so that it + * can be written to. */ +void bluesky_block_touch(BlueSkyInode *inode, uint64_t i) +{ + g_return_if_fail(i < inode->blocks->len); + BlueSkyBlock *block = &g_array_index(inode->blocks, BlueSkyBlock, i); + + switch (block->type) { + case BLUESKY_BLOCK_ZERO: + block->data = g_malloc0(BLUESKY_BLOCK_SIZE); + break; + case BLUESKY_BLOCK_REF: + /* TODO: Pull in data first */ + block->data = g_malloc0(BLUESKY_BLOCK_SIZE); + break; + case BLUESKY_BLOCK_CACHED: + case BLUESKY_BLOCK_DIRTY: + break; + } + + block->type = BLUESKY_BLOCK_DIRTY; +} + /* Set the size of a file. This will truncate or extend the file as needed. * Newly-allocated bytes are zeroed. */ void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size) @@ -141,7 +165,7 @@ void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size) if (size == inode->size) return; - uint64_t blocks = (size + BLUESKY_BLOCK_SIZE - 1) / BLUESKY_MAX_FILE_SIZE; + uint64_t blocks = (size + BLUESKY_BLOCK_SIZE - 1) / BLUESKY_BLOCK_SIZE; if (blocks > inode->blocks->len) { /* Need to add new blocks to the end of a file. New block structures @@ -158,8 +182,83 @@ void bluesky_file_truncate(BlueSkyInode *inode, uint64_t size) g_array_set_size(inode->blocks, blocks); } - /* TODO: Zero out partial blocks if needed? */ + /* If the file size is being decreased, ensure that any trailing data in + * the last block is zeroed. */ + if (size < inode->size) { + BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, + blocks - 1); + if (b->type != BLUESKY_BLOCK_ZERO) { + bluesky_block_touch(inode, blocks - 1); + int end_offset = size % BLUESKY_BLOCK_SIZE; + if (end_offset > 0) { + memset(&b->data[end_offset], 0, + BLUESKY_BLOCK_SIZE - end_offset); + } + } + } inode->size = size; bluesky_inode_update_ctime(inode, 1); } + +void bluesky_file_write(BlueSkyInode *inode, uint64_t offset, + const char *data, gint len) +{ + g_return_if_fail(inode->type == BLUESKY_REGULAR); + g_return_if_fail(offset < inode->size); + g_return_if_fail(len <= inode->size - offset); + + if (len == 0) + return; + + while (len > 0) { + uint64_t block_num = offset / BLUESKY_BLOCK_SIZE; + gint block_offset = offset % BLUESKY_BLOCK_SIZE; + gint bytes = MIN(BLUESKY_BLOCK_SIZE - block_offset, len); + + bluesky_block_touch(inode, block_num); + BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, + block_num); + memcpy(&b->data[block_offset], data, bytes); + + offset += bytes; + data += bytes; + len -= bytes; + } + + bluesky_inode_update_ctime(inode, 1); +} + +void bluesky_file_read(BlueSkyInode *inode, uint64_t offset, + char *buf, gint len) +{ + g_return_if_fail(inode->type == BLUESKY_REGULAR); + g_return_if_fail(offset < inode->size); + g_return_if_fail(len <= inode->size - offset); + + while (len > 0) { + uint64_t block_num = offset / BLUESKY_BLOCK_SIZE; + gint block_offset = offset % BLUESKY_BLOCK_SIZE; + gint bytes = MIN(BLUESKY_BLOCK_SIZE - block_offset, len); + + BlueSkyBlock *b = &g_array_index(inode->blocks, BlueSkyBlock, + block_num); + switch (b->type) { + case BLUESKY_BLOCK_ZERO: + memset(buf, 0, bytes); + break; + case BLUESKY_BLOCK_REF: + /* TODO: Pull in data first */ + memset(buf, 0, bytes); + break; + case BLUESKY_BLOCK_CACHED: + case BLUESKY_BLOCK_DIRTY: + memcpy(buf, &b->data[block_offset], bytes); + break; + } + + offset += bytes; + buf += bytes; + len -= bytes; + } +} diff --git a/nfs3/nfs3.c b/nfs3/nfs3.c index 04a77b6..95185e5 100644 --- a/nfs3/nfs3.c +++ b/nfs3/nfs3.c @@ -188,8 +188,35 @@ read3res * nfsproc3_read_3_svc(read3args *argp, struct svc_req *rqstp) { static read3res result; + static char buf[32768]; - result.status = NFS3ERR_NOTSUPP; + BlueSkyInode *inode = lookup_fh(&argp->file); + if (inode == NULL) { + result.status = NFS3ERR_STALE; + result.read3res_u.resfail.present = FALSE; + return &result; + } + + int count = argp->count; + if (argp->offset >= inode->size) { + count = 0; + result.read3res_u.resok.eof = TRUE; + } else { + count = MIN(count, inode->size - argp->offset); + if (argp->offset + count == inode->size) + result.read3res_u.resok.eof = TRUE; + else + result.read3res_u.resok.eof = FALSE; + + bluesky_file_read(inode, argp->offset, buf, count); + } + + result.status = NFS3_OK; + result.read3res_u.resok.file_attributes.present = TRUE; + encode_fattr3(&result.read3res_u.resok.file_attributes.post_op_attr_u.attributes, inode); + result.read3res_u.resok.count = count; + result.read3res_u.resok.data.data_val = buf; + result.read3res_u.resok.data.data_len = count; return &result; } @@ -219,7 +246,13 @@ nfsproc3_write_3_svc(write3args *argp, struct svc_req *rqstp) if (lastbyte > inode->size) { bluesky_file_truncate(inode, lastbyte); } - inode->change_count++; + + if (argp->data.data_len < argp->count) { + /* ??? */ + } else { + bluesky_file_write(inode, argp->offset, + argp->data.data_val, argp->count); + } encode_fattr3(&wcc.after.post_op_attr_u.attributes, inode); result.write3res_u.resok.file_wcc = wcc; -- 2.20.1