Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
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;
}
Example #6
0
static void nlm4svc_callback_release(void *data)
{
    lock_kernel();
    nlm_release_call(data);
    unlock_kernel();
}
Example #7
0
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;
}
Example #8
0
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,
};
Example #9
0
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;
}
Example #10
0
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;
}
Example #12
0
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;
}
Example #13
0
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,
};
Example #14
0
/*
 *  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;
}
Example #16
0
File: gdc.c Project: wsj-zz/FamesOS
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;
}
Example #18
0
File: dir.c Project: 274914765/C
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;
}
Example #19
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;
}
Example #20
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);
}
Example #21
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;
}
Example #22
0
/*
 * 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;
}
Example #23
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;
}
Example #24
0
/*
 * 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;
}
Example #25
0
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;
}
Example #27
0
/*
 * 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;
}
Example #29
0
/*
 * 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;
}
Example #30
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);
}