int32_t rmdir(char *pathname) { /* rmdir() system call */ char *parent, *child; inode_t *dir; super_block_t *sb; namei_t namei_data; int32_t err; /* divide pathname: */ if (err = divide_path(pathname, 1, &parent, &child)) return -err; /* get the inode structure of parent: */ err = namei(NULL, parent, &namei_data); kfree(parent); /* no need anymore. */ if (err) { kfree(child); return -err; } /* extract information from namei_data: */ dir = namei_data.inode; sb = dir->sb; kfree(namei_data.path); /* not needed. */ /* call filesystem driver: */ err = sb->fsdriver->rmdir(dir, child); /* that's all! */ iput(dir); kfree(child); return -err; }
//PAGEBREAK: 32 // Set up first user process. void userinit(void) { struct proc *p; extern char _binary_initcode_start[], _binary_initcode_size[]; p = allocproc(); initproc = p; if((p->pgdir = setupkvm()) == 0) panic("userinit: out of memory?"); inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size); p->sz = PGSIZE; memset(p->tf, 0, sizeof(*p->tf)); p->tf->cs = (SEG_UCODE << 3) | DPL_USER; p->tf->ds = (SEG_UDATA << 3) | DPL_USER; p->tf->es = p->tf->ds; p->tf->ss = p->tf->ds; p->tf->eflags = FL_IF; p->tf->esp = PGSIZE; p->tf->eip = 0; // beginning of initcode.S safestrcpy(p->name, "initcode", sizeof(p->name)); p->cwd = namei("/"); // this assignment to p->state lets other cores // run this process. the acquire forces the above // writes to be visible, and the lock is also needed // because the assignment might not be atomic. acquire(&ptable.lock); p->state = RUNNABLE; release(&ptable.lock); }
int compat_20_netbsd32_statfs(struct lwp *l, const struct compat_20_netbsd32_statfs_args *uap, register_t *retval) { /* { syscallarg(const netbsd32_charp) path; syscallarg(netbsd32_statfsp_t) buf; } */ struct mount *mp; struct statvfs *sp; struct netbsd32_statfs s32; int error; struct nameidata nd; NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, SCARG_P32(uap, path)); if ((error = namei(&nd)) != 0) return (error); mp = nd.ni_vp->v_mount; sp = &mp->mnt_stat; vrele(nd.ni_vp); if ((error = VFS_STATVFS(mp, sp)) != 0) return (error); sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK; compat_20_netbsd32_from_statvfs(sp, &s32); return copyout(&s32, SCARG_P32(uap, buf), sizeof(s32)); }
asmlinkage int sys_chmod(const char * filename, mode_t mode) { struct inode * inode; int error; struct iattr newattrs; error = namei(filename,&inode); if (error) return error; if (IS_RDONLY(inode)) { iput(inode); return -EROFS; } if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { iput(inode); return -EPERM; } if (mode == (mode_t) -1) mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; inode->i_dirt = 1; error = notify_change(inode, &newattrs); iput(inode); return error; }
//PAGEBREAK: 32 // hand-craft the first user process. We link initcode.S into the kernel // as a binary, the linker will generate __binary_initcode_start/_size void userinit(void) { struct proc *p; extern char _binary_initcode_start[], _binary_initcode_size[]; p = allocproc(); initproc = p; if((p->pgdir = kpt_alloc()) == NULL) { panic("userinit: out of memory?"); } inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size); p->sz = PTE_SZ; // craft the trapframe as if memset(p->tf, 0, sizeof(*p->tf)); p->tf->r14_svc = (uint)error_init; p->tf->spsr = spsr_usr (); p->tf->sp_usr = PTE_SZ; // set the user stack p->tf->lr_usr = 0; // set the user pc. The actual pc loaded into r15_usr is in // p->tf, the trapframe. p->tf->pc = 0; // beginning of initcode.S safestrcpy(p->name, "initcode", sizeof(p->name)); p->cwd = namei("/"); p->state = RUNNABLE; }
static int linux_unlink_dircheck(const char *path) { struct nameidata nd; struct pathbuf *pb; int error; /* * Linux returns EISDIR if unlink(2) is called on a directory. * We return EPERM in such cases. To emulate correct behaviour, * check if the path points to directory and return EISDIR if this * is the case. * * XXX this should really not copy in the path buffer twice... */ error = pathbuf_copyin(path, &pb); if (error) { return error; } NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb); if (namei(&nd) == 0) { struct stat sb; if (vn_stat(nd.ni_vp, &sb) == 0 && S_ISDIR(sb.st_mode)) error = EISDIR; vput(nd.ni_vp); } pathbuf_destroy(pb); return error ? error : EPERM; }
/* * Perform process accounting functions. */ void sysacct(void) { register struct inode *ip; register struct a { char *fname; } *uap; uap = (struct a *)u.u_ap; if (suser()) { if (uap->fname==NULL) { if (acctp) { plock(acctp); iput(acctp); acctp = NULL; } return; } if (acctp) { u.u_error = EBUSY; return; } u.u_dirp = uap->fname; ip = namei(uchar, 0); if (ip == NULL) { return; } if ((ip->i_mode & IFMT) != IFREG) { u.u_error = EACCES; iput(ip); return; } acctp = ip; prele(ip); } }
//PAGEBREAK: 32 // Set up first user process. void userinit(void) { struct proc *p; extern char _binary_initcode_start[], _binary_initcode_size[]; p = allocproc(); initproc = p; if((p->pgdir = setupkvm()) == 0) panic("userinit: out of memory?"); inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size); p->sz = PGSIZE; memset(p->tf, 0, sizeof(*p->tf)); p->tf->cs = (SEG_UCODE << 3) | DPL_USER; p->tf->ds = (SEG_UDATA << 3) | DPL_USER; p->tf->es = p->tf->ds; p->tf->ss = p->tf->ds; p->tf->eflags = FL_IF; p->tf->esp = PGSIZE; p->tf->eip = 0; // beginning of initcode.S safestrcpy(p->name, "initcode", sizeof(p->name)); p->cwd = namei("/"); p->state = RUNNABLE; p->next = NULL; // initialize queue next pointer p->priority = 15; // initialize priority //**** //cprintf("add in userinit\n"); acquire(&ptable.lock); addtoq(p); release(&ptable.lock); //**** }
/* * do_mount() does the actual mounting after sys_mount has done the ugly * parameter parsing. When enough time has gone by, and everything uses the * new mount() parameters, sys_mount() can then be cleaned up. * * We cannot mount a filesystem if it has active, used, or dirty inodes. * We also have to flush all inode-data for this device, as the new mount * might need new info. */ static int do_mount(dev_t dev, const char * dir, const char * type, int flags, void * data) { struct inode *dir_i; struct super_block *sb; int error; error = namei(dir, &dir_i); if (error) return error; if (dir_i->i_count != 1 || dir_i->i_mount) { iput(dir_i); return -EBUSY; } if (!S_ISDIR(dir_i->i_mode)) { iput(dir_i); return -EPERM; } //if (!fs_may_mount(dev)) { // iput(dir_i); // return -EBUSY; //} sb = read_super(dev, type, flags, data, 0); if (!sb || sb->s_covered) { iput(dir_i); return -EBUSY; } sb->s_covered = dir_i; dir_i->i_mount = sb->s_mounted; return 0; // we don't iput(dir_i) - see umount }
//PAGEBREAK: 32 // Set up first user process. void userinit(void) { struct proc *p; extern char _binary_initcode_start[], _binary_initcode_size[]; p = allocproc(); initproc = p; initproc->uid = 0; if((p->pgdir = setupkvm()) == 0) panic("userinit: out of memory?"); inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size); p->sz = PGSIZE; memset(p->tf, 0, sizeof(*p->tf)); p->tf->cs = (SEG_UCODE << 3) | DPL_USER; p->tf->ds = (SEG_UDATA << 3) | DPL_USER; p->tf->es = p->tf->ds; p->tf->ss = p->tf->ds; p->tf->eflags = FL_IF; p->tf->esp = PGSIZE; p->tf->eip = 0; // beginning of initcode.S safestrcpy(p->name, "initcode", sizeof(p->name)); p->cwd = namei("/"); safestrcpy(p->wdpath, "/\n", 2); //start in the root directory p->state = RUNNABLE; }
/* * change to a directory * */ void cd(const char* pathname) { /* * get pinode in memory */ int dinode_no = namei(pathname); if (dinode_no == 0) { printf("No such file or directory\n"); return; } struct inode_t* pinode = iget(dinode_no); if (pinode == NULL) { printf("No such file or directory\n"); return; } if (pinode->type != 'd') { printf("Not a directory\n"); return; } /* change the cur dir */ cur_dir_dinode_no = dinode_no; return; }
int sys_truncate(char *path, loff_t length) { struct inode *inode; register struct inode *inodep; int error; error = namei(path, &inode, NOT_DIR, MAY_WRITE); inodep = inode; if (error) return error; if (IS_RDONLY(inodep)) { iput(inodep); return -EROFS; } #ifdef BLOAT_FS error = get_write_access(inodep); if (error) { iput(inodep); return error; } #endif error = do_truncate(inodep, length); put_write_access(inodep); iput(inodep); return error; }
int sys_utimes(char *filename, struct timeval *utimes) { int error; struct inode *inode; register struct inode *inodep; struct iattr newattrs; error = namei(filename, &inode, 0, 0); inodep = inode; if (error) return error; if (IS_RDONLY(inodep)) { iput(inodep); return -EROFS; } /* Don't worry, the checks are done in inode_change_ok() */ newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; if (utimes) { struct timeval times[2]; if (error = verified_memcpy_fromfs(×, utimes, sizeof(times))) { iput(inodep); return error; } newattrs.ia_atime = times[0].tv_sec; newattrs.ia_mtime = times[1].tv_sec; newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; } else if ((error = permission(inodep, MAY_WRITE)) != 0) { iput(inodep); return error; } error = notify_change(inodep, &newattrs); iput(inodep); return error; }
int sys_access(char *filename, int mode) { struct inode *inode; mode_t tmp_mode = 0; struct task *current; if (!(inode = namei(filename, NULL))) return -EACCESS; if (mode == F_OK) { iput(inode); return 0; } mode &= 7; current = CURRENT_TASK(); if (current->uid == inode->i_uid) tmp_mode |= (mode) << 6; if (current->gid == inode->i_gid) tmp_mode |= (mode) << 3; tmp_mode |= (mode); if (tmp_mode & inode->i_mode) { iput(inode); return 0; } iput(inode); return -EACCESS; }
asmlinkage int sys_umount(char * name, int flags) { struct dentry * dentry; int retval; if (!capable(CAP_SYS_ADMIN)) return -EPERM; lock_kernel(); dentry = namei(name); retval = PTR_ERR(dentry); if (!IS_ERR(dentry)) { struct inode * inode = dentry->d_inode; kdev_t dev = inode->i_rdev; retval = 0; if (S_ISBLK(inode->i_mode)) { if (IS_NODEV(inode)) retval = -EACCES; } else { struct super_block *sb = inode->i_sb; retval = -EINVAL; if (sb && inode == sb->s_root->d_inode) { dev = sb->s_dev; retval = 0; } } dput(dentry); if (!retval) retval = umount_dev(dev, flags); } unlock_kernel(); return retval; }
int linux_newstat(struct proc *p, struct linux_newstat_args *args) { struct stat buf; struct nameidata nd; int error; caddr_t sg; sg = stackgap_init(); CHECKALTEXIST(p, &sg, args->path); #ifdef DEBUG printf("Linux-emul(%ld): newstat(%s, *)\n", (long)p->p_pid, args->path); #endif NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, args->path, p); error = namei(&nd); if (error) return (error); NDFREE(&nd, NDF_ONLY_PNBUF); error = vn_stat(nd.ni_vp, &buf, p); vput(nd.ni_vp); if (error) return (error); return (newstat_copyout(&buf, args->buf)); }
int do_remount(const char *dir,int flags,char *data) { struct dentry *dentry; int retval; dentry = namei(dir); retval = PTR_ERR(dentry); if (!IS_ERR(dentry)) { struct super_block * sb = dentry->d_inode->i_sb; retval = -ENODEV; if (sb) { retval = -EINVAL; if (dentry == sb->s_root) { /* * Shrink the dcache and sync the device. */ shrink_dcache_sb(sb); fsync_dev(sb->s_dev); if (flags & MS_RDONLY) acct_auto_close(sb->s_dev); retval = do_remount_sb(sb, flags, data); } } dput(dentry); } return retval; }
// Set up first user process. void userinit(void) { struct proc *p; extern uchar _binary_initcode_start[], _binary_initcode_size[]; p = copyproc(0); p->sz = PAGE; p->mem = kalloc(p->sz); p->cwd = namei("/"); memset(p->tf, 0, sizeof(*p->tf)); p->tf->cs = (SEG_UCODE << 3) | DPL_USER; p->tf->ds = (SEG_UDATA << 3) | DPL_USER; p->tf->es = p->tf->ds; p->tf->ss = p->tf->ds; p->tf->eflags = FL_IF; p->tf->esp = p->sz; // Make return address readable; needed for some gcc. p->tf->esp -= 4; *(uint*)(p->mem + p->tf->esp) = 0xefefefef; // On entry to user space, start executing at beginning of initcode.S. p->tf->eip = 0; memmove(p->mem, _binary_initcode_start, (int)_binary_initcode_size); safestrcpy(p->name, "initcode", sizeof(p->name)); p->state = RUNNABLE; initproc = p; }
int mount(char* path, uint partitionNum){ int partition; struct inode *ip; partition = findPlaceToMount(); ip = namei(path); ilock(ip); if(ip->type != T_DIR){ cprintf("mount place is not a file!\n"); return -1; } iunlock(ip); if(partitionNum < 0 || partitionNum > 3){ cprintf("not a valid partition!\n"); return -1; } else{ mountArr.mounts[partition].inode = ip; //return inode by path memmove(mountArr.mounts[partition].path, path, strlen(path)); mountArr.mounts[partition].partition = partitionNum; mountArr.mounts[partition].used = 1; cprintf("mounted! partition num:%d\n", partitionNum); } return 0; }
//PAGEBREAK: 32 // Set up first user process. void userinit(void) { struct proc *p; extern char _binary_initcode_start[], _binary_initcode_size[]; p = allocproc(); initproc = p; if((p->pgdir = setupkvm()) == 0) panic("userinit: out of memory?"); inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size); p->sz = PGSIZE; memset(p->tf, 0, sizeof(*p->tf)); p->tf->cs = (SEG_UCODE << 3) | DPL_USER; p->tf->ds = (SEG_UDATA << 3) | DPL_USER; p->tf->es = p->tf->ds; p->tf->ss = p->tf->ds; p->tf->eflags = FL_IF; p->tf->esp = PGSIZE; p->tf->eip = 0; // beginning of initcode.S safestrcpy(p->name, "initcode", sizeof(p->name)); p->cwd = namei("/"); p->state = RUNNABLE; #ifndef __ORIGINAL_SCHED__ penqueue(p); #endif }
/* If times==NULL, set access and modification to current time, * must be owner or have write permission. * Else, update from *times, must be owner or super user. */ asmlinkage int sys_utime(char * filename, struct utimbuf * times) { int error; struct inode * inode; struct iattr newattrs; error = namei(filename,&inode); if (error) return error; if (IS_RDONLY(inode)) { iput(inode); return -EROFS; } /* Don't worry, the checks are done in inode_change_ok() */ newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; if (times) { error = verify_area(VERIFY_READ, times, sizeof(*times)); if (error) { iput(inode); return error; } newattrs.ia_atime = get_user(×->actime); newattrs.ia_mtime = get_user(×->modtime); newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; } else { if (current->fsuid != inode->i_uid && (error = permission(inode,MAY_WRITE)) != 0) { iput(inode); return error; } } error = notify_change(inode, &newattrs); iput(inode); return error; }
// Set up internal proccess for swap managment (inswapper) void createInternalProcess(const char *name, void (*entrypoint)()) { struct proc *p; extern char _binary_initcode_start[], _binary_initcode_size[]; p = allocproc(); inswapper = p; if((p->pgdir = setupkvm(kalloc)) == 0) panic("inswapper: out of memory?"); inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size); p->sz = PGSIZE; memset(p->tf, 0, sizeof(*p->tf)); p->tf->cs = (SEG_UCODE << 3) | DPL_USER; p->tf->ds = (SEG_UDATA << 3) | DPL_USER; p->tf->es = p->tf->ds; p->tf->ss = p->tf->ds; p->tf->eflags = FL_IF; p->tf->esp = PGSIZE; p->tf->eip = 0; p->context->eip = (uint) entrypoint; // beginning of inswapper safestrcpy(p->name, name, sizeof(p->name)); p->cwd = namei("/"); // start sleeping until first proccess is created p->state = SLEEPING; }
// Set up first user process. void userinit(void) { struct proc *p; extern char _binary_initcode_start[], _binary_initcode_size[]; p = allocproc(); initproc = p; // Initialize memory from initcode.S p->sz = PAGE; p->mem = kalloc(p->sz); memset(p->mem, 0, p->sz); memmove(p->mem, _binary_initcode_start, (int)_binary_initcode_size); memset(p->tf, 0, sizeof(*p->tf)); p->tf->cs = (SEG_UCODE << 3) | DPL_USER; p->tf->ds = (SEG_UDATA << 3) | DPL_USER; p->tf->es = p->tf->ds; p->tf->ss = p->tf->ds; p->tf->eflags = FL_IF; p->tf->esp = p->sz; p->tf->eip = 0; // beginning of initcode.S safestrcpy(p->name, "initcode", sizeof(p->name)); p->cwd = namei("/"); p->state = RUNNABLE; }
//PAGEBREAK: 32 // Set up first user process. void userinit(void) { struct proc *p; extern char _binary_initcode_start[], _binary_initcode_size[]; p = allocproc(); initproc = p; if((p->pgdir = setupkvm(kalloc)) == 0) panic("userinit: out of memory?"); inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size); p->sz = PGSIZE; memset(p->tf, 0, sizeof(*p->tf)); p->tf->cs = (SEG_UCODE << 3) | DPL_USER; p->tf->ds = (SEG_UDATA << 3) | DPL_USER; p->tf->es = p->tf->ds; p->tf->ss = p->tf->ds; p->tf->eflags = FL_IF; p->tf->esp = PGSIZE; p->tf->eip = 0; // beginning of initcode.S safestrcpy(p->name, "initcode", sizeof(p->name)); p->cwd = namei("/"); p->state = RUNNABLE; createInternalProcess("inSwapper",(void*)inSwapper); }
//PAGEBREAK: 32 // Set up first user process. void userinit(void) { struct proc *p; extern char _binary_initcode_start[], _binary_initcode_size[]; p = allocproc(); initproc = p; if ((p->pgdir = setupkvm()) == 0) panic("userinit: out of memory?"); inituvm(p->pgdir, _binary_initcode_start, (int) _binary_initcode_size); p->sz = PGSIZE; memset(p->tf, 0, sizeof(*p->tf)); p->tf->cs = (SEG_UCODE << 3) | DPL_USER; p->tf->ds = (SEG_UDATA << 3) | DPL_USER; p->tf->es = p->tf->ds; p->tf->ss = p->tf->ds; p->tf->eflags = FL_IF; p->tf->esp = PGSIZE; p->tf->eip = 0; // beginning of initcode.S safestrcpy(p->name, "initcode", sizeof(p->name)); p->cwd = namei("/"); p->parent=0; setpriority(p,0); SetProcessRunnable(p); }
// Set up first user process. void userinit(void) { struct proc *p; extern char _binary_initcode_start[], _binary_initcode_size[]; p = allocproc(); acquire(&ptable.lock); initproc = p; if((p->pgdir = setupkvm()) == 0) panic("userinit: out of memory?"); inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size); p->sz = PGSIZE; memset(p->tf, 0, sizeof(*p->tf)); p->tf->cs = (SEG_UCODE << 3) | DPL_USER; p->tf->ds = (SEG_UDATA << 3) | DPL_USER; p->tf->es = p->tf->ds; p->tf->ss = p->tf->ds; p->tf->eflags = FL_IF; p->tf->esp = PGSIZE; //init stack ptr p->tf->eip = 0; // beginning of initcode.S //init instruction ptr safestrcpy(p->name, "initcode", sizeof(p->name)); p->cwd = namei("/"); p->state = RUNNABLE; release(&ptable.lock); }
int do_open(const char *path, int mode) { int fd; struct file *f; struct inode *ip; if ((mode & O_CREATE) &&!(ip = icreate(path, T_FILE, 0, 0))) return -1; else if (!(ip = namei(path))) return -1; if (ip->type == T_DIR && mode != O_RDONLY) { iput(ip); return -1; } if (!(f = filealloc()) || (fd = fdalloc()) < 0) { if (f) fileclose(f); iput(ip); return -1; } f->type = FD_INODE; f->ip = ip; f->off = 0; f->readable = !(mode & O_WRONLY); f->writable = (mode & O_WRONLY) || (mode & O_RDWR); fs_current->ofile[fd] = f; return fd; }
// Set up first user process. void userinit(void) { struct proc *p; extern char _binary_initcode_start[], _binary_initcode_size[]; p = allocproc(); initproc = p; if(!(p->pgdir = setupkvm())) panic("userinit: out of memory?"); inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size); p->sz = PGSIZE; memset(p->tf, 0, sizeof(*p->tf)); p->tf->cs = (SEG_UCODE << 3) | DPL_USER; p->tf->ds = (SEG_UDATA << 3) | DPL_USER; p->tf->es = p->tf->ds; p->tf->ss = p->tf->ds; p->tf->eflags = FL_IF; p->tf->esp = PGSIZE; p->tf->eip = 0; // beginning of initcode.S safestrcpy(p->name, "initcode", sizeof(p->name)); p->cwd = namei("/"); p->state = RUNNABLE; // START HW4 p->priority = 0; p->affinity = -1; acquire(&runqueue.lock); enqueue( p->pid, 0 ); release(&runqueue.lock); // END HW4 }
int do_mount(kdev_t dev, char *dir, char *type, int flags, char *data) { struct inode *dir_i; register struct inode *dirp; register struct super_block *sb; int error; if ((error = namei(dir, &dir_i, IS_DIR, 0))) return error; dirp = dir_i; if ((dirp->i_count != 1 || dirp->i_mount) || (!fs_may_mount(dev)) ) { goto BUSY; } sb = read_super(dev, type, flags, data, 0); if (!sb) { iput(dirp); return -EINVAL; } if (sb->s_covered) { BUSY: iput(dirp); return -EBUSY; } sb->s_covered = dirp; dirp->i_mount = sb->s_mounted; return 0; /* we don't iput(dir_i) - see umount */ }
int sys_umount(char *name) { struct inode *inode; register struct inode *inodep; kdev_t dev; int retval; struct inode dummy_inode; if (!suser()) return -EPERM; retval = namei(name, &inode, 0, 0); if (retval) { retval = lnamei(name, &inode); if (retval) return retval; } inodep = inode; if (S_ISBLK(inodep->i_mode)) { dev = inodep->i_rdev; if (IS_NODEV(inodep)) { iput(inodep); return -EACCES; } } else { register struct super_block *sb = inodep->i_sb; if (!sb || inodep != sb->s_mounted) { iput(inodep); return -EINVAL; } dev = sb->s_dev; iput(inodep); memset(&dummy_inode, 0, sizeof(dummy_inode)); dummy_inode.i_rdev = dev; inodep = &dummy_inode; } if (MAJOR(dev) >= MAX_BLKDEV) { iput(inodep); return -ENXIO; } if (!(retval = do_umount(dev)) && dev != ROOT_DEV) { register struct file_operations *fops; fops = get_blkfops(MAJOR(dev)); if (fops && fops->release) fops->release(inodep, NULL); #ifdef NOT_YET if (MAJOR(dev) == UNNAMED_MAJOR) put_unnamed_dev(dev); #endif } if (inodep != &dummy_inode) iput(inodep); if (retval) return retval; fsync_dev(dev); return 0; }