int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; int ret = -EPERM; lock_kernel(); if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; ret = 0; goto out; } ret = -ESRCH; read_lock(&tasklist_lock); child = find_task_by_pid(pid); if (child) get_task_struct(child); read_unlock(&tasklist_lock); if (!child) goto out; ret = -EPERM; if (pid == 1) /* you may not mess with init */ goto out_tsk; if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); goto out_tsk; } ret = ptrace_check_attach(child, request == PTRACE_KILL); if (ret < 0) goto out_tsk; switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; int copied; copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); ret = -EIO; if (copied != sizeof(tmp)) break; ret = put_user(tmp,(unsigned long *) data); break; } /* read the word at location addr in the USER area. */ /* XXX this will need fixing for 64-bit */ case PTRACE_PEEKUSR: { unsigned long index, tmp; ret = -EIO; /* convert to index and check */ index = (unsigned long) addr >> 2; if ((addr & 3) || index > PT_FPSCR) break; if (index < PT_FPR0) { tmp = get_reg(child, (int) index); } else { if (child->thread.regs != NULL && child->thread.regs->msr & MSR_FP) giveup_fpu(child); tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; } ret = put_user(tmp,(unsigned long *) data); break; } /* If I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: ret = 0; if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) break; ret = -EIO; break; /* write the word at location addr in the USER area */ /* XXX this will need fixing for 64-bit */ case PTRACE_POKEUSR: { unsigned long index; ret = -EIO; /* convert to index and check */ index = (unsigned long) addr >> 2; if ((addr & 3) || index > PT_FPSCR) break; if (index == PT_ORIG_R3) break; if (index < PT_FPR0) { ret = put_reg(child, index, data); } else { if (child->thread.regs != NULL && child->thread.regs->msr & MSR_FP) giveup_fpu(child); ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; ret = 0; } break; } case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -EIO; if ((unsigned long) data > _NSIG) break; if (request == PTRACE_SYSCALL) child->ptrace |= PT_TRACESYS; else child->ptrace &= ~PT_TRACESYS; child->exit_code = data; /* make sure the single step bit is not set. */ clear_single_step(child); wake_up_process(child); ret = 0; break; } /* * make the child exit. Best I can do is send it a sigkill. * perhaps it should be put in the status that it wants to * exit. */ case PTRACE_KILL: { ret = 0; if (child->state == TASK_ZOMBIE) /* already dead */ break; child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ clear_single_step(child); wake_up_process(child); break; } case PTRACE_SINGLESTEP: { /* set the trap flag. */ ret = -EIO; if ((unsigned long) data > _NSIG) break; child->ptrace &= ~PT_TRACESYS; set_single_step(child); child->exit_code = data; /* give it a chance to run. */ wake_up_process(child); ret = 0; break; } case PTRACE_DETACH: ret = ptrace_detach(child, data); break; #ifdef CONFIG_ALTIVEC case PTRACE_GETVRREGS: /* Get the child altivec register state. */ if (child->thread.regs->msr & MSR_VEC) giveup_altivec(child); ret = get_vrregs((unsigned long *)data, child); break; case PTRACE_SETVRREGS: /* Set the child altivec register state. */ /* this is to clear the MSR_VEC bit to force a reload * of register state from memory */ if (child->thread.regs->msr & MSR_VEC) giveup_altivec(child); ret = set_vrregs(child, (unsigned long *)data); break; #endif default: ret = -EIO; break; } out_tsk: free_task_struct(child); out: unlock_kernel(); return ret; }
static int ext2_remount (struct super_block * sb, int * flags, char * data) { struct ext2_sb_info * sbi = EXT2_SB(sb); struct ext2_super_block * es; unsigned long old_mount_opt = sbi->s_mount_opt; struct ext2_mount_options old_opts; unsigned long old_sb_flags; int err; lock_kernel(); /* Store the old options */ old_sb_flags = sb->s_flags; old_opts.s_mount_opt = sbi->s_mount_opt; old_opts.s_resuid = sbi->s_resuid; old_opts.s_resgid = sbi->s_resgid; /* * Allow the "check" option to be passed as a remount option. */ if (!parse_options (data, sbi)) { err = -EINVAL; goto restore_opts; } sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); ext2_xip_verify_sb(sb); /* see if bdev supports xip, unset EXT2_MOUNT_XIP if not */ if ((ext2_use_xip(sb)) && (sb->s_blocksize != PAGE_SIZE)) { printk("XIP: Unsupported blocksize\n"); err = -EINVAL; goto restore_opts; } es = sbi->s_es; if (((sbi->s_mount_opt & EXT2_MOUNT_XIP) != (old_mount_opt & EXT2_MOUNT_XIP)) && invalidate_inodes(sb)) { ext2_warning(sb, __func__, "refusing change of xip flag " "with busy inodes while remounting"); sbi->s_mount_opt &= ~EXT2_MOUNT_XIP; sbi->s_mount_opt |= old_mount_opt & EXT2_MOUNT_XIP; } if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { unlock_kernel(); return 0; } if (*flags & MS_RDONLY) { if (le16_to_cpu(es->s_state) & EXT2_VALID_FS || !(sbi->s_mount_state & EXT2_VALID_FS)) { unlock_kernel(); return 0; } /* * OK, we are remounting a valid rw partition rdonly, so set * the rdonly flag and then mark the partition as valid again. */ es->s_state = cpu_to_le16(sbi->s_mount_state); es->s_mtime = cpu_to_le32(get_seconds()); } else { __le32 ret = EXT2_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP); if (ret) { printk("EXT2-fs: %s: couldn't remount RDWR because of " "unsupported optional features (%x).\n", sb->s_id, le32_to_cpu(ret)); err = -EROFS; goto restore_opts; } /* * Mounting a RDONLY partition read-write, so reread and * store the current valid flag. (It may have been changed * by e2fsck since we originally mounted the partition.) */ sbi->s_mount_state = le16_to_cpu(es->s_state); if (!ext2_setup_super (sb, es, 0)) sb->s_flags &= ~MS_RDONLY; } ext2_sync_super(sb, es); unlock_kernel(); return 0; restore_opts: sbi->s_mount_opt = old_opts.s_mount_opt; sbi->s_resuid = old_opts.s_resuid; sbi->s_resgid = old_opts.s_resgid; sb->s_flags = old_sb_flags; unlock_kernel(); return err; }
static inline void emulate_load_store_insn(struct pt_regs *regs, unsigned long addr, unsigned long pc) { union mips_instruction insn; unsigned long value, fixup; regs->regs[0] = 0; /* * This load never faults. */ __get_user(insn.word, (unsigned int *)pc); switch (insn.i_format.opcode) { /* * These are instructions that a compiler doesn't generate. We * can assume therefore that the code is MIPS-aware and * really buggy. Emulating these instructions would break the * semantics anyway. */ case ll_op: case lld_op: case sc_op: case scd_op: /* * For these instructions the only way to create an address * error is an attempted access to kernel/supervisor address * space. */ case ldl_op: case ldr_op: case lwl_op: case lwr_op: case sdl_op: case sdr_op: case swl_op: case swr_op: case lb_op: case lbu_op: case sb_op: goto sigbus; /* * The remaining opcodes are the ones that are really of interest. */ case lh_op: check_axs(pc, addr, 2); __asm__( ".set\tnoat\n" #ifdef __BIG_ENDIAN "1:\tlb\t%0,0(%1)\n" "2:\tlbu\t$1,1(%1)\n\t" #endif #ifdef __LITTLE_ENDIAN "1:\tlb\t%0,1(%1)\n" "2:\tlbu\t$1,0(%1)\n\t" #endif "sll\t%0,0x8\n\t" "or\t%0,$1\n\t" ".set\tat\n\t" ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" ".previous" :"=&r" (value) :"r" (addr), "i" (&&fault) :"$1"); regs->regs[insn.i_format.rt] = value; return; case lw_op: check_axs(pc, addr, 4); __asm__( #ifdef __BIG_ENDIAN "1:\tlwl\t%0,(%1)\n" "2:\tlwr\t%0,3(%1)\n\t" #endif #ifdef __LITTLE_ENDIAN "1:\tlwl\t%0,3(%1)\n" "2:\tlwr\t%0,(%1)\n\t" #endif ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" ".previous" :"=&r" (value) :"r" (addr), "i" (&&fault)); regs->regs[insn.i_format.rt] = value; return; case lhu_op: check_axs(pc, addr, 2); __asm__( ".set\tnoat\n" #ifdef __BIG_ENDIAN "1:\tlbu\t%0,0(%1)\n" "2:\tlbu\t$1,1(%1)\n\t" #endif #ifdef __LITTLE_ENDIAN "1:\tlbu\t%0,1(%1)\n" "2:\tlbu\t$1,0(%1)\n\t" #endif "sll\t%0,0x8\n\t" "or\t%0,$1\n\t" ".set\tat\n\t" ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" ".previous" :"=&r" (value) :"r" (addr), "i" (&&fault) :"$1"); regs->regs[insn.i_format.rt] = value; return; case lwu_op: check_axs(pc, addr, 4); __asm__( #ifdef __BIG_ENDIAN "1:\tlwl\t%0,(%1)\n" "2:\tlwr\t%0,3(%1)\n\t" #endif #ifdef __LITTLE_ENDIAN "1:\tlwl\t%0,3(%1)\n" "2:\tlwr\t%0,(%1)\n\t" #endif ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" ".previous" :"=&r" (value) :"r" (addr), "i" (&&fault)); value &= 0xffffffff; regs->regs[insn.i_format.rt] = value; return; case ld_op: check_axs(pc, addr, 8); __asm__( ".set\tmips3\n" #ifdef __BIG_ENDIAN "1:\tldl\t%0,(%1)\n" "2:\tldr\t%0,7(%1)\n\t" #endif #ifdef __LITTLE_ENDIAN "1:\tldl\t%0,7(%1)\n" "2:\tldr\t%0,(%1)\n\t" #endif ".set\tmips0\n\t" ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" ".previous" :"=&r" (value) :"r" (addr), "i" (&&fault)); regs->regs[insn.i_format.rt] = value; return; case sh_op: check_axs(pc, addr, 2); value = regs->regs[insn.i_format.rt]; __asm__( #ifdef __BIG_ENDIAN ".set\tnoat\n" "1:\tsb\t%0,1(%1)\n\t" "srl\t$1,%0,0x8\n" "2:\tsb\t$1,0(%1)\n\t" ".set\tat\n\t" #endif #ifdef __LITTLE_ENDIAN ".set\tnoat\n" "1:\tsb\t%0,0(%1)\n\t" "srl\t$1,%0,0x8\n" "2:\tsb\t$1,1(%1)\n\t" ".set\tat\n\t" #endif ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" ".previous" : /* no outputs */ :"r" (value), "r" (addr), "i" (&&fault) :"$1"); return; case sw_op: check_axs(pc, addr, 4); value = regs->regs[insn.i_format.rt]; __asm__( #ifdef __BIG_ENDIAN "1:\tswl\t%0,(%1)\n" "2:\tswr\t%0,3(%1)\n\t" #endif #ifdef __LITTLE_ENDIAN "1:\tswl\t%0,3(%1)\n" "2:\tswr\t%0,(%1)\n\t" #endif ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" ".previous" : /* no outputs */ :"r" (value), "r" (addr), "i" (&&fault)); return; case sd_op: check_axs(pc, addr, 8); value = regs->regs[insn.i_format.rt]; __asm__( ".set\tmips3\n" #ifdef __BIG_ENDIAN "1:\tsdl\t%0,(%1)\n" "2:\tsdr\t%0,7(%1)\n\t" #endif #ifdef __LITTLE_ENDIAN "1:\tsdl\t%0,7(%1)\n" "2:\tsdr\t%0,(%1)\n\t" #endif ".set\tmips0\n\t" ".section\t__ex_table,\"a\"\n\t" STR(PTR)"\t1b,%2\n\t" STR(PTR)"\t2b,%2\n\t" ".previous" : /* no outputs */ :"r" (value), "r" (addr), "i" (&&fault)); return; case lwc1_op: case ldc1_op: case swc1_op: case sdc1_op: /* * I herewith declare: this does not happen. So send SIGBUS. */ goto sigbus; case lwc2_op: case ldc2_op: case swc2_op: case sdc2_op: /* * These are the coprocessor 2 load/stores. The current * implementations don't use cp2 and cp2 should always be * disabled in c0_status. So send SIGILL. * (No longer true: The Sony Praystation uses cp2 for * 3D matrix operations. Dunno if that thingy has a MMU ...) */ default: /* * Pheeee... We encountered an yet unknown instruction or * cache coherence problem. Die sucker, die ... */ goto sigill; } return; fault: /* Did we have an exception handler installed? */ fixup = search_exception_table(regs->cp0_epc); if (fixup) { long new_epc; new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc); printk(KERN_DEBUG "%s: Forwarding exception at [<%lx>] (%lx)\n", current->comm, regs->cp0_epc, new_epc); regs->cp0_epc = new_epc; return; } lock_kernel(); send_sig(SIGSEGV, current, 1); unlock_kernel(); return; sigbus: lock_kernel(); send_sig(SIGBUS, current, 1); unlock_kernel(); return; sigill: lock_kernel(); send_sig(SIGILL, current, 1); unlock_kernel(); return; }
static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev, void *label) { const char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct buffer_head *bh; struct fnode *fnode; fnode_secno fno; int r; struct hpfs_dirent dee; struct inode *result = NULL; int err; if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; if (hpfs_sb(dir->i_sb)->sb_eas < 2) return -EPERM; if (!new_valid_dev(rdev)) return -EINVAL; lock_kernel(); err = -ENOSPC; fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); if (!fnode) goto bail; memset(&dee, 0, sizeof dee); if (!(mode & 0222)) dee.read_only = 1; dee.archive = 1; dee.hidden = name[0] == '.'; dee.fnode = fno; dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); result = new_inode(dir->i_sb); if (!result) goto bail1; hpfs_init_inode(result); result->i_ino = fno; hpfs_i(result)->i_parent_dir = dir->i_ino; result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); result->i_ctime.tv_nsec = 0; result->i_mtime.tv_nsec = 0; result->i_atime.tv_nsec = 0; hpfs_i(result)->i_ea_size = 0; result->i_uid = current->fsuid; result->i_gid = current->fsgid; result->i_nlink = 1; result->i_size = 0; result->i_blocks = 1; init_special_inode(result, mode, rdev); mutex_lock(&hpfs_i(dir)->i_mutex); r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); if (r == 1) goto bail2; if (r == -1) { err = -EEXIST; goto bail2; } fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); fnode->up = dir->i_ino; mark_buffer_dirty(bh); insert_inode_hash(result); hpfs_write_inode_nolock(result); d_instantiate(dentry, result); mutex_unlock(&hpfs_i(dir)->i_mutex); brelse(bh); unlock_kernel(); return 0; bail2: mutex_unlock(&hpfs_i(dir)->i_mutex); iput(result); bail1: brelse(bh); hpfs_free_sectors(dir->i_sb, fno, 1); bail: unlock_kernel(); return err; }
static int hpfs_unlink(struct inode *dir, struct dentry *dentry) { const char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct quad_buffer_head qbh; struct hpfs_dirent *de; struct inode *inode = dentry->d_inode; dnode_secno dno; fnode_secno fno; int r; int rep = 0; int err; lock_kernel(); hpfs_adjust_length((char *)name, &len); again: mutex_lock(&hpfs_i(inode)->i_parent_mutex); mutex_lock(&hpfs_i(dir)->i_mutex); err = -ENOENT; de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh); if (!de) goto out; err = -EPERM; if (de->first) goto out1; err = -EISDIR; if (de->directory) goto out1; fno = de->fnode; r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); switch (r) { case 1: hpfs_error(dir->i_sb, "there was error when removing dirent"); err = -EFSERROR; break; case 2: /* no space for deleting, try to truncate file */ err = -ENOSPC; if (rep++) break; mutex_unlock(&hpfs_i(dir)->i_mutex); mutex_unlock(&hpfs_i(inode)->i_parent_mutex); d_drop(dentry); spin_lock(&dentry->d_lock); if (atomic_read(&dentry->d_count) > 1 || permission(inode, MAY_WRITE, NULL) || !S_ISREG(inode->i_mode) || get_write_access(inode)) { spin_unlock(&dentry->d_lock); d_rehash(dentry); } else { struct iattr newattrs; spin_unlock(&dentry->d_lock); /*printk("HPFS: truncating file before delete.\n");*/ newattrs.ia_size = 0; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; err = notify_change(dentry, &newattrs); put_write_access(inode); if (!err) goto again; } unlock_kernel(); return -ENOSPC; default: drop_nlink(inode); err = 0; } goto out; out1: hpfs_brelse4(&qbh); out: mutex_unlock(&hpfs_i(dir)->i_mutex); mutex_unlock(&hpfs_i(inode)->i_parent_mutex); unlock_kernel(); return err; }
static void nlm4svc_callback_release(void *data) { lock_kernel(); nlm_release_call(data); unlock_kernel(); }
static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode, void *label) { const char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct quad_buffer_head qbh0; struct buffer_head *bh; struct hpfs_dirent *de; struct fnode *fnode; struct dnode *dnode; struct inode *result; fnode_secno fno; dnode_secno dno; int r; struct hpfs_dirent dee; int err; if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; lock_kernel(); err = -ENOSPC; fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); if (!fnode) goto bail; dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0, 1); if (!dnode) goto bail1; memset(&dee, 0, sizeof dee); dee.directory = 1; if (!(mode & 0222)) dee.read_only = 1; /*dee.archive = 0;*/ dee.hidden = name[0] == '.'; dee.fnode = fno; dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); result = new_inode(dir->i_sb); if (!result) goto bail2; hpfs_init_inode(result); result->i_ino = fno; hpfs_i(result)->i_parent_dir = dir->i_ino; hpfs_i(result)->i_dno = dno; result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); result->i_ctime.tv_nsec = 0; result->i_mtime.tv_nsec = 0; result->i_atime.tv_nsec = 0; hpfs_i(result)->i_ea_size = 0; result->i_mode |= S_IFDIR; result->i_op = &hpfs_dir_iops; result->i_fop = &hpfs_dir_ops; result->i_blocks = 4; result->i_size = 2048; result->i_nlink = 2; if (dee.read_only) result->i_mode &= ~0222; mutex_lock(&hpfs_i(dir)->i_mutex); r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); if (r == 1) goto bail3; if (r == -1) { err = -EEXIST; goto bail3; } fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); fnode->up = dir->i_ino; fnode->dirflag = 1; fnode->btree.n_free_nodes = 7; fnode->btree.n_used_nodes = 1; fnode->btree.first_free = 0x14; fnode->u.external[0].disk_secno = dno; fnode->u.external[0].file_secno = -1; dnode->root_dnode = 1; dnode->up = fno; de = hpfs_add_de(dir->i_sb, dnode, "\001\001", 2, 0); de->creation_date = de->write_date = de->read_date = gmt_to_local(dir->i_sb, get_seconds()); if (!(mode & 0222)) de->read_only = 1; de->first = de->directory = 1; /*de->hidden = de->system = 0;*/ de->fnode = fno; mark_buffer_dirty(bh); brelse(bh); hpfs_mark_4buffers_dirty(&qbh0); hpfs_brelse4(&qbh0); inc_nlink(dir); insert_inode_hash(result); if (result->i_uid != current->fsuid || result->i_gid != current->fsgid || result->i_mode != (mode | S_IFDIR)) { result->i_uid = current->fsuid; result->i_gid = current->fsgid; result->i_mode = mode | S_IFDIR; hpfs_write_inode_nolock(result); } d_instantiate(dentry, result); mutex_unlock(&hpfs_i(dir)->i_mutex); unlock_kernel(); return 0; bail3: mutex_unlock(&hpfs_i(dir)->i_mutex); iput(result); bail2: hpfs_brelse4(&qbh0); hpfs_free_dnode(dir->i_sb, dno); bail1: brelse(bh); hpfs_free_sectors(dir->i_sb, fno, 1); bail: unlock_kernel(); return err; }
static int nfs_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_diropargs arg = { .fh = NFS_FH(dir), .name = name->name, .len = name->len }; struct nfs_diropok res = { .fh = fhandle, .fattr = fattr }; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_LOOKUP], .rpc_argp = &arg, .rpc_resp = &res, }; int status; dprintk("NFS call lookup %s\n", name->name); nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); dprintk("NFS reply lookup: %d\n", status); return status; } static int nfs_proc_readlink(struct inode *inode, struct page *page, unsigned int pgbase, unsigned int pglen) { struct nfs_readlinkargs args = { .fh = NFS_FH(inode), .pgbase = pgbase, .pglen = pglen, .pages = &page }; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_READLINK], .rpc_argp = &args, }; int status; dprintk("NFS call readlink\n"); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); dprintk("NFS reply readlink: %d\n", status); return status; } static int nfs_proc_read(struct nfs_read_data *rdata) { int flags = rdata->flags; struct inode * inode = rdata->inode; struct nfs_fattr * fattr = rdata->res.fattr; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_READ], .rpc_argp = &rdata->args, .rpc_resp = &rdata->res, .rpc_cred = rdata->cred, }; int status; dprintk("NFS call read %d @ %Ld\n", rdata->args.count, (long long) rdata->args.offset); nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); nfs_invalidate_atime(inode); if (status >= 0) { nfs_refresh_inode(inode, fattr); /* Emulate the eof flag, which isn't normally needed in NFSv2 * as it is guaranteed to always return the file attributes */ if (rdata->args.offset + rdata->args.count >= fattr->size) rdata->res.eof = 1; } dprintk("NFS reply read: %d\n", status); return status; } static int nfs_proc_write(struct nfs_write_data *wdata) { int flags = wdata->flags; struct inode * inode = wdata->inode; struct nfs_fattr * fattr = wdata->res.fattr; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_WRITE], .rpc_argp = &wdata->args, .rpc_resp = &wdata->res, .rpc_cred = wdata->cred, }; int status; dprintk("NFS call write %d @ %Ld\n", wdata->args.count, (long long) wdata->args.offset); nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); if (status >= 0) { nfs_post_op_update_inode_force_wcc(inode, fattr); wdata->res.count = wdata->args.count; wdata->verf.committed = NFS_FILE_SYNC; } dprintk("NFS reply write: %d\n", status); return status < 0? status : wdata->res.count; } static int nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags, struct nameidata *nd) { struct nfs_fh fhandle; struct nfs_fattr fattr; struct nfs_createargs arg = { .fh = NFS_FH(dir), .name = dentry->d_name.name, .len = dentry->d_name.len, .sattr = sattr }; struct nfs_diropok res = { .fh = &fhandle, .fattr = &fattr }; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_CREATE], .rpc_argp = &arg, .rpc_resp = &res, }; int status; nfs_fattr_init(&fattr); dprintk("NFS call create %s\n", dentry->d_name.name); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_mark_for_revalidate(dir); if (status == 0) status = nfs_instantiate(dentry, &fhandle, &fattr); dprintk("NFS reply create: %d\n", status); return status; } /* * In NFSv2, mknod is grafted onto the create call. */ static int nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, dev_t rdev) { struct nfs_fh fhandle; struct nfs_fattr fattr; struct nfs_createargs arg = { .fh = NFS_FH(dir), .name = dentry->d_name.name, .len = dentry->d_name.len, .sattr = sattr }; struct nfs_diropok res = { .fh = &fhandle, .fattr = &fattr }; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_CREATE], .rpc_argp = &arg, .rpc_resp = &res, }; int status, mode; dprintk("NFS call mknod %s\n", dentry->d_name.name); mode = sattr->ia_mode; if (S_ISFIFO(mode)) { sattr->ia_mode = (mode & ~S_IFMT) | S_IFCHR; sattr->ia_valid &= ~ATTR_SIZE; } else if (S_ISCHR(mode) || S_ISBLK(mode)) { sattr->ia_valid |= ATTR_SIZE; sattr->ia_size = new_encode_dev(rdev);/* get out your barf bag */ } nfs_fattr_init(&fattr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_mark_for_revalidate(dir); if (status == -EINVAL && S_ISFIFO(mode)) { sattr->ia_mode = mode; nfs_fattr_init(&fattr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); } if (status == 0) status = nfs_instantiate(dentry, &fhandle, &fattr); dprintk("NFS reply mknod: %d\n", status); return status; } static int nfs_proc_remove(struct inode *dir, struct qstr *name) { struct nfs_removeargs arg = { .fh = NFS_FH(dir), .name.len = name->len, .name.name = name->name, }; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_REMOVE], .rpc_argp = &arg, }; int status; dprintk("NFS call remove %s\n", name->name); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_mark_for_revalidate(dir); dprintk("NFS reply remove: %d\n", status); return status; } static void nfs_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) { msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE]; } static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir) { nfs_mark_for_revalidate(dir); return 1; } static void nfs_proc_rename_setup(struct rpc_message *msg, struct inode *dir) { msg->rpc_proc = &nfs_procedures[NFSPROC_RENAME]; } static int nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir, struct inode *new_dir) { nfs_mark_for_revalidate(old_dir); nfs_mark_for_revalidate(new_dir); return 1; } static int nfs_proc_rename(struct inode *old_dir, struct qstr *old_name, struct inode *new_dir, struct qstr *new_name) { struct nfs_renameargs arg = { .old_dir = NFS_FH(old_dir), .old_name = old_name, .new_dir = NFS_FH(new_dir), .new_name = new_name, }; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_RENAME], .rpc_argp = &arg, }; int status; dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); nfs_mark_for_revalidate(old_dir); nfs_mark_for_revalidate(new_dir); dprintk("NFS reply rename: %d\n", status); return status; } static int nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) { struct nfs_linkargs arg = { .fromfh = NFS_FH(inode), .tofh = NFS_FH(dir), .toname = name->name, .tolen = name->len }; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_LINK], .rpc_argp = &arg, }; int status; dprintk("NFS call link %s\n", name->name); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); nfs_mark_for_revalidate(inode); nfs_mark_for_revalidate(dir); dprintk("NFS reply link: %d\n", status); return status; } static int nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, unsigned int len, struct iattr *sattr) { struct nfs_fh fhandle; struct nfs_fattr fattr; struct nfs_symlinkargs arg = { .fromfh = NFS_FH(dir), .fromname = dentry->d_name.name, .fromlen = dentry->d_name.len, .pages = &page, .pathlen = len, .sattr = sattr }; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_SYMLINK], .rpc_argp = &arg, }; int status; if (len > NFS2_MAXPATHLEN) return -ENAMETOOLONG; dprintk("NFS call symlink %s\n", dentry->d_name.name); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_mark_for_revalidate(dir); /* * V2 SYMLINK requests don't return any attributes. Setting the * filehandle size to zero indicates to nfs_instantiate that it * should fill in the data with a LOOKUP call on the wire. */ if (status == 0) { nfs_fattr_init(&fattr); fhandle.size = 0; status = nfs_instantiate(dentry, &fhandle, &fattr); } dprintk("NFS reply symlink: %d\n", status); return status; } static int nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) { struct nfs_fh fhandle; struct nfs_fattr fattr; struct nfs_createargs arg = { .fh = NFS_FH(dir), .name = dentry->d_name.name, .len = dentry->d_name.len, .sattr = sattr }; struct nfs_diropok res = { .fh = &fhandle, .fattr = &fattr }; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_MKDIR], .rpc_argp = &arg, .rpc_resp = &res, }; int status; dprintk("NFS call mkdir %s\n", dentry->d_name.name); nfs_fattr_init(&fattr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_mark_for_revalidate(dir); if (status == 0) status = nfs_instantiate(dentry, &fhandle, &fattr); dprintk("NFS reply mkdir: %d\n", status); return status; } static int nfs_proc_rmdir(struct inode *dir, struct qstr *name) { struct nfs_diropargs arg = { .fh = NFS_FH(dir), .name = name->name, .len = name->len }; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_RMDIR], .rpc_argp = &arg, }; int status; dprintk("NFS call rmdir %s\n", name->name); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_mark_for_revalidate(dir); dprintk("NFS reply rmdir: %d\n", status); return status; } /* * The READDIR implementation is somewhat hackish - we pass a temporary * buffer to the encode function, which installs it in the receive * the receive iovec. The decode function just parses the reply to make * sure it is syntactically correct; the entries itself are decoded * from nfs_readdir by calling the decode_entry function directly. */ static int nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, u64 cookie, struct page *page, unsigned int count, int plus) { struct inode *dir = dentry->d_inode; struct nfs_readdirargs arg = { .fh = NFS_FH(dir), .cookie = cookie, .count = count, .pages = &page, }; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_READDIR], .rpc_argp = &arg, .rpc_cred = cred, }; int status; lock_kernel(); dprintk("NFS call readdir %d\n", (unsigned int)cookie); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_invalidate_atime(dir); dprintk("NFS reply readdir: %d\n", status); unlock_kernel(); return status; } static int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *stat) { struct nfs2_fsstat fsinfo; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_STATFS], .rpc_argp = fhandle, .rpc_resp = &fsinfo, }; int status; dprintk("NFS call statfs\n"); nfs_fattr_init(stat->fattr); status = rpc_call_sync(server->client, &msg, 0); dprintk("NFS reply statfs: %d\n", status); if (status) goto out; stat->tbytes = (u64)fsinfo.blocks * fsinfo.bsize; stat->fbytes = (u64)fsinfo.bfree * fsinfo.bsize; stat->abytes = (u64)fsinfo.bavail * fsinfo.bsize; stat->tfiles = 0; stat->ffiles = 0; stat->afiles = 0; out: return status; } static int nfs_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info) { struct nfs2_fsstat fsinfo; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_STATFS], .rpc_argp = fhandle, .rpc_resp = &fsinfo, }; int status; dprintk("NFS call fsinfo\n"); nfs_fattr_init(info->fattr); status = rpc_call_sync(server->client, &msg, 0); dprintk("NFS reply fsinfo: %d\n", status); if (status) goto out; info->rtmax = NFS_MAXDATA; info->rtpref = fsinfo.tsize; info->rtmult = fsinfo.bsize; info->wtmax = NFS_MAXDATA; info->wtpref = fsinfo.tsize; info->wtmult = fsinfo.bsize; info->dtpref = fsinfo.tsize; info->maxfilesize = 0x7FFFFFFF; info->lease_time = 0; out: return status; } static int nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_pathconf *info) { info->max_link = 0; info->max_namelen = NFS2_MAXNAMLEN; return 0; } static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data) { nfs_invalidate_atime(data->inode); if (task->tk_status >= 0) { nfs_refresh_inode(data->inode, data->res.fattr); /* Emulate the eof flag, which isn't normally needed in NFSv2 * as it is guaranteed to always return the file attributes */ if (data->args.offset + data->args.count >= data->res.fattr->size) data->res.eof = 1; } return 0; } static void nfs_proc_read_setup(struct nfs_read_data *data) { struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_READ], .rpc_argp = &data->args, .rpc_resp = &data->res, .rpc_cred = data->cred, }; rpc_call_setup(&data->task, &msg, 0); } static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) { if (task->tk_status >= 0) nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr); return 0; } static void nfs_proc_write_setup(struct nfs_write_data *data, int how) { struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_WRITE], .rpc_argp = &data->args, .rpc_resp = &data->res, .rpc_cred = data->cred, }; /* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */ data->args.stable = NFS_FILE_SYNC; /* Finalize the task. */ rpc_call_setup(&data->task, &msg, 0); } static void nfs_proc_commit_setup(struct nfs_write_data *data, int how) { BUG(); } static int nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl) { return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl); } const struct nfs_rpc_ops nfs_v2_clientops = { .version = 2, /* protocol version */ .dentry_ops = &nfs_dentry_operations, .dir_inode_ops = &nfs_dir_inode_operations, .file_inode_ops = &nfs_file_inode_operations, .getroot = nfs_proc_get_root, .getattr = nfs_proc_getattr, .setattr = nfs_proc_setattr, .lookup = nfs_proc_lookup, .access = NULL, /* access */ .readlink = nfs_proc_readlink, .read = nfs_proc_read, .write = nfs_proc_write, .commit = NULL, /* commit */ .create = nfs_proc_create, .remove = nfs_proc_remove, .unlink_setup = nfs_proc_unlink_setup, .unlink_done = nfs_proc_unlink_done, .rename = nfs_proc_rename, .rename_setup = nfs_proc_rename_setup, .rename_done = nfs_proc_rename_done, .link = nfs_proc_link, .symlink = nfs_proc_symlink, .mkdir = nfs_proc_mkdir, .rmdir = nfs_proc_rmdir, .readdir = nfs_proc_readdir, .mknod = nfs_proc_mknod, .statfs = nfs_proc_statfs, .fsinfo = nfs_proc_fsinfo, .pathconf = nfs_proc_pathconf, .decode_dirent = nfs_decode_dirent, .read_setup = nfs_proc_read_setup, .read_done = nfs_read_done, .write_setup = nfs_proc_write_setup, .write_done = nfs_write_done, .commit_setup = nfs_proc_commit_setup, .file_open = nfs_open, .file_release = nfs_release, .lock = nfs_proc_lock, .close_context = nfs_close_context, };
asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3) { struct file *filp; struct inode *ino; struct strbuf __user *ctlptr; struct strbuf __user *datptr; struct strbuf ctl, dat; int __user *flgptr; int flags; int error = -EBADF; struct fdtable *fdt; SOLD("entry"); lock_kernel(); if(fd >= NR_OPEN) goto out; fdt = files_fdtable(current->files); filp = fdt->fd[fd]; if(!filp) goto out; ino = filp->f_path.dentry->d_inode; if (!ino || !S_ISSOCK(ino->i_mode)) goto out; ctlptr = (struct strbuf __user *)A(arg1); datptr = (struct strbuf __user *)A(arg2); flgptr = (int __user *)A(arg3); error = -EFAULT; if (ctlptr) { if (copy_from_user(&ctl,ctlptr,sizeof(struct strbuf)) || put_user(-1,&ctlptr->len)) goto out; } else ctl.maxlen = -1; if (datptr) { if (copy_from_user(&dat,datptr,sizeof(struct strbuf)) || put_user(-1,&datptr->len)) goto out; } else dat.maxlen = -1; if (get_user(flags,flgptr)) goto out; switch (flags) { case 0: case MSG_HIPRI: case MSG_ANY: case MSG_BAND: break; default: error = -EINVAL; goto out; } error = timod_getmsg(fd,A(ctl.buf),ctl.maxlen,&ctlptr->len, A(dat.buf),dat.maxlen,&datptr->len,&flags); if (!error && put_user(flags,flgptr)) error = -EFAULT; out: unlock_kernel(); SOLD("done"); return error; }
static int nilfs_remount(struct super_block *sb, int *flags, char *data) { struct nilfs_sb_info *sbi = NILFS_SB(sb); struct the_nilfs *nilfs = sbi->s_nilfs; unsigned long old_sb_flags; struct nilfs_mount_options old_opts; int was_snapshot, err; lock_kernel(); down_write(&nilfs->ns_super_sem); old_sb_flags = sb->s_flags; old_opts.mount_opt = sbi->s_mount_opt; old_opts.snapshot_cno = sbi->s_snapshot_cno; was_snapshot = nilfs_test_opt(sbi, SNAPSHOT); if (!parse_options(data, sb, 1)) { err = -EINVAL; goto restore_opts; } sb->s_flags = (sb->s_flags & ~MS_POSIXACL); err = -EINVAL; if (was_snapshot && !(*flags & MS_RDONLY)) { printk(KERN_ERR "NILFS (device %s): cannot remount snapshot " "read/write.\n", sb->s_id); goto restore_opts; } if (!nilfs_valid_fs(nilfs)) { printk(KERN_WARNING "NILFS (device %s): couldn't " "remount because the filesystem is in an " "incomplete recovery state.\n", sb->s_id); goto restore_opts; } if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) goto out; if (*flags & MS_RDONLY) { /* Shutting down the segment constructor */ nilfs_detach_segment_constructor(sbi); sb->s_flags |= MS_RDONLY; /* * Remounting a valid RW partition RDONLY, so set * the RDONLY flag and then mark the partition as valid again. */ down_write(&nilfs->ns_sem); nilfs_cleanup_super(sbi); up_write(&nilfs->ns_sem); } else { __u64 features; /* * Mounting a RDONLY partition read-write, so reread and * store the current valid flag. (It may have been changed * by fsck since we originally mounted the partition.) */ down_read(&nilfs->ns_sem); features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) & ~NILFS_FEATURE_COMPAT_RO_SUPP; up_read(&nilfs->ns_sem); if (features) { printk(KERN_WARNING "NILFS (device %s): couldn't " "remount RDWR because of unsupported optional " "features (%llx)\n", sb->s_id, (unsigned long long)features); err = -EROFS; goto restore_opts; } sb->s_flags &= ~MS_RDONLY; err = nilfs_attach_segment_constructor(sbi); if (err) goto restore_opts; down_write(&nilfs->ns_sem); nilfs_setup_super(sbi); up_write(&nilfs->ns_sem); } out: up_write(&nilfs->ns_super_sem); unlock_kernel(); return 0; restore_opts: sb->s_flags = old_sb_flags; sbi->s_mount_opt = old_opts.mount_opt; sbi->s_snapshot_cno = old_opts.snapshot_cno; up_write(&nilfs->ns_super_sem); unlock_kernel(); return err; }
/** * iowarrior_ioctl */ static long iowarrior_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct iowarrior *dev = NULL; __u8 *buffer; __u8 __user *user_buffer; int retval; int io_res; /* checks for bytes read/written and copy_to/from_user results */ dev = (struct iowarrior *)file->private_data; if (dev == NULL) { return -ENODEV; } buffer = kzalloc(dev->report_size, GFP_KERNEL); if (!buffer) return -ENOMEM; /* lock this object */ lock_kernel(); mutex_lock(&dev->mutex); /* verify that the device wasn't unplugged */ if (!dev->present) { retval = -ENODEV; goto error_out; } dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __func__, dev->minor, cmd, arg); retval = 0; io_res = 0; switch (cmd) { case IOW_WRITE: if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 || dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 || dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 || dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) { user_buffer = (__u8 __user *)arg; io_res = copy_from_user(buffer, user_buffer, dev->report_size); if (io_res) { retval = -EFAULT; } else { io_res = usb_set_report(dev->interface, 2, 0, buffer, dev->report_size); if (io_res < 0) retval = io_res; } } else { retval = -EINVAL; dev_err(&dev->interface->dev, "ioctl 'IOW_WRITE' is not supported for product=0x%x.\n", dev->product_id); } break; case IOW_READ: user_buffer = (__u8 __user *)arg; io_res = usb_get_report(dev->udev, dev->interface->cur_altsetting, 1, 0, buffer, dev->report_size); if (io_res < 0) retval = io_res; else { io_res = copy_to_user(user_buffer, buffer, dev->report_size); if (io_res < 0) retval = -EFAULT; } break; case IOW_GETINFO: { /* Report available information for the device */ struct iowarrior_info info; /* needed for power consumption */ struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc; /* directly from the descriptor */ info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); info.product = dev->product_id; info.revision = le16_to_cpu(dev->udev->descriptor.bcdDevice); /* 0==UNKNOWN, 1==LOW(usb1.1) ,2=FULL(usb1.1), 3=HIGH(usb2.0) */ info.speed = le16_to_cpu(dev->udev->speed); info.if_num = dev->interface->cur_altsetting->desc.bInterfaceNumber; info.report_size = dev->report_size; /* serial number string has been read earlier 8 chars or empty string */ memcpy(info.serial, dev->chip_serial, sizeof(dev->chip_serial)); if (cfg_descriptor == NULL) { info.power = -1; /* no information available */ } else { /* the MaxPower is stored in units of 2mA to make it fit into a byte-value */ info.power = cfg_descriptor->bMaxPower * 2; } io_res = copy_to_user((struct iowarrior_info __user *)arg, &info, sizeof(struct iowarrior_info)); if (io_res < 0) retval = -EFAULT; break; } default: /* return that we did not understand this ioctl call */ retval = -ENOTTY; break; } error_out: /* unlock the device */ mutex_unlock(&dev->mutex); unlock_kernel(); kfree(buffer); return retval; }
asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; unsigned long tmp; int ret; lock_kernel(); ret = -EPERM; if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; ret = security_ptrace(current->parent, current); if (ret) goto out; /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; ret = 0; goto out; } ret = -ESRCH; read_lock(&tasklist_lock); child = find_task_by_pid(pid); if (child) get_task_struct(child); read_unlock(&tasklist_lock); if (!child) goto out; ret = -EPERM; if (pid == 1) /* you may not mess with init */ goto out_tsk; if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); goto out_tsk; } ret = ptrace_check_attach(child, request == PTRACE_KILL); if (ret < 0) goto out_tsk; switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { int copied; ret = -EIO; if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0) break; copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); if (copied != sizeof(tmp)) break; ret = put_user(tmp,(unsigned long *) data); break; } /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { tmp = 0; ret = -EIO; if ((addr & 3) || addr < 0) break; ret = 0; switch (addr >> 2) { case 0 ... PT__END - 1: tmp = get_reg(child, addr >> 2); break; case PT__END + 0: tmp = child->mm->end_code - child->mm->start_code; break; case PT__END + 1: tmp = child->mm->end_data - child->mm->start_data; break; case PT__END + 2: tmp = child->mm->start_stack - child->mm->start_brk; break; case PT__END + 3: tmp = child->mm->start_code; break; case PT__END + 4: tmp = child->mm->start_stack; break; default: ret = -EIO; break; } if (ret == 0) ret = put_user(tmp, (unsigned long *) data); break; } /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: ret = -EIO; if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0) break; if (access_process_vm(child, addr, &data, sizeof(data), 1) != sizeof(data)) break; ret = 0; break; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ ret = -EIO; if ((addr & 3) || addr < 0) break; ret = 0; switch (addr >> 2) { case 0 ... PT__END-1: ret = put_reg(child, addr >> 2, data); break; default: ret = -EIO; break; } break; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: /* restart after signal. */ ret = -EIO; if (!valid_signal(data)) break; if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; ptrace_disable(child); wake_up_process(child); ret = 0; break; /* make the child exit. Best I can do is send it a sigkill. * perhaps it should be put in the status that it wants to * exit. */ case PTRACE_KILL: ret = 0; if (child->exit_state == EXIT_ZOMBIE) /* already dead */ break; child->exit_code = SIGKILL; clear_tsk_thread_flag(child, TIF_SINGLESTEP); ptrace_disable(child); wake_up_process(child); break; case PTRACE_SINGLESTEP: /* set the trap flag. */ ret = -EIO; if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); ptrace_enable(child); child->exit_code = data; wake_up_process(child); ret = 0; break; case PTRACE_DETACH: /* detach a process that was attached. */ ret = ptrace_detach(child, data); break; case PTRACE_GETREGS: { /* Get all integer regs from the child. */ int i; for (i = 0; i < PT__GPEND; i++) { tmp = get_reg(child, i); if (put_user(tmp, (unsigned long *) data)) { ret = -EFAULT; break; } data += sizeof(long); } ret = 0; break; } case PTRACE_SETREGS: { /* Set all integer regs in the child. */ int i; for (i = 0; i < PT__GPEND; i++) { if (get_user(tmp, (unsigned long *) data)) { ret = -EFAULT; break; } put_reg(child, i, tmp); data += sizeof(long); } ret = 0; break; } case PTRACE_GETFPREGS: { /* Get the child FP/Media state. */ ret = 0; if (copy_to_user((void *) data, &child->thread.user->f, sizeof(child->thread.user->f))) ret = -EFAULT; break; } case PTRACE_SETFPREGS: { /* Set the child FP/Media state. */ ret = 0; if (copy_from_user(&child->thread.user->f, (void *) data, sizeof(child->thread.user->f))) ret = -EFAULT; break; } case PTRACE_GETFDPIC: tmp = 0; switch (addr) { case PTRACE_GETFDPIC_EXEC: tmp = child->mm->context.exec_fdpic_loadmap; break; case PTRACE_GETFDPIC_INTERP: tmp = child->mm->context.interp_fdpic_loadmap; break; default: break; } ret = 0; if (put_user(tmp, (unsigned long *) data)) { ret = -EFAULT; break; } break; default: ret = -EIO; break; } out_tsk: put_task_struct(child); out: unlock_kernel(); return ret; }
static int nfs_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_diropargs arg = { .fh = NFS_FH(dir), .name = name->name, .len = name->len }; struct nfs_diropok res = { .fh = fhandle, .fattr = fattr }; int status; dprintk("NFS call lookup %s\n", name->name); fattr->valid = 0; status = rpc_call(NFS_CLIENT(dir), NFSPROC_LOOKUP, &arg, &res, 0); dprintk("NFS reply lookup: %d\n", status); return status; } static int nfs_proc_readlink(struct inode *inode, struct page *page, unsigned int pgbase, unsigned int pglen) { struct nfs_readlinkargs args = { .fh = NFS_FH(inode), .pgbase = pgbase, .pglen = pglen, .pages = &page }; int status; dprintk("NFS call readlink\n"); status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK, &args, NULL, 0); dprintk("NFS reply readlink: %d\n", status); return status; } static int nfs_proc_read(struct nfs_read_data *rdata) { int flags = rdata->flags; struct inode * inode = rdata->inode; struct nfs_fattr * fattr = rdata->res.fattr; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_READ], .rpc_argp = &rdata->args, .rpc_resp = &rdata->res, .rpc_cred = rdata->cred, }; int status; dprintk("NFS call read %d @ %Ld\n", rdata->args.count, (long long) rdata->args.offset); fattr->valid = 0; status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); if (status >= 0) { nfs_refresh_inode(inode, fattr); /* Emulate the eof flag, which isn't normally needed in NFSv2 * as it is guaranteed to always return the file attributes */ if (rdata->args.offset + rdata->args.count >= fattr->size) rdata->res.eof = 1; } dprintk("NFS reply read: %d\n", status); return status; } static int nfs_proc_write(struct nfs_write_data *wdata) { int flags = wdata->flags; struct inode * inode = wdata->inode; struct nfs_fattr * fattr = wdata->res.fattr; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_WRITE], .rpc_argp = &wdata->args, .rpc_resp = &wdata->res, .rpc_cred = wdata->cred, }; int status; dprintk("NFS call write %d @ %Ld\n", wdata->args.count, (long long) wdata->args.offset); fattr->valid = 0; status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); if (status >= 0) { nfs_refresh_inode(inode, fattr); wdata->res.count = wdata->args.count; wdata->verf.committed = NFS_FILE_SYNC; } dprintk("NFS reply write: %d\n", status); return status < 0? status : wdata->res.count; } static struct inode * nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags) { struct nfs_fh fhandle; struct nfs_fattr fattr; struct nfs_createargs arg = { .fh = NFS_FH(dir), .name = dentry->d_name.name, .len = dentry->d_name.len, .sattr = sattr }; struct nfs_diropok res = { .fh = &fhandle, .fattr = &fattr }; int status; fattr.valid = 0; dprintk("NFS call create %s\n", dentry->d_name.name); status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); dprintk("NFS reply create: %d\n", status); if (status == 0) { struct inode *inode; inode = nfs_fhget(dir->i_sb, &fhandle, &fattr); if (inode) return inode; status = -ENOMEM; } return ERR_PTR(status); } /* * In NFSv2, mknod is grafted onto the create call. */ static int nfs_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr, dev_t rdev, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_createargs arg = { .fh = NFS_FH(dir), .name = name->name, .len = name->len, .sattr = sattr }; struct nfs_diropok res = { .fh = fhandle, .fattr = fattr }; int status, mode; dprintk("NFS call mknod %s\n", name->name); mode = sattr->ia_mode; if (S_ISFIFO(mode)) { sattr->ia_mode = (mode & ~S_IFMT) | S_IFCHR; sattr->ia_valid &= ~ATTR_SIZE; } else if (S_ISCHR(mode) || S_ISBLK(mode)) { sattr->ia_valid |= ATTR_SIZE; sattr->ia_size = new_encode_dev(rdev);/* get out your barf bag */ } fattr->valid = 0; status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); if (status == -EINVAL && S_ISFIFO(mode)) { sattr->ia_mode = mode; fattr->valid = 0; status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); } dprintk("NFS reply mknod: %d\n", status); return status; } static int nfs_proc_remove(struct inode *dir, struct qstr *name) { struct nfs_diropargs arg = { .fh = NFS_FH(dir), .name = name->name, .len = name->len }; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_REMOVE], .rpc_argp = &arg, .rpc_resp = NULL, .rpc_cred = NULL }; int status; dprintk("NFS call remove %s\n", name->name); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); dprintk("NFS reply remove: %d\n", status); return status; } static int nfs_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) { struct nfs_diropargs *arg; arg = (struct nfs_diropargs *)kmalloc(sizeof(*arg), GFP_KERNEL); if (!arg) return -ENOMEM; arg->fh = NFS_FH(dir->d_inode); arg->name = name->name; arg->len = name->len; msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE]; msg->rpc_argp = arg; return 0; } static int nfs_proc_unlink_done(struct dentry *dir, struct rpc_task *task) { struct rpc_message *msg = &task->tk_msg; if (msg->rpc_argp) kfree(msg->rpc_argp); return 0; } static int nfs_proc_rename(struct inode *old_dir, struct qstr *old_name, struct inode *new_dir, struct qstr *new_name) { struct nfs_renameargs arg = { .fromfh = NFS_FH(old_dir), .fromname = old_name->name, .fromlen = old_name->len, .tofh = NFS_FH(new_dir), .toname = new_name->name, .tolen = new_name->len }; int status; dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); status = rpc_call(NFS_CLIENT(old_dir), NFSPROC_RENAME, &arg, NULL, 0); dprintk("NFS reply rename: %d\n", status); return status; } static int nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) { struct nfs_linkargs arg = { .fromfh = NFS_FH(inode), .tofh = NFS_FH(dir), .toname = name->name, .tolen = name->len }; int status; dprintk("NFS call link %s\n", name->name); status = rpc_call(NFS_CLIENT(inode), NFSPROC_LINK, &arg, NULL, 0); dprintk("NFS reply link: %d\n", status); return status; } static int nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_symlinkargs arg = { .fromfh = NFS_FH(dir), .fromname = name->name, .fromlen = name->len, .topath = path->name, .tolen = path->len, .sattr = sattr }; int status; if (path->len > NFS2_MAXPATHLEN) return -ENAMETOOLONG; dprintk("NFS call symlink %s -> %s\n", name->name, path->name); fattr->valid = 0; fhandle->size = 0; status = rpc_call(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, 0); dprintk("NFS reply symlink: %d\n", status); return status; } static int nfs_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_createargs arg = { .fh = NFS_FH(dir), .name = name->name, .len = name->len, .sattr = sattr }; struct nfs_diropok res = { .fh = fhandle, .fattr = fattr }; int status; dprintk("NFS call mkdir %s\n", name->name); fattr->valid = 0; status = rpc_call(NFS_CLIENT(dir), NFSPROC_MKDIR, &arg, &res, 0); dprintk("NFS reply mkdir: %d\n", status); return status; } static int nfs_proc_rmdir(struct inode *dir, struct qstr *name) { struct nfs_diropargs arg = { .fh = NFS_FH(dir), .name = name->name, .len = name->len }; int status; dprintk("NFS call rmdir %s\n", name->name); status = rpc_call(NFS_CLIENT(dir), NFSPROC_RMDIR, &arg, NULL, 0); dprintk("NFS reply rmdir: %d\n", status); return status; } /* * The READDIR implementation is somewhat hackish - we pass a temporary * buffer to the encode function, which installs it in the receive * the receive iovec. The decode function just parses the reply to make * sure it is syntactically correct; the entries itself are decoded * from nfs_readdir by calling the decode_entry function directly. */ static int nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, u64 cookie, struct page *page, unsigned int count, int plus) { struct inode *dir = dentry->d_inode; struct nfs_readdirargs arg = { .fh = NFS_FH(dir), .cookie = cookie, .count = count, .pages = &page }; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_READDIR], .rpc_argp = &arg, .rpc_resp = NULL, .rpc_cred = cred }; int status; lock_kernel(); dprintk("NFS call readdir %d\n", (unsigned int)cookie); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); dprintk("NFS reply readdir: %d\n", status); unlock_kernel(); return status; } static int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *stat) { struct nfs2_fsstat fsinfo; int status; dprintk("NFS call statfs\n"); stat->fattr->valid = 0; status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &fsinfo, 0); dprintk("NFS reply statfs: %d\n", status); if (status) goto out; stat->tbytes = (u64)fsinfo.blocks * fsinfo.bsize; stat->fbytes = (u64)fsinfo.bfree * fsinfo.bsize; stat->abytes = (u64)fsinfo.bavail * fsinfo.bsize; stat->tfiles = 0; stat->ffiles = 0; stat->afiles = 0; out: return status; } static int nfs_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info) { struct nfs2_fsstat fsinfo; int status; dprintk("NFS call fsinfo\n"); info->fattr->valid = 0; status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &fsinfo, 0); dprintk("NFS reply fsinfo: %d\n", status); if (status) goto out; info->rtmax = NFS_MAXDATA; info->rtpref = fsinfo.tsize; info->rtmult = fsinfo.bsize; info->wtmax = NFS_MAXDATA; info->wtpref = fsinfo.tsize; info->wtmult = fsinfo.bsize; info->dtpref = fsinfo.tsize; info->maxfilesize = 0x7FFFFFFF; info->lease_time = 0; out: return status; } static int nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_pathconf *info) { info->max_link = 0; info->max_namelen = NFS2_MAXNAMLEN; return 0; } extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int); static void nfs_read_done(struct rpc_task *task) { struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata; if (task->tk_status >= 0) { nfs_refresh_inode(data->inode, data->res.fattr); /* Emulate the eof flag, which isn't normally needed in NFSv2 * as it is guaranteed to always return the file attributes */ if (data->args.offset + data->args.count >= data->res.fattr->size) data->res.eof = 1; } nfs_readpage_result(task); } static void nfs_proc_read_setup(struct nfs_read_data *data) { struct rpc_task *task = &data->task; struct inode *inode = data->inode; int flags; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_READ], .rpc_argp = &data->args, .rpc_resp = &data->res, .rpc_cred = data->cred, }; /* N.B. Do we need to test? Never called for swapfile inode */ flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs_read_done, flags); rpc_call_setup(task, &msg, 0); } static void nfs_write_done(struct rpc_task *task) { struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; if (task->tk_status >= 0) nfs_refresh_inode(data->inode, data->res.fattr); nfs_writeback_done(task); } static void nfs_proc_write_setup(struct nfs_write_data *data, int how) { struct rpc_task *task = &data->task; struct inode *inode = data->inode; int flags; struct rpc_message msg = { .rpc_proc = &nfs_procedures[NFSPROC_WRITE], .rpc_argp = &data->args, .rpc_resp = &data->res, .rpc_cred = data->cred, }; /* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */ data->args.stable = NFS_FILE_SYNC; /* Set the initial flags for the task. */ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs_write_done, flags); rpc_call_setup(task, &msg, 0); } static void nfs_proc_commit_setup(struct nfs_write_data *data, int how) { BUG(); } static int nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl) { return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl); } struct nfs_rpc_ops nfs_v2_clientops = { .version = 2, /* protocol version */ .dentry_ops = &nfs_dentry_operations, .dir_inode_ops = &nfs_dir_inode_operations, .getroot = nfs_proc_get_root, .getattr = nfs_proc_getattr, .setattr = nfs_proc_setattr, .lookup = nfs_proc_lookup, .access = NULL, /* access */ .readlink = nfs_proc_readlink, .read = nfs_proc_read, .write = nfs_proc_write, .commit = NULL, /* commit */ .create = nfs_proc_create, .remove = nfs_proc_remove, .unlink_setup = nfs_proc_unlink_setup, .unlink_done = nfs_proc_unlink_done, .rename = nfs_proc_rename, .link = nfs_proc_link, .symlink = nfs_proc_symlink, .mkdir = nfs_proc_mkdir, .rmdir = nfs_proc_rmdir, .readdir = nfs_proc_readdir, .mknod = nfs_proc_mknod, .statfs = nfs_proc_statfs, .fsinfo = nfs_proc_fsinfo, .pathconf = nfs_proc_pathconf, .decode_dirent = nfs_decode_dirent, .read_setup = nfs_proc_read_setup, .write_setup = nfs_proc_write_setup, .commit_setup = nfs_proc_commit_setup, .file_open = nfs_open, .file_release = nfs_release, .lock = nfs_proc_lock, };
/* * sys_acct() is the only system call needed to implement process * accounting. It takes the name of the file where accounting records * should be written. If the filename is NULL, accounting will be * shutdown. */ asmlinkage long sys_acct(const char *name) { struct file *file = NULL, *old_acct = NULL; char *tmp; int error; if (!capable(CAP_SYS_PACCT)) return -EPERM; if (name) { tmp = getname(name); error = PTR_ERR(tmp); if (IS_ERR(tmp)) goto out; /* Difference from BSD - they don't do O_APPEND */ file = filp_open(tmp, O_WRONLY|O_APPEND, 0); putname(tmp); if (IS_ERR(file)) { error = PTR_ERR(file); goto out; } error = -EACCES; if (!S_ISREG(file->f_dentry->d_inode->i_mode)) goto out_err; error = -EIO; if (!file->f_op->write) goto out_err; } if ((error = security_acct(file))) goto out_err; error = 0; lock_kernel(); if (acct_file) { old_acct = acct_file; del_timer(&acct_timer); acct_active = 0; acct_needcheck = 0; acct_file = NULL; } if (name) { acct_file = file; acct_needcheck = 0; acct_active = 1; /* It's been deleted if it was used before so this is safe */ init_timer(&acct_timer); acct_timer.function = acct_timeout; acct_timer.expires = jiffies + ACCT_TIMEOUT*HZ; add_timer(&acct_timer); } unlock_kernel(); if (old_acct) { do_acct_process(0,old_acct); filp_close(old_acct, NULL); } out: return error; out_err: if (file) filp_close(file, NULL); goto out; }
/* The file offset position is now represented as a true offset into the * page cache as is the case in most of the other filesystems. */ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct dentry *dentry = filp->f_dentry; struct inode *inode = dentry->d_inode; nfs_readdir_descriptor_t my_desc, *desc = &my_desc; struct nfs_entry my_entry; struct nfs_fh fh; struct nfs_fattr fattr; long res; lock_kernel(); res = nfs_revalidate_inode(NFS_SERVER(inode), inode); if (res < 0) { unlock_kernel(); return res; } /* * filp->f_pos points to the file offset in the page cache. * but if the cache has meanwhile been zapped, we need to * read from the last dirent to revalidate f_pos * itself. */ memset(desc, 0, sizeof(*desc)); desc->file = filp; desc->target = filp->f_pos; desc->decode = NFS_PROTO(inode)->decode_dirent; desc->plus = NFS_USE_READDIRPLUS(inode); my_entry.cookie = my_entry.prev_cookie = 0; my_entry.eof = 0; my_entry.fh = &fh; my_entry.fattr = &fattr; desc->entry = &my_entry; while(!desc->entry->eof) { res = readdir_search_pagecache(desc); if (res == -EBADCOOKIE) { /* This means either end of directory */ if (desc->entry->cookie != desc->target) { /* Or that the server has 'lost' a cookie */ res = uncached_readdir(desc, dirent, filldir); if (res >= 0) continue; } res = 0; break; } if (res == -ETOOSMALL && desc->plus) { NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS; nfs_zap_caches(inode); desc->plus = 0; desc->entry->eof = 0; continue; } if (res < 0) break; res = nfs_do_filldir(desc, dirent, filldir); if (res < 0) { res = 0; break; } } unlock_kernel(); if (desc->error < 0) return desc->error; if (res < 0) return res; return 0; }
void __sysonly gdc_set_myself_window(gui_window_t * w) { lock_kernel(); myself_window = w; unlock_kernel(); }
/* * This is called every time the dcache has a lookup hit, * and we should check whether we can really trust that * lookup. * * NOTE! The hit can be a negative hit too, don't assume * we have an inode! * * If the parent directory is seen to have changed, we throw out the * cached dentry and do a new lookup. */ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) { struct inode *dir; struct inode *inode; struct dentry *parent; int error; struct nfs_fh fhandle; struct nfs_fattr fattr; unsigned long verifier; int isopen = 0; parent = dget_parent(dentry); lock_kernel(); dir = parent->d_inode; inode = dentry->d_inode; if (nd && !(nd->flags & LOOKUP_CONTINUE) && (nd->flags & LOOKUP_OPEN)) isopen = 1; if (!inode) { if (nfs_neg_need_reval(dir, dentry, nd)) goto out_bad; goto out_valid; } if (is_bad_inode(inode)) { dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n", dentry->d_parent->d_name.name, dentry->d_name.name); goto out_bad; } /* Revalidate parent directory attribute cache */ nfs_revalidate_inode(NFS_SERVER(dir), dir); /* Force a full look up iff the parent directory has changed */ if (nfs_check_verifier(dir, dentry)) { if (nfs_lookup_verify_inode(inode, isopen)) goto out_zap_parent; goto out_valid; } /* * Note: we're not holding inode->i_sem and so may be racing with * operations that change the directory. We therefore save the * change attribute *before* we do the RPC call. */ verifier = nfs_save_change_attribute(dir); error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr); if (!error) { if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0) goto out_bad; if (nfs_lookup_verify_inode(inode, isopen)) goto out_zap_parent; goto out_valid_renew; } if (NFS_STALE(inode)) goto out_bad; error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); if (error) goto out_bad; if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0) goto out_bad; if ((error = nfs_refresh_inode(inode, &fattr)) != 0) goto out_bad; out_valid_renew: nfs_renew_times(dentry); nfs_set_verifier(dentry, verifier); out_valid: unlock_kernel(); dput(parent); return 1; out_zap_parent: nfs_zap_caches(dir); out_bad: NFS_CACHEINV(dir); if (inode && S_ISDIR(inode->i_mode)) { /* Purge readdir caches. */ nfs_zap_caches(inode); /* If we have submounts, don't unhash ! */ if (have_submounts(dentry)) goto out_valid; shrink_dcache_parent(dentry); } d_drop(dentry); unlock_kernel(); dput(parent); return 0; }
static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct inode *inode = filp->f_path.dentry->d_inode; struct buffer_head *bh; struct efs_dir *dirblock; struct efs_dentry *dirslot; efs_ino_t inodenum; efs_block_t block; int slot, namelen; char *nameptr; if (inode->i_size & (EFS_DIRBSIZE-1)) printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n"); lock_kernel(); /* work out where this entry can be found */ block = filp->f_pos >> EFS_DIRBSIZE_BITS; /* each block contains at most 256 slots */ slot = filp->f_pos & 0xff; /* look at all blocks */ while (block < inode->i_blocks) { /* read the dir block */ bh = sb_bread(inode->i_sb, efs_bmap(inode, block)); if (!bh) { printk(KERN_ERR "EFS: readdir(): failed to read dir block %d\n", block); break; } dirblock = (struct efs_dir *) bh->b_data; if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { printk(KERN_ERR "EFS: readdir(): invalid directory block\n"); brelse(bh); break; } while (slot < dirblock->slots) { if (dirblock->space[slot] == 0) { slot++; continue; } dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); inodenum = be32_to_cpu(dirslot->inode); namelen = dirslot->namelen; nameptr = dirslot->name; #ifdef DEBUG printk(KERN_DEBUG "EFS: readdir(): block %d slot %d/%d: inode %u, name \"%s\", namelen %u\n", block, slot, dirblock->slots-1, inodenum, nameptr, namelen); #endif if (namelen > 0) { /* found the next entry */ filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; /* copy filename and data in dirslot */ filldir(dirent, nameptr, namelen, filp->f_pos, inodenum, DT_UNKNOWN); /* sanity check */ if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) { printk(KERN_WARNING "EFS: directory entry %d exceeds directory block\n", slot); slot++; continue; } /* store position of next slot */ if (++slot == dirblock->slots) { slot = 0; block++; } brelse(bh); filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; goto out; } slot++; } brelse(bh); slot = 0; block++; } filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; out: unlock_kernel(); return 0; }
static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) { struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_super_block_third * usb3; unsigned new_mount_opt, ufstype; unsigned flags; lock_kernel(); lock_super(sb); uspi = UFS_SB(sb)->s_uspi; flags = UFS_SB(sb)->s_flags; usb1 = ubh_get_usb_first(uspi); usb3 = ubh_get_usb_third(uspi); /* * Allow the "check" option to be passed as a remount option. * It is not possible to change ufstype option during remount */ ufstype = UFS_SB(sb)->s_mount_opt & UFS_MOUNT_UFSTYPE; new_mount_opt = 0; ufs_set_opt (new_mount_opt, ONERROR_LOCK); if (!ufs_parse_options (data, &new_mount_opt)) { unlock_super(sb); unlock_kernel(); return -EINVAL; } if (!(new_mount_opt & UFS_MOUNT_UFSTYPE)) { new_mount_opt |= ufstype; } else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) { printk("ufstype can't be changed during remount\n"); unlock_super(sb); unlock_kernel(); return -EINVAL; } if ((*mount_flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { UFS_SB(sb)->s_mount_opt = new_mount_opt; unlock_super(sb); unlock_kernel(); return 0; } /* * fs was mouted as rw, remounting ro */ if (*mount_flags & MS_RDONLY) { ufs_put_super_internal(sb); usb1->fs_time = cpu_to_fs32(sb, get_seconds()); if ((flags & UFS_ST_MASK) == UFS_ST_SUN || (flags & UFS_ST_MASK) == UFS_ST_SUNOS || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) ufs_set_fs_state(sb, usb1, usb3, UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); ubh_mark_buffer_dirty (USPI_UBH(uspi)); sb->s_dirt = 0; sb->s_flags |= MS_RDONLY; } else { /* * fs was mounted as ro, remounting rw */ #ifndef CONFIG_UFS_FS_WRITE printk("ufs was compiled with read-only support, " "can't be mounted as read-write\n"); unlock_super(sb); unlock_kernel(); return -EINVAL; #else if (ufstype != UFS_MOUNT_UFSTYPE_SUN && ufstype != UFS_MOUNT_UFSTYPE_SUNOS && ufstype != UFS_MOUNT_UFSTYPE_44BSD && ufstype != UFS_MOUNT_UFSTYPE_SUNx86 && ufstype != UFS_MOUNT_UFSTYPE_UFS2) { printk("this ufstype is read-only supported\n"); unlock_super(sb); unlock_kernel(); return -EINVAL; } if (!ufs_read_cylinder_structures(sb)) { printk("failed during remounting\n"); unlock_super(sb); unlock_kernel(); return -EPERM; } sb->s_flags &= ~MS_RDONLY; #endif } UFS_SB(sb)->s_mount_opt = new_mount_opt; unlock_super(sb); unlock_kernel(); return 0; }
/* * This is the lockd kernel thread */ static void lockd(struct svc_rqst *rqstp) { struct svc_serv *serv = rqstp->rq_server; int err = 0; unsigned long grace_period_expire; /* Lock module and set up kernel thread */ /* lockd_up is waiting for us to startup, so will * be holding a reference to this module, so it * is safe to just claim another reference */ __module_get(THIS_MODULE); lock_kernel(); /* * Let our maker know we're running. */ nlmsvc_pid = current->pid; up(&lockd_start); daemonize("lockd"); /* Process request with signals blocked, but allow SIGKILL. */ allow_signal(SIGKILL); /* kick rpciod */ rpciod_up(); dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); if (!nlm_timeout) nlm_timeout = LOCKD_DFLT_TIMEO; nlmsvc_timeout = nlm_timeout * HZ; grace_period_expire = set_grace_period(); /* * The main request loop. We don't terminate until the last * NFS mount or NFS daemon has gone away, and we've been sent a * signal, or else another process has taken over our job. */ while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) { long timeout = MAX_SCHEDULE_TIMEOUT; if (signalled()) { flush_signals(current); if (nlmsvc_ops) { nlmsvc_invalidate_all(); grace_period_expire = set_grace_period(); } } /* * Retry any blocked locks that have been notified by * the VFS. Don't do this during grace period. * (Theoretically, there shouldn't even be blocked locks * during grace period). */ if (!nlmsvc_grace_period) { timeout = nlmsvc_retry_blocked(); } else if (time_before(grace_period_expire, jiffies)) clear_grace_period(); /* * Find a socket with data available and call its * recvfrom routine. */ err = svc_recv(serv, rqstp, timeout); if (err == -EAGAIN || err == -EINTR) continue; if (err < 0) { printk(KERN_WARNING "lockd: terminating on error %d\n", -err); break; } dprintk("lockd: request from %08x\n", (unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr)); svc_process(serv, rqstp); } /* * Check whether there's a new lockd process before * shutting down the hosts and clearing the slot. */ if (!nlmsvc_pid || current->pid == nlmsvc_pid) { if (nlmsvc_ops) nlmsvc_invalidate_all(); nlm_shutdown_hosts(); nlmsvc_pid = 0; } else printk(KERN_DEBUG "lockd: new process, skipping host shutdown\n"); wake_up(&lockd_exit); /* Exit the RPC thread */ svc_exit_thread(rqstp); /* release rpciod */ rpciod_down(); /* Release module */ unlock_kernel(); module_put_and_exit(0); }
static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { const char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct inode *result = NULL; struct buffer_head *bh; struct fnode *fnode; fnode_secno fno; int r; struct hpfs_dirent dee; int err; if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; lock_kernel(); err = -ENOSPC; fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); if (!fnode) goto bail; memset(&dee, 0, sizeof dee); if (!(mode & 0222)) dee.read_only = 1; dee.archive = 1; dee.hidden = name[0] == '.'; dee.fnode = fno; dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); result = new_inode(dir->i_sb); if (!result) goto bail1; hpfs_init_inode(result); result->i_ino = fno; result->i_mode |= S_IFREG; result->i_mode &= ~0111; result->i_op = &hpfs_file_iops; result->i_fop = &hpfs_file_ops; result->i_nlink = 1; hpfs_decide_conv(result, (char *)name, len); hpfs_i(result)->i_parent_dir = dir->i_ino; result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); result->i_ctime.tv_nsec = 0; result->i_mtime.tv_nsec = 0; result->i_atime.tv_nsec = 0; hpfs_i(result)->i_ea_size = 0; if (dee.read_only) result->i_mode &= ~0222; result->i_blocks = 1; result->i_size = 0; result->i_data.a_ops = &hpfs_aops; hpfs_i(result)->mmu_private = 0; mutex_lock(&hpfs_i(dir)->i_mutex); r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); if (r == 1) goto bail2; if (r == -1) { err = -EEXIST; goto bail2; } fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); fnode->up = dir->i_ino; mark_buffer_dirty(bh); brelse(bh); insert_inode_hash(result); if (result->i_uid != current->fsuid || result->i_gid != current->fsgid || result->i_mode != (mode | S_IFREG)) { result->i_uid = current->fsuid; result->i_gid = current->fsgid; result->i_mode = mode | S_IFREG; hpfs_write_inode_nolock(result); } d_instantiate(dentry, result); mutex_unlock(&hpfs_i(dir)->i_mutex); unlock_kernel(); return 0; bail2: mutex_unlock(&hpfs_i(dir)->i_mutex); iput(result); bail1: brelse(bh); hpfs_free_sectors(dir->i_sb, fno, 1); bail: unlock_kernel(); return err; }
/* * Reboot system call: for obvious reasons only root may call it, * and even root needs to set up some magic numbers in the registers * so that some mistake won't make this reboot the whole machine. * You can also set the meaning of the ctrl-alt-del-key here. * * reboot doesn't sync: do that yourself before calling this. */ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user * arg) { char buffer[256]; /* We only trust the superuser with rebooting the system. */ if (!capable(CAP_SYS_BOOT)) return -EPERM; /* For safety, we require "magic" arguments. */ if (magic1 != LINUX_REBOOT_MAGIC1 || (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A && magic2 != LINUX_REBOOT_MAGIC2B && magic2 != LINUX_REBOOT_MAGIC2C)) return -EINVAL; /* Instead of trying to make the power_off code look like * halt when pm_power_off is not set do it the easy way. */ if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) cmd = LINUX_REBOOT_CMD_HALT; lock_kernel(); switch (cmd) { case LINUX_REBOOT_CMD_RESTART: kernel_restart(NULL); break; case LINUX_REBOOT_CMD_CAD_ON: C_A_D = 1; break; case LINUX_REBOOT_CMD_CAD_OFF: C_A_D = 0; break; case LINUX_REBOOT_CMD_HALT: kernel_halt(); unlock_kernel(); do_exit(0); break; case LINUX_REBOOT_CMD_POWER_OFF: kernel_power_off(); unlock_kernel(); do_exit(0); break; case LINUX_REBOOT_CMD_RESTART2: if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) { unlock_kernel(); return -EFAULT; } buffer[sizeof(buffer) - 1] = '\0'; kernel_restart(buffer); break; case LINUX_REBOOT_CMD_KEXEC: kernel_kexec(); unlock_kernel(); return -EINVAL; #ifdef CONFIG_SOFTWARE_SUSPEND case LINUX_REBOOT_CMD_SW_SUSPEND: { int ret = software_suspend(); unlock_kernel(); return ret; } #endif default: unlock_kernel(); return -EINVAL; } unlock_kernel(); return 0; }
static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink) { const char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct buffer_head *bh; struct fnode *fnode; fnode_secno fno; int r; struct hpfs_dirent dee; struct inode *result; int err; if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; lock_kernel(); if (hpfs_sb(dir->i_sb)->sb_eas < 2) { unlock_kernel(); return -EPERM; } err = -ENOSPC; fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); if (!fnode) goto bail; memset(&dee, 0, sizeof dee); dee.archive = 1; dee.hidden = name[0] == '.'; dee.fnode = fno; dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); result = new_inode(dir->i_sb); if (!result) goto bail1; result->i_ino = fno; hpfs_init_inode(result); hpfs_i(result)->i_parent_dir = dir->i_ino; result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); result->i_ctime.tv_nsec = 0; result->i_mtime.tv_nsec = 0; result->i_atime.tv_nsec = 0; hpfs_i(result)->i_ea_size = 0; result->i_mode = S_IFLNK | 0777; result->i_uid = current->fsuid; result->i_gid = current->fsgid; result->i_blocks = 1; result->i_nlink = 1; result->i_size = strlen(symlink); result->i_op = &page_symlink_inode_operations; result->i_data.a_ops = &hpfs_symlink_aops; mutex_lock(&hpfs_i(dir)->i_mutex); r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); if (r == 1) goto bail2; if (r == -1) { err = -EEXIST; goto bail2; } fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); fnode->up = dir->i_ino; hpfs_set_ea(result, fnode, "SYMLINK", (char *)symlink, strlen(symlink)); mark_buffer_dirty(bh); brelse(bh); insert_inode_hash(result); hpfs_write_inode_nolock(result); d_instantiate(dentry, result); mutex_unlock(&hpfs_i(dir)->i_mutex); unlock_kernel(); return 0; bail2: mutex_unlock(&hpfs_i(dir)->i_mutex); iput(result); bail1: brelse(bh); hpfs_free_sectors(dir->i_sb, fno, 1); bail: unlock_kernel(); return err; }
/* * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to * be given to the mount() call (ie: read-only, no-dev, no-suid etc). * * data is a (void *) that can point to any structure up to * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent * information (or be NULL). * * NOTE! As old versions of mount() didn't use this setup, the flags * have to have a special 16-bit magic number in the high word: * 0xC0ED. If this magic word isn't present, the flags and data info * aren't used, as the syscall assumes we are talking to an older * version that didn't understand them. */ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, unsigned long new_flags, void * data) { struct file_system_type * fstype; struct dentry * dentry = NULL; struct inode * inode = NULL; kdev_t dev; int retval = -EPERM; unsigned long flags = 0; unsigned long page = 0; struct file dummy; /* allows read-write or read-only flag */ lock_kernel(); if (!capable(CAP_SYS_ADMIN)) goto out; if ((new_flags & (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) { retval = copy_mount_options (data, &page); if (retval < 0) goto out; retval = do_remount(dir_name, new_flags & ~MS_MGC_MSK & ~MS_REMOUNT, (char *) page); free_mount_page(page); goto out; } retval = copy_mount_options (type, &page); if (retval < 0) goto out; fstype = get_fs_type((char *) page); free_mount_page(page); retval = -ENODEV; if (!fstype) goto out; memset(&dummy, 0, sizeof(dummy)); if (fstype->fs_flags & FS_REQUIRES_DEV) { dentry = namei(dev_name); retval = PTR_ERR(dentry); if (IS_ERR(dentry)) goto out; inode = dentry->d_inode; retval = -ENOTBLK; if (!S_ISBLK(inode->i_mode)) goto dput_and_out; retval = -EACCES; if (IS_NODEV(inode)) goto dput_and_out; dev = inode->i_rdev; retval = -ENXIO; if (MAJOR(dev) >= MAX_BLKDEV) goto dput_and_out; retval = -ENOTBLK; dummy.f_op = get_blkfops(MAJOR(dev)); if (!dummy.f_op) goto dput_and_out; if (dummy.f_op->open) { dummy.f_dentry = dentry; dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3; retval = dummy.f_op->open(inode, &dummy); if (retval) goto dput_and_out; } } else { retval = -EMFILE; if (!(dev = get_unnamed_dev())) goto out; } page = 0; if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) { flags = new_flags & ~MS_MGC_MSK; retval = copy_mount_options(data, &page); if (retval < 0) goto clean_up; } retval = do_mount(dev, dev_name, dir_name, fstype->name, flags, (void *) page); free_mount_page(page); if (retval) goto clean_up; dput_and_out: dput(dentry); out: unlock_kernel(); return retval; clean_up: if (dummy.f_op) { if (dummy.f_op->release) dummy.f_op->release(inode, NULL); } else put_unnamed_dev(dev); goto dput_and_out; }
static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { char *old_name = (char *)old_dentry->d_name.name; int old_len = old_dentry->d_name.len; char *new_name = (char *)new_dentry->d_name.name; int new_len = new_dentry->d_name.len; struct inode *i = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct quad_buffer_head qbh, qbh1; struct hpfs_dirent *dep, *nde; struct hpfs_dirent de; dnode_secno dno; int r; struct buffer_head *bh; struct fnode *fnode; int err; if ((err = hpfs_chk_name((char *)new_name, &new_len))) return err; err = 0; hpfs_adjust_length((char *)old_name, &old_len); lock_kernel(); /* order doesn't matter, due to VFS exclusion */ mutex_lock(&hpfs_i(i)->i_parent_mutex); if (new_inode) mutex_lock(&hpfs_i(new_inode)->i_parent_mutex); mutex_lock(&hpfs_i(old_dir)->i_mutex); if (new_dir != old_dir) mutex_lock(&hpfs_i(new_dir)->i_mutex); /* Erm? Moving over the empty non-busy directory is perfectly legal */ if (new_inode && S_ISDIR(new_inode->i_mode)) { err = -EINVAL; goto end1; } if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, (char *)old_name, old_len, &dno, &qbh))) { hpfs_error(i->i_sb, "lookup succeeded but map dirent failed"); err = -ENOENT; goto end1; } copy_de(&de, dep); de.hidden = new_name[0] == '.'; if (new_inode) { int r; if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) { if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, (char *)new_name, new_len, NULL, &qbh1))) { clear_nlink(new_inode); copy_de(nde, &de); memcpy(nde->name, new_name, new_len); hpfs_mark_4buffers_dirty(&qbh1); hpfs_brelse4(&qbh1); goto end; } hpfs_error(new_dir->i_sb, "hpfs_rename: could not find dirent"); err = -EFSERROR; goto end1; } err = r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0; goto end1; } if (new_dir == old_dir) hpfs_brelse4(&qbh); hpfs_lock_creation(i->i_sb); if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de, 1))) { hpfs_unlock_creation(i->i_sb); if (r == -1) hpfs_error(new_dir->i_sb, "hpfs_rename: dirent already exists!"); err = r == 1 ? -ENOSPC : -EFSERROR; if (new_dir != old_dir) hpfs_brelse4(&qbh); goto end1; } if (new_dir == old_dir) if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, (char *)old_name, old_len, &dno, &qbh))) { hpfs_unlock_creation(i->i_sb); hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2"); err = -ENOENT; goto end1; } if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 0))) { hpfs_unlock_creation(i->i_sb); hpfs_error(i->i_sb, "hpfs_rename: could not remove dirent"); err = r == 2 ? -ENOSPC : -EFSERROR; goto end1; } hpfs_unlock_creation(i->i_sb); end: hpfs_i(i)->i_parent_dir = new_dir->i_ino; if (S_ISDIR(i->i_mode)) { inc_nlink(new_dir); drop_nlink(old_dir); } if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) { fnode->up = new_dir->i_ino; fnode->len = new_len; memcpy(fnode->name, new_name, new_len>15?15:new_len); if (new_len < 15) memset(&fnode->name[new_len], 0, 15 - new_len); mark_buffer_dirty(bh); brelse(bh); } hpfs_i(i)->i_conv = hpfs_sb(i->i_sb)->sb_conv; hpfs_decide_conv(i, (char *)new_name, new_len); end1: if (old_dir != new_dir) mutex_unlock(&hpfs_i(new_dir)->i_mutex); mutex_unlock(&hpfs_i(old_dir)->i_mutex); mutex_unlock(&hpfs_i(i)->i_parent_mutex); if (new_inode) mutex_unlock(&hpfs_i(new_inode)->i_parent_mutex); unlock_kernel(); return err; }
/* * RENAME * FIXME: Some nfsds, like the Linux user space nfsd, may generate a * different file handle for the same inode after a rename (e.g. when * moving to a different directory). A fail-safe method to do so would * be to look up old_dir/old_name, create a link to new_dir/new_name and * rename the old file using the sillyrename stuff. This way, the original * file in old_dir will go away when the last process iput()s the inode. * * FIXED. * * It actually works quite well. One needs to have the possibility for * at least one ".nfs..." file in each directory the file ever gets * moved or linked to which happens automagically with the new * implementation that only depends on the dcache stuff instead of * using the inode layer * * Unfortunately, things are a little more complicated than indicated * above. For a cross-directory move, we want to make sure we can get * rid of the old inode after the operation. This means there must be * no pending writes (if it's a file), and the use count must be 1. * If these conditions are met, we can drop the dentries before doing * the rename. */ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct dentry *dentry = NULL, *rehash = NULL; int error = -EBUSY; /* * To prevent any new references to the target during the rename, * we unhash the dentry and free the inode in advance. */ lock_kernel(); if (!d_unhashed(new_dentry)) { d_drop(new_dentry); rehash = new_dentry; } dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", old_dentry->d_parent->d_name.name, old_dentry->d_name.name, new_dentry->d_parent->d_name.name, new_dentry->d_name.name, atomic_read(&new_dentry->d_count)); /* * First check whether the target is busy ... we can't * safely do _any_ rename if the target is in use. * * For files, make a copy of the dentry and then do a * silly-rename. If the silly-rename succeeds, the * copied dentry is hashed and becomes the new target. */ if (!new_inode) goto go_ahead; if (S_ISDIR(new_inode->i_mode)) goto out; else if (atomic_read(&new_dentry->d_count) > 1) { int err; /* copy the target dentry's name */ dentry = d_alloc(new_dentry->d_parent, &new_dentry->d_name); if (!dentry) goto out; /* silly-rename the existing target ... */ err = nfs_sillyrename(new_dir, new_dentry); if (!err) { new_dentry = rehash = dentry; new_inode = NULL; /* instantiate the replacement target */ d_instantiate(new_dentry, NULL); } /* dentry still busy? */ if (atomic_read(&new_dentry->d_count) > 1) { #ifdef NFS_PARANOIA printk("nfs_rename: target %s/%s busy, d_count=%d\n", new_dentry->d_parent->d_name.name, new_dentry->d_name.name, atomic_read(&new_dentry->d_count)); #endif goto out; } } go_ahead: /* * ... prune child dentries and writebacks if needed. */ if (atomic_read(&old_dentry->d_count) > 1) { nfs_wb_all(old_inode); shrink_dcache_parent(old_dentry); } if (new_inode) d_delete(new_dentry); nfs_begin_data_update(old_dir); nfs_begin_data_update(new_dir); nfs_begin_data_update(old_inode); error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, new_dir, &new_dentry->d_name); nfs_end_data_update(old_inode); nfs_end_data_update(new_dir); nfs_end_data_update(old_dir); out: if (rehash) d_rehash(rehash); if (!error) { if (!S_ISDIR(old_inode->i_mode)) d_move(old_dentry, new_dentry); nfs_renew_times(new_dentry); nfs_set_verifier(new_dentry, nfs_save_change_attribute(new_dir)); } /* new dentry created? */ if (dentry) dput(dentry); unlock_kernel(); return error; }
/* * sys_ipc() is the de-multiplexer for the SysV IPC calls.. * * This is really horribly ugly. */ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) { int version, ret; lock_kernel(); version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; if (call <= SEMCTL) switch (call) { case SEMOP: ret = sys_semop (first, (struct sembuf *)ptr, second); goto out; case SEMGET: ret = sys_semget (first, second, third); goto out; case SEMCTL: { union semun fourth; ret = -EINVAL; if (!ptr) goto out; ret = -EFAULT; if (get_user(fourth.__pad, (void **) ptr)) goto out; ret = sys_semctl (first, second, third, fourth); goto out; } default: ret = -EINVAL; goto out; } if (call <= MSGCTL) switch (call) { case MSGSND: ret = sys_msgsnd (first, (struct msgbuf *) ptr, second, third); goto out; case MSGRCV: switch (version) { case 0: { struct ipc_kludge tmp; ret = -EINVAL; if (!ptr) goto out; ret = -EFAULT; if (copy_from_user(&tmp,(struct ipc_kludge *) ptr, sizeof (tmp))) goto out; ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); goto out; } case 1: default: ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); goto out; } case MSGGET: ret = sys_msgget ((key_t) first, second); goto out; case MSGCTL: ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); goto out; default: ret = -EINVAL; goto out; } if (call <= SHMCTL) switch (call) { case SHMAT: switch (version) { case 0: default: { ulong raddr; ret = sys_shmat (first, (char *) ptr, second, &raddr); if (ret) goto out; ret = put_user (raddr, (ulong *) third); goto out; } case 1: /* iBCS2 emulator entry point */ ret = -EINVAL; if (!segment_eq(get_fs(), get_ds())) goto out; ret = sys_shmat (first, (char *) ptr, second, (ulong *) third); goto out; } case SHMDT: ret = sys_shmdt ((char *)ptr); goto out; case SHMGET: ret = sys_shmget (first, second, third); goto out; case SHMCTL: ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); goto out; default: ret = -EINVAL; goto out; } else ret = -EINVAL; out: unlock_kernel(); return ret; }
int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) { struct nfs_access_cache *cache = &NFS_I(inode)->cache_access; struct rpc_cred *cred; int mode = inode->i_mode; int res; if (mask == 0) return 0; if (mask & MAY_WRITE) { /* * * Nobody gets write access to a read-only fs. * */ if (IS_RDONLY(inode) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) return -EROFS; /* * * Nobody gets write access to an immutable file. * */ if (IS_IMMUTABLE(inode)) return -EACCES; } /* Are we checking permissions on anything other than lookup/execute? */ if ((mask & MAY_EXEC) == 0) { /* We only need to check permissions on file open() and access() */ if (!nd || !(nd->flags & (LOOKUP_OPEN|LOOKUP_ACCESS))) return 0; /* NFSv4 has atomic_open... */ if (NFS_PROTO(inode)->version > 3 && (nd->flags & LOOKUP_OPEN)) return 0; } lock_kernel(); if (!NFS_PROTO(inode)->access) goto out_notsup; cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); if (cache->cred == cred && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)) && !(NFS_FLAGS(inode) & NFS_INO_INVALID_ATTR)) { if (!(res = cache->err)) { /* Is the mask a subset of an accepted mask? */ if ((cache->mask & mask) == mask) goto out; } else { /* ...or is it a superset of a rejected mask? */ if ((cache->mask & mask) == cache->mask) goto out; } } res = NFS_PROTO(inode)->access(inode, cred, mask); if (!res || res == -EACCES) goto add_cache; out: put_rpccred(cred); unlock_kernel(); return res; out_notsup: nfs_revalidate_inode(NFS_SERVER(inode), inode); res = vfs_permission(inode, mask); unlock_kernel(); return res; add_cache: cache->jiffies = jiffies; if (cache->cred) put_rpccred(cache->cred); cache->cred = cred; cache->mask = mask; cache->err = res; unlock_kernel(); return res; }
/* * Reboot system call: for obvious reasons only root may call it, * and even root needs to set up some magic numbers in the registers * so that some mistake won't make this reboot the whole machine. * You can also set the meaning of the ctrl-alt-del-key here. * * reboot doesn't sync: do that yourself before calling this. */ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user * arg) { char buffer[256]; /* We only trust the superuser with rebooting the system. */ if (!capable(CAP_SYS_BOOT)) return -EPERM; /* For safety, we require "magic" arguments. */ if (magic1 != LINUX_REBOOT_MAGIC1 || (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A && magic2 != LINUX_REBOOT_MAGIC2B && magic2 != LINUX_REBOOT_MAGIC2C)) return -EINVAL; lock_kernel(); switch (cmd) { case LINUX_REBOOT_CMD_RESTART: notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL); system_state = SYSTEM_RESTART; device_shutdown(); printk(KERN_EMERG "Restarting system.\n"); machine_restart(NULL); break; case LINUX_REBOOT_CMD_CAD_ON: C_A_D = 1; break; case LINUX_REBOOT_CMD_CAD_OFF: C_A_D = 0; break; case LINUX_REBOOT_CMD_HALT: notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL); system_state = SYSTEM_HALT; device_shutdown(); printk(KERN_EMERG "System halted.\n"); machine_halt(); unlock_kernel(); do_exit(0); break; case LINUX_REBOOT_CMD_POWER_OFF: notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL); system_state = SYSTEM_POWER_OFF; device_shutdown(); printk(KERN_EMERG "Power down.\n"); machine_power_off(); unlock_kernel(); do_exit(0); break; case LINUX_REBOOT_CMD_RESTART2: if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) { unlock_kernel(); return -EFAULT; } buffer[sizeof(buffer) - 1] = '\0'; notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer); system_state = SYSTEM_RESTART; device_shutdown(); printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer); machine_restart(buffer); break; #ifdef CONFIG_SOFTWARE_SUSPEND case LINUX_REBOOT_CMD_SW_SUSPEND: { int ret = software_suspend(); unlock_kernel(); return ret; } #endif default: unlock_kernel(); return -EINVAL; } unlock_kernel(); return 0; }
static struct dentry * romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { unsigned long offset, maxoff; int fslen, res; struct inode *inode; char fsname[ROMFS_MAXFN]; /* XXX dynamic? */ struct romfs_inode ri; const char *name; /* got from dentry */ int len; res = -EACCES; /* placeholder for "no data here" */ offset = dir->i_ino & ROMFH_MASK; lock_kernel(); if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) goto out; maxoff = romfs_maxsize(dir->i_sb); offset = be32_to_cpu(ri.spec) & ROMFH_MASK; /* OK, now find the file whose name is in "dentry" in the * directory specified by "dir". */ name = dentry->d_name.name; len = dentry->d_name.len; for(;;) { if (!offset || offset >= maxoff) goto out0; if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) goto out; /* try to match the first 16 bytes of name */ fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE); if (len < ROMFH_SIZE) { if (len == fslen) { /* both are shorter, and same size */ romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1); if (strncmp (name, fsname, len) == 0) break; } } else if (fslen >= ROMFH_SIZE) { /* both are longer; XXX optimize max size */ fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, sizeof(fsname)-1); if (len == fslen) { romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1); if (strncmp(name, fsname, len) == 0) break; } } /* next entry */ offset = be32_to_cpu(ri.next) & ROMFH_MASK; } /* Hard link handling */ if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD) offset = be32_to_cpu(ri.spec) & ROMFH_MASK; if ((inode = iget(dir->i_sb, offset))) goto outi; /* * it's a bit funky, _lookup needs to return an error code * (negative) or a NULL, both as a dentry. ENOENT should not * be returned, instead we need to create a negative dentry by * d_add(dentry, NULL); and return 0 as no error. * (Although as I see, it only matters on writable file * systems). */ out0: inode = NULL; outi: res = 0; d_add (dentry, inode); out: unlock_kernel(); return ERR_PTR(res); }