/* * Called when the vnode refcount (in-memory usage count) hits zero. * * This function should try to avoid returning errors other than EBUSY. */ static int sfs_reclaim(struct vnode *v) { struct sfs_vnode *sv = v->vn_data; struct sfs_fs *sfs = v->vn_fs->fs_data; int ix, i, num, result; lock_acquire(sfs->sfs_vnodes_lock); /* * Make sure someone else hasn't picked up the vnode since the * decision was made to reclaim it. (You must also synchronize * this with sfs_loadvnode.) */ lock_acquire(v->vn_countlock); if (v->vn_refcount != 1) { /* consume the reference VOP_DECREF gave us */ assert(v->vn_refcount>1); v->vn_refcount--; lock_release(v->vn_countlock); lock_release(sfs->sfs_vnodes_lock); return EBUSY; } lock_release(v->vn_countlock); /* If there are no on-disk references to the file either, erase it. */ if (sv->sv_i.sfi_linkcount==0 && sv->sv_i.sfi_type==SFS_TYPE_FILE) { /* * VOP_TRUNCATE doesn't work on directories, which is why I added * the second requirement to the above if statement. */ result = VOP_TRUNCATE(&sv->sv_v, 0); if (result) { lock_release(sfs->sfs_vnodes_lock); return result; } } /* Sync the inode to disk */ result = sfs_sync_inode(sv); if (result) { lock_release(sfs->sfs_vnodes_lock); return result; } /* If there are no on-disk references, discard the inode */ if (sv->sv_i.sfi_linkcount==0) { sfs_bfree(sfs, sv->sv_ino); } /* Remove the vnode structure from the table in the struct sfs_fs. */ ix = -1; num = array_getnum(sfs->sfs_vnodes); for (i=0; i<num; i++) { struct sfs_vnode *sv2 = array_getguy(sfs->sfs_vnodes, i); if (sv2==sv) { ix = i; break; } } if (ix<0) { panic("sfs: reclaim vnode %u not in vnode pool\n", sv->sv_ino); } array_remove(sfs->sfs_vnodes, ix); VOP_KILL(&sv->sv_v); /* Release the storage for the vnode structure itself. */ kfree(sv); lock_release(sfs->sfs_vnodes_lock); /* Done */ return 0; }
errno_t sc_open(thread_t *p, syscall_result_t *r, sc_open_args *arg) { int fd; int flags = arg->flags; int error = 0; vnode_t *node; proc_t *proc = p->thr_proc; char fname[PATH_MAX+1]; if((error = copyinstr(fname, arg->fname, PATH_MAX))) return error; KASSERT(proc->p_rootdir!=NULL); error = vfs_lookup(proc->p_curdir, &node, fname, p, LKP_NORMAL); if(error) { if(!(flags & O_CREAT)) return error; vnode_t *parent; error = vfs_lookup_parent(proc->p_curdir, &parent, fname, p); if(error) return error; if((error = VOP_ACCESS(parent, W_OK, proc->p_cred))) { vrele(parent); return error; } vattr_t attr; attr.va_mode = arg->mode & ~(proc->p_umask) & 0777; attr.va_type = VNODE_TYPE_REG; attr.va_uid = proc->p_cred->p_uid; attr.va_gid = proc->p_cred->p_gid; attr.va_size = 0; attr.va_dev = NULL; error = VOP_CREATE(parent, &node, _get_last_cmpt(fname), &attr); VOP_UNLOCK(parent); if(error) return error; VOP_LOCK(node); } else { //plik istnieje if((flags & O_CREAT) && (flags & O_EXCL)) { vrele(node); return -EEXIST; } if((node->v_type == VNODE_TYPE_DIR) && (flags & (O_RDWR | O_WRONLY))) { vrele(node); return -EISDIR; } } int wmode = (flags & O_RDWR) ? (W_OK | R_OK) : (flags & O_RDONLY) ? (R_OK) : (W_OK); if((error = VOP_ACCESS(node, wmode, proc->p_cred))) { vrele(node); return error; } if((error = VOP_OPEN(node, flags, arg->mode))) { vrele(node); return error; } if(ISSET(flags, O_RDWR | O_WRONLY) && ISSET(flags, O_TRUNC) && node->v_type == VNODE_TYPE_REG) VOP_TRUNCATE(node, 0); if((error = f_alloc(proc, node, flags, &fd))) { vrele(node); // <- powinno to tutaj być, dopisałem bo nie było. return error; } VOP_UNLOCK(node); r->result = fd; return 0; }
/* * Called when the vnode refcount (in-memory usage count) hits zero. * * This function should try to avoid returning errors other than EBUSY. */ static int sfs_reclaim(struct vnode *v) { struct sfs_vnode *sv = v->vn_data; struct sfs_fs *sfs = v->vn_fs->fs_data; unsigned ix, i, num; int result; vfs_biglock_acquire(); /* * Make sure someone else hasn't picked up the vnode since the * decision was made to reclaim it. (You must also synchronize * this with sfs_loadvnode.) */ if (v->vn_refcount != 1) { /* consume the reference VOP_DECREF gave us */ KASSERT(v->vn_refcount>1); v->vn_refcount--; vfs_biglock_release(); return EBUSY; } /* If there are no on-disk references to the file either, erase it. */ if (sv->sv_i.sfi_linkcount==0) { result = VOP_TRUNCATE(&sv->sv_v, 0); if (result) { vfs_biglock_release(); return result; } } /* Sync the inode to disk */ result = sfs_sync_inode(sv); if (result) { vfs_biglock_release(); return result; } /* If there are no on-disk references, discard the inode */ if (sv->sv_i.sfi_linkcount==0) { sfs_bfree(sfs, sv->sv_ino); } /* Remove the vnode structure from the table in the struct sfs_fs. */ num = vnodearray_num(sfs->sfs_vnodes); ix = num; for (i=0; i<num; i++) { struct vnode *v2 = vnodearray_get(sfs->sfs_vnodes, i); struct sfs_vnode *sv2 = v2->vn_data; if (sv2 == sv) { ix = i; break; } } if (ix == num) { panic("sfs: reclaim vnode %u not in vnode pool\n", sv->sv_ino); } vnodearray_remove(sfs->sfs_vnodes, ix); VOP_CLEANUP(&sv->sv_v); vfs_biglock_release(); /* Release the storage for the vnode structure itself. */ kfree(sv); /* Done */ return 0; }
/* Does most of the work for open(). */ int vfs_open(char *path, int openflags, struct vnode **ret) { int how; int result; int canwrite; struct vnode *vn = NULL; how = openflags & O_ACCMODE; switch (how) { case O_RDONLY: canwrite=0; break; case O_WRONLY: case O_RDWR: canwrite=1; break; default: return EINVAL; } if (openflags & O_CREAT) { char name[NAME_MAX+1]; struct vnode *dir; int excl = (openflags & O_EXCL)!=0; result = vfs_lookparent(path, &dir, name, sizeof(name)); if (result) { return result; } result = VOP_CREAT(dir, name, excl, &vn); VOP_DECREF(dir); } else { result = vfs_lookup(path, &vn); } if (result) { return result; } assert(vn != NULL); result = VOP_OPEN(vn, openflags); if (result) { VOP_DECREF(vn); return result; } VOP_INCOPEN(vn); if (openflags & O_TRUNC) { if (canwrite==0) { result = EINVAL; } else { result = VOP_TRUNCATE(vn, 0); } if (result) { VOP_DECOPEN(vn); VOP_DECREF(vn); return result; } } *ret = vn; return 0; }