/* This tests is for the reader writer test, it reads a value, and * checks to make sure that it is the same value that is expected. */ void *reader(int arg1, void *arg2) { kmutex_lock(&reader_mutex); kmutex_lock(&mutex); num_readers++; if(num_readers == 1) { kmutex_lock(&writer_mutex); } kmutex_unlock(&mutex); kmutex_unlock(&reader_mutex); sched_switch(); dbg_print("reader_test: Expected to Read: %i, Did Read: %i\n", arg1, rwval); KASSERT(arg1 == rwval); kmutex_lock(&mutex); num_readers--; if(num_readers == 0) { kmutex_unlock(&writer_mutex); } kmutex_unlock(&mutex); return NULL; }
static void test_normal_locking(){ dbg(DBG_TEST, "testing normal mutex behavior\n"); kmutex_t m; kmutex_init(&m); proc_t *kmutex_proc = proc_create("kmutex_test_proc"); kthread_t *kmutex_thread = kthread_create(kmutex_proc, lock_kmutex_func, NULL, (void *) &m); sched_make_runnable(kmutex_thread); kmutex_lock(&m); /* let kmutex_proc attempt to lock the mutex */ yield(); kmutex_unlock(&m); /* lock and unlock the mutex with nobody on it's wait queue */ kmutex_lock(&m); kmutex_unlock(&m); int status; do_waitpid(kmutex_proc->p_pid, 0, &status); dbg(DBG_TESTPASS, "normal kmutex tests passed!\n"); }
/* * See the comment in vnode.h for what is expected of this function. * * When this function returns, the inode refcount on the parent should be * decremented (since ".." in the removed directory no longer references * it). Remember that the directory must be empty (except for "." and * ".."). * * You probably want to use s5_find_dirent() and s5_remove_dirent(). */ static int s5fs_rmdir(vnode_t *parent, const char *name, size_t namelen) { KASSERT(!(namelen == 1 && name[0] == '.')); KASSERT(!(namelen == 2 && name[0] == '.' && name[1] == '.')); KASSERT(parent->vn_ops->rmdir != NULL); kmutex_lock(&parent->vn_mutex); int ino = s5_find_dirent(parent, name, namelen); /* we check in do_rmdir to make sure the directory exists */ KASSERT(ino != -ENOENT); if (ino < 0){ dbg(DBG_S5FS, "error finding child dir to delete\n"); kmutex_unlock(&parent->vn_mutex); return ino; } vnode_t *child = vget(VNODE_TO_S5FS(parent)->s5f_fs, ino); kmutex_lock(&child->vn_mutex); int dot_lookup_res = s5_find_dirent(child, ".", 1); int dotdot_lookup_res = s5_find_dirent(child, "..", 2); KASSERT(dot_lookup_res != -ENOENT && dotdot_lookup_res != -ENOENT); if (dot_lookup_res < 0 || dotdot_lookup_res < 0){ dbg(DBG_S5FS, "error reading dirents of directory to delete\n"); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&parent->vn_mutex); return (dot_lookup_res < 0) ? dot_lookup_res : dotdot_lookup_res; } KASSERT((unsigned) child->vn_len >= 2 * sizeof(s5_dirent_t)); if ((unsigned) child->vn_len > 2 * sizeof(s5_dirent_t)){ vput(child); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&parent->vn_mutex); return -ENOTEMPTY; } vput(child); VNODE_TO_S5INODE(parent)->s5_linkcount--; s5_dirty_inode(VNODE_TO_S5FS(parent), VNODE_TO_S5INODE(parent)); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&parent->vn_mutex); return s5_remove_dirent(parent, name, namelen); }
/* * See the comment in vnode.h for what is expected of this function. * * This function is similar to s5fs_create, but it creates a special * file specified by 'devid'. * * You probably want to use s5_alloc_inode, s5_link(), vget(), and vput(). */ static int s5fs_mknod(vnode_t *dir, const char *name, size_t namelen, int mode, devid_t devid) { KASSERT(namelen < NAME_LEN); kmutex_lock(&dir->vn_mutex); fs_t *fs = VNODE_TO_S5FS(dir)->s5f_fs; int ino; if (S_ISCHR(mode)){ ino = s5_alloc_inode(fs, S5_TYPE_CHR, devid); } else if (S_ISBLK(mode)){ ino = s5_alloc_inode(fs, S5_TYPE_BLK, devid); } else { panic("invalid mode"); } if (ino < 0){ dbg(DBG_S5FS, "unable to alloc a new inode\n"); kmutex_unlock(&dir->vn_mutex); return ino; } vnode_t *child = vget(fs, ino); kmutex_lock(&child->vn_mutex); /* make sure the state of the new vnode is correct */ assert_new_vnode_state(child, ino, S_ISCHR(mode) ? S5_TYPE_CHR : S5_TYPE_BLK, devid); int link_res = s5_link(dir, child, name, namelen); if (link_res < 0){ dbg(DBG_S5FS, "error creating entry for new directory in parent dir\n"); vput(child); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&dir->vn_mutex); /*s5_free_inode(child);*/ return link_res; } vput(child); KASSERT(child->vn_refcount == 0); KASSERT(VNODE_TO_S5INODE(child)->s5_linkcount == 1); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&dir->vn_mutex); return 0; }
/* This test writes to the value and makes sure that there are no race conditions */ void *writer(int arg1, void *arg2) { kmutex_lock(&reader_mutex); kmutex_lock(&writer_mutex); sched_switch(); rwval++; kmutex_unlock(&writer_mutex); kmutex_unlock(&reader_mutex); return NULL; }
static void test_locking_and_cancelling(){ dbg(DBG_TEST, "testing kmutex behavior with cancellation\n"); kmutex_t m; kmutex_init(&m); proc_t *kmutex_proc = proc_create("kmutex_sleep_test_proc"); kthread_t *kmutex_thread = kthread_create(kmutex_proc, cancellable_lock_kmutex, NULL, (void *) &m); sched_make_runnable(kmutex_thread); kmutex_lock(&m); /* let kmutex_proc attempt to lock the mutex */ yield(); kthread_cancel(kmutex_thread, 0); kmutex_unlock(&m); int status; do_waitpid(kmutex_proc->p_pid, 0, &status); dbg(DBG_TESTPASS, "kmutex cancellation tests passed!\n"); }
static void * remove_my_node(int arg1, void *arg2) { int counter = 10; dbg(DBG_TEST, "Invoke remove_mynode\n"); int rand_number, i=0; while (counter > 0) { check_sleep("remove"); kmutex_lock(&mynode.my_mutex); check_sleep("remove"); if (mynode.length > 0) { mynode.length--; counter--; } dbg(DBG_TEST, "Remove node: %d\n", mynode.length); kmutex_unlock(&mynode.my_mutex); } return NULL; }
static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) { struct smscore_registry_entry_t *entry; struct list_head *next; kmutex_lock(&g_smscore_registrylock); for (next = g_smscore_registry.next; next != &g_smscore_registry; next = next->next) { entry = (struct smscore_registry_entry_t *) next; if (!strcmp(entry->devpath, devpath)) { kmutex_unlock(&g_smscore_registrylock); return entry; } } entry = kmalloc( sizeof(struct smscore_registry_entry_t), GFP_KERNEL); if (entry) { entry->mode = default_mode; if(strlen(devpath) >= 32) { sms_err(" strlen(devpath) >= 32\n"); return NULL; } strcpy(entry->devpath, devpath); list_add(&entry->entry, &g_smscore_registry); } else sms_err("failed to create smscore_registry."); kmutex_unlock(&g_smscore_registrylock); return entry; }
/* * See the comment in vnode.h for what is expected of this function. * * Here you need to use s5_read_file() to read a s5_dirent_t from a directory * and copy that data into the given dirent. The value of d_off is dependent on * your implementation and may or may not b e necessary. Finally, return the * number of bytes read. */ static int s5fs_readdir(vnode_t *vnode, off_t offset, struct dirent *d) { static int s5_dirent_size = sizeof(s5_dirent_t); KASSERT(vnode != NULL); KASSERT(d != NULL); KASSERT(offset <= vnode->vn_len); if (offset == vnode->vn_len){ return 0; } kmutex_lock(&vnode->vn_mutex); s5_dirent_t s5d; int read_res = s5_read_file(vnode, offset, (char *) &s5d, s5_dirent_size); KASSERT(read_res <= s5_dirent_size && "read too much!"); if (read_res == s5_dirent_size){ d->d_ino = s5d.s5d_inode; d->d_off = offset + s5_dirent_size; strcpy(d->d_name, s5d.s5d_name); } else { KASSERT(read_res < 0 && "bad offset or incomplete read"); dbg(DBG_S5FS, "error reading dirent from file\n"); } kmutex_unlock(&vnode->vn_mutex); return read_res; }
/* * s5fs_lookup: * s5fs_lookup sets *result to the vnode in dir with the specified name. * param *base: the vnode object of the base directory * param *name: name string * param namelen: the length of the name * param **result: *result points to the vnode in dir with the specified name * return: 0 on success; negative number on a variety of errors */ int s5fs_lookup(vnode_t *base, const char *name, size_t namelen, vnode_t **result) { dbg(DBG_S5FS, "{\n"); KASSERT(base != NULL); KASSERT(name != NULL); KASSERT(namelen <= S5_NAME_LEN-1); kmutex_lock(&base->vn_mutex); int inode_number = 0; if ((inode_number = s5_find_dirent(base, name, namelen)) < 0) { kmutex_unlock(&base->vn_mutex); return inode_number; } /* May block here */ /* No modification, no need to lock */ *result = vget(base->vn_fs, inode_number); kmutex_unlock(&base->vn_mutex); dbg(DBG_S5FS, "}\n"); return 0; }
/* * See the comment in vnode.h for what is expected of this function. * * When this function returns, the inode refcount of the linked file * should be incremented. * * You probably want to use s5_link(). */ static int s5fs_link(vnode_t *child, vnode_t *parent, const char *name, size_t namelen) { KASSERT(parent->vn_ops->mkdir != NULL); KASSERT(child->vn_ops->mkdir == NULL); kmutex_lock(&parent->vn_mutex); kmutex_lock(&child->vn_mutex); int ret = s5_link(parent, child, name, namelen); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&parent->vn_mutex); return ret; }
void smsnet_onremove(void *context) { kmutex_lock(&g_smsnet_clientslock); smsnet_unregister_client((struct smsnet_client_t *)context); kmutex_unlock(&g_smsnet_clientslock); }
/* Simply call s5_write_file. */ static int s5fs_write(vnode_t *vnode, off_t offset, const void *buf, size_t len) { kmutex_lock(&vnode->vn_mutex); int ret = s5_write_file(vnode, offset, buf, len); kmutex_unlock(&vnode->vn_mutex); return ret; }
/* This function is deceptivly simple, just return the vnode's * mmobj_t through the ret variable. Remember to watch the * refcount. * * Don't worry about this until VM. */ static int s5fs_mmap(vnode_t *file, vmarea_t *vma, mmobj_t **ret) { kmutex_lock(&file->vn_mutex); *ret = &file->vn_mmobj; kmutex_unlock(&file->vn_mutex); return 0; }
static void * lock_kmutex_func(int arg1, void *arg2){ kmutex_t *m = (kmutex_t *) arg2; kmutex_lock(m); kmutex_unlock(m); return NULL; }
/* * See the comment in vnode.h for what is expected of this function. * * When this function returns, the inode refcount of the file should be 2 * and the vnode refcount should be 1. * * You probably want to use s5_alloc_inode(), s5_link(), and vget(). */ static int s5fs_create(vnode_t *dir, const char *name, size_t namelen, vnode_t **result) { KASSERT(namelen < NAME_LEN); kmutex_lock(&dir->vn_mutex); fs_t *fs = VNODE_TO_S5FS(dir)->s5f_fs; int ino = s5_alloc_inode(fs, S5_TYPE_DATA, NULL); if (ino < 0){ dbg(DBG_S5FS, "unable to alloc a new inode\n"); kmutex_unlock(&dir->vn_mutex); return ino; } vnode_t *child = vget(fs, ino); kmutex_lock(&child->vn_mutex); /* make sure the state of the new vnode is correct */ assert_new_vnode_state(child, ino, S5_TYPE_DATA, 0); int link_res = s5_link(dir, child, name, namelen); if (link_res < 0){ dbg(DBG_S5FS, "error creating entry for new directory in parent dir\n"); vput(child); kmutex_unlock(&child->vn_mutex); kmutex_unlock(&dir->vn_mutex); /*s5_free_inode(child);*/ return link_res; } KASSERT(child->vn_refcount == 1); KASSERT(VNODE_TO_S5INODE(child)->s5_linkcount == 2); *result = child; kmutex_unlock(&child->vn_mutex); kmutex_unlock(&dir->vn_mutex); return 0; }
void debug(const char* fmt, ...) { va_list va; kmutex_lock(debug_mutex); va_start(va,fmt); vsnprintf(debug_buff,MAX_DEBUG_LEN,fmt,va); va_end(va); uart_write(1,debug_buff,strlen(debug_buff)); kmutex_unlock(debug_mutex); }
/* * See the comment in vnode.h for what is expected of this function. * * When this function returns, the inode refcount of the unlinked file * should be decremented. * * You probably want to use s5_remove_dirent(). */ static int s5fs_unlink(vnode_t *dir, const char *name, size_t namelen) { KASSERT(dir->vn_ops->mkdir != NULL); kmutex_lock(&dir->vn_mutex); int ret = s5_remove_dirent(dir, name, namelen); kmutex_unlock(&dir->vn_mutex); return ret; }
void smsdvb_unregister(void) { smscore_unregister_hotplug(smsdvb_hotplug); kmutex_lock(&g_smsdvb_clientslock); while (!list_empty(&g_smsdvb_clients)) smsdvb_unregister_client( (struct smsdvb_client_t *) g_smsdvb_clients.next); kmutex_unlock(&g_smsdvb_clientslock); }
static void __exit smsdvb_module_exit(void) { smscore_unregister_hotplug(smsdvb_hotplug); kmutex_lock(&g_smsdvb_clientslock); while (!list_empty(&g_smsdvb_clients)) smsdvb_unregister_client((struct smsdvb_client_t *)g_smsdvb_clients.next); smsdvb_debugfs_unregister(); kmutex_unlock(&g_smsdvb_clientslock); }
/** * poll for data availability * * @param file File structure. * @param wait kernel polling table. * * @return (POLLIN | POLLRDNORM) flags if read data is available. * POLLNVAL flag if wait_queue was cancelled. * <0 on error. */ static unsigned int smschar_poll(struct file *file, struct poll_table_struct *wait) { struct smschar_device_t *dev; int events = 0; if (file == NULL) { sms_err("file is NULL"); return EINVAL; } dev = file->private_data; if (dev == NULL) { sms_err("dev is NULL"); return -EINVAL; } if (dev->cancel_waitq) { /*sms_debug("returning POLLNVAL");*/ events |= POLLNVAL; return events; } /* * critical section, protect access to kernel poll * table structure */ kmutex_lock(&g_smschar_pollwait_lock); /* * make the system call to wait to wait_queue wakeup if there is * no data * cancel_waitq is checked again to prevenet reace condition (wait * to cancalled wait_queue) */ if (list_empty(&dev->pending_data) && (!dev->cancel_waitq)) { poll_wait(file, &dev->waitq, wait); } /* * pending data, raise relevant flags */ if (!list_empty(&dev->pending_data)) { events |= (POLLIN | POLLRDNORM); } kmutex_unlock(&g_smschar_pollwait_lock); return events; }
/* * s5fs_link: * s5fs_link sets up a hard link. it links oldvnode into dir with the * specified name. * param *src: * param *dir: * param *name: name string * param namelen: the length of the name string * return: 0 on success; negative number on a variety of errors */ static int s5fs_link(vnode_t *src, vnode_t *dir, const char *name, size_t namelen) { dbg(DBG_S5FS, "{\n"); KASSERT(src != NULL); KASSERT(dir != NULL); KASSERT(name != NULL); KASSERT(namelen <= S5_NAME_LEN-1); KASSERT(src->vn_fs == dir->vn_fs); vnode_t* vn = NULL; /* Non exist */ KASSERT(s5fs_lookup(dir, name, namelen, &vn) < 0); kmutex_lock(&dir->vn_mutex); kmutex_lock(&src->vn_mutex); s5_inode_t* inode = (s5_inode_t*)src->vn_i; int original_link = inode->s5_linkcount; KASSERT(inode != NULL); int ret = s5_link(dir, src, name, namelen); /* Check increment */ KASSERT(original_link + 1 == inode->s5_linkcount); kmutex_unlock(&src->vn_mutex); kmutex_unlock(&dir->vn_mutex); dbg(DBG_S5FS, "}\n"); return ret; }
/* * A Thread function that exhibits a race condition on the race global being * removed by a mutex. It loads increments and stores race, context switching * between each line of C after acquiring mutex. The mutex acquire cannot * be cancelled. */ void *mutex_uncancellable_test(int arg1, void *arg2) { int local; kmutex_lock(&mutex); sched_switch(); local = race; sched_switch(); local++; sched_switch(); race = local; sched_switch(); kmutex_unlock(&mutex); do_exit(race); return NULL; }
/* * s5fs_write: * Simply call s5_write_file; should be in critical section * param *vnode: the pointer to the vnode object * param offset: the offset in the file where you want to write * param *buf: the source buffer * param len: the length of the buffer * return: just return the result of s5_write_file */ static int s5fs_write(vnode_t *vnode, off_t offset, const void *buf, size_t len) { dbg(DBG_S5FS, "{\n"); KASSERT(vnode != NULL); KASSERT(buf != NULL); int ret = 0; kmutex_lock(&vnode->vn_mutex); ret = s5_write_file(vnode, offset, buf, len); kmutex_unlock(&vnode->vn_mutex); dbg(DBG_S5FS, "}\n"); return ret; }
/* * Read a maximum of len bytes from the line discipline into buf. If * the buffer is empty, sleep until some characters appear. This might * be a long wait, so it's best to let the thread be cancellable. * * Then, read from the head of the buffer up to the tail, stopping at * len bytes or a newline character, and leaving the buffer partially * full if necessary. Return the number of bytes you read into the * buf. * In this function, you will be accessing the input buffer, which * could be modified by other threads. Make sure to make the * appropriate calls to ensure that no one else will modify the input * buffer when we are not expecting it. * * Remember to handle newline characters and CTRL-D, or ASCII 0x04, * properly. */ int n_tty_read(tty_ldisc_t *ldisc, void *buf, int len) { /* DRIVERS {{{ */ int i; char *cbuf = (char *)buf; n_tty_t *ntty; KASSERT(TTY_BUF_SIZE < PAGE_SIZE); KASSERT(NULL != ldisc); ntty = ldisc_to_ntty(ldisc); N_TTY_ASSERT_VALID(ntty); KASSERT(NULL != buf); KASSERT(len >= 0); kmutex_lock(&ntty->ntty_rlock); if (n_tty_ckdbuf_empty(ntty)) { dprintf("Cooked buffer is empty. Sleeping\n"); if (sched_cancellable_sleep_on(&ntty->ntty_rwaitq) == -EINTR) { dprintf("Sleep cancelled. Returning -EINTR\n"); kmutex_unlock(&ntty->ntty_rlock); return -EINTR; } dprintf("Woken up from sleep\n"); } for (i = 0; i < len && !n_tty_ckdbuf_empty(ntty); ++i) { cbuf[i] = n_tty_ckdbuf_dequeue(ntty); if (cbuf[i] == LF) { ++i; break; } else if (cbuf[i] == EOT) { break; } } kmutex_unlock(&ntty->ntty_rlock); return i; /* DRIVERS }}} */ return 0; }
/* * s5fs_create: * s5fs_create is called by open_namev(). it should vget() a new vnode, * and create an entry for this vnode in 'dir' of the specified name. * param *dir: * param name: the name string * param namelen: the length of the name * param **result: pointer to the address of the result vnode * return: 0 on success; negative number on a variety of errors */ static int s5fs_create(vnode_t *dir, const char *name, size_t namelen, vnode_t **result) { dbg(DBG_S5FS, "{\n"); KASSERT(dir != NULL); KASSERT(name != NULL); KASSERT(namelen <= NAME_LEN-1); vnode_t* vn = NULL; /* Must be non-exist */ KASSERT(0 != s5fs_lookup(dir, name, namelen, result)); /* Lock base */ kmutex_lock(&dir->vn_mutex); int ino; if ((ino = s5_alloc_inode(dir->vn_fs, S5_TYPE_DATA, 0)) < 0) { /* Unsuccessfull*/ kmutex_unlock(&dir->vn_mutex); return ino; } /* May block here */ vn = vget(dir->vn_fs, (ino_t)ino); KASSERT(vn->vn_vno == (ino_t)ino); KASSERT(vn != NULL); int ret = 0; if ((ret = s5_link(dir, vn, name, namelen)) < 0) { /* May block here */ vput(vn); kmutex_unlock(&dir->vn_mutex); return ret; } KASSERT(VNODE_TO_S5INODE(vn)->s5_linkcount == 2); KASSERT(vn->vn_refcount == 1); *result = vn; kmutex_unlock(&dir->vn_mutex); dbg(DBG_S5FS, "}\n"); return 0; }
void smsnet_unregister(void) { if (g_smsnet_device) { unregister_netdev(g_smsnet_device); free_netdev(g_smsnet_device); g_smsnet_device = NULL; } smscore_unregister_hotplug(smsnet_hotplug); kmutex_lock(&g_smsnet_clientslock); while (!list_empty(&g_smsnet_clients)) smsnet_unregister_client((struct smsnet_client_t *) g_smsnet_clients.next); kmutex_unlock(&g_smsnet_clientslock); sms_info("exit"); }
/* * See the comment in vnode.h for what is expected of this function. * * You probably want to use s5_find_dirent() and vget(). */ int s5fs_lookup(vnode_t *base, const char *name, size_t namelen, vnode_t **result) { kmutex_lock(&base->vn_mutex); int ino = s5_find_dirent(base, name, namelen); if (ino == -ENOENT){ kmutex_unlock(&base->vn_mutex); return -ENOENT; } KASSERT(ino >= 0 && "forgot an error case\n"); vnode_t *child = vget(VNODE_TO_S5FS(base)->s5f_fs, ino); KASSERT(child != NULL); *result = child; kmutex_unlock(&base->vn_mutex); return 0; }
/* * s5fs_delete_vnode: * s5fs_delete_vnode is called by vput when the * specified vnode_t no longer needs to exist * param *vnode: the pointer to the vnode object */ static void s5fs_delete_vnode(vnode_t *vnode) { dbg(DBG_S5FS, "{\n"); KASSERT(vnode != NULL); KASSERT(vnode->vn_fs != NULL); /* Lock */ kmutex_lock(&vnode->vn_mutex); pframe_t* page = NULL; int ret = pframe_get(S5FS_TO_VMOBJ(FS_TO_S5FS(vnode->vn_fs)), S5_INODE_BLOCK(vnode->vn_vno), &page); KASSERT(ret == 0); KASSERT(page != NULL); s5_inode_t* inode = ((s5_inode_t*)page->pf_addr) + S5_INODE_OFFSET(vnode->vn_vno); inode->s5_linkcount--; s5_dirty_inode(VNODE_TO_S5FS(vnode), inode); KASSERT(VNODE_TO_S5INODE(vnode) == inode); KASSERT(inode->s5_linkcount >= 0); if (inode->s5_linkcount== 0) { s5_free_inode(vnode); } pframe_unpin(page); /* Unlock */ kmutex_unlock(&vnode->vn_mutex); dbg(DBG_S5FS, "}\n"); }
/* * See the comment in vnode.h for what is expected of this function. * * Don't worry if you don't know what some of the fields in struct stat * mean. The ones you should be sure to set are st_mode, st_ino, * st_nlink, st_size, st_blksize, and st_blocks. * * You probably want to use s5_inode_blocks(). */ static int s5fs_stat(vnode_t *vnode, struct stat *ss) { kmutex_lock(&vnode->vn_mutex); int allocated_blocks = s5_inode_blocks(vnode); s5_inode_t *inode = VNODE_TO_S5INODE(vnode); if (allocated_blocks < 0){ dbg(DBG_S5FS, "error calculating number of allocated blocks\n"); kmutex_unlock(&vnode->vn_mutex); return allocated_blocks; } ss->st_mode =vnode->vn_mode; ss->st_ino = inode->s5_number; ss->st_nlink = inode->s5_linkcount; ss->st_size = vnode->vn_len; ss->st_blksize = BLOCK_SIZE; ss->st_blocks = allocated_blocks; kmutex_unlock(&vnode->vn_mutex); return 0; }