⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vfs.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * vfs.c * * This file implements kernel downcalls from lento. * * Author: Rob Simmonds <simmonds@stelias.com> *         Andreas Dilger <adilger@stelias.com> * Copyright (C) 2000 Stelias Computing Inc * Copyright (C) 2000 Red Hat Inc. * * Extended attribute support * Copyright (C) 2001 Shirish H. Phatak, Tacit Networks, Inc. * * This code is based on code from namei.c in the linux file system; * see copyright notice below. *//** namei.c copyright **//* *  linux/fs/namei.c * *  Copyright (C) 1991, 1992  Linus Torvalds *//* * Some corrections by tytso. *//* [Feb 1997 T. Schoebel-Theuer] Complete rewrite of the pathname * lookup logic. *//** end of namei.c copyright **/#include <linux/mm.h>#include <linux/proc_fs.h>#include <linux/smp_lock.h>#include <linux/quotaops.h>#include <asm/uaccess.h>#include <asm/unaligned.h>#include <asm/semaphore.h>#include <asm/pgtable.h>#include <linux/file.h>#include <linux/fs.h>#include <linux/blk.h>#include <linux/intermezzo_fs.h>#include <linux/intermezzo_upcall.h>#include <linux/intermezzo_psdev.h>#include <linux/intermezzo_kml.h>#ifdef CONFIG_FS_EXT_ATTR#include <linux/ext_attr.h>#ifdef CONFIG_FS_POSIX_ACL#include <linux/posix_acl.h>#endif#endifextern struct inode_operations presto_sym_iops;/* * It's inline, so penalty for filesystems that don't use sticky bit is * minimal. */static inline int check_sticky(struct inode *dir, struct inode *inode){        if (!(dir->i_mode & S_ISVTX))                return 0;        if (inode->i_uid == current->fsuid)                return 0;        if (dir->i_uid == current->fsuid)                return 0;        return !capable(CAP_FOWNER);}/* from linux/fs/namei.c */static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir){        int error;        if (!victim->d_inode || victim->d_parent->d_inode != dir)                return -ENOENT;        error = permission(dir,MAY_WRITE | MAY_EXEC);        if (error)                return error;        if (IS_APPEND(dir))                return -EPERM;        if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)||            IS_IMMUTABLE(victim->d_inode))                return -EPERM;        if (isdir) {                if (!S_ISDIR(victim->d_inode->i_mode))                        return -ENOTDIR;                if (IS_ROOT(victim))                        return -EBUSY;        } else if (S_ISDIR(victim->d_inode->i_mode))                return -EISDIR;        return 0;}/* from linux/fs/namei.c */static inline int may_create(struct inode *dir, struct dentry *child) {        if (child->d_inode)                return -EEXIST;        if (IS_DEADDIR(dir))                return -ENOENT;        return permission(dir,MAY_WRITE | MAY_EXEC);}#ifdef PRESTO_DEBUG/* The loop_discard_io() function is available via a kernel patch to the * loop block device.  It "works" by accepting writes, but throwing them * away, rather than trying to write them to disk.  The old method worked * by setting the underlying device read-only, but that has the problem * that dirty buffers are kept in memory, and ext3 didn't like that at all. */#ifdef CONFIG_LOOP_DISCARD#define BLKDEV_FAIL(dev,fail) loop_discard_io(dev,fail)#else#define BLKDEV_FAIL(dev,fail) set_device_ro(dev, 1)#endif/* If a breakpoint has been set via /proc/sys/intermezzo/intermezzoX/errorval, * that is the same as "value", the underlying device will "fail" now. */inline void presto_debug_fail_blkdev(struct presto_file_set *fset,                                     unsigned long value){        int minor = presto_f2m(fset);        int errorval = upc_comms[minor].uc_errorval;        kdev_t dev = fset->fset_mtpt->d_inode->i_dev;        if (errorval && errorval == (long)value && !is_read_only(dev)) {                CDEBUG(D_SUPER, "setting device %s read only\n", kdevname(dev));                BLKDEV_FAIL(dev, 1);                upc_comms[minor].uc_errorval = -dev;        }}#else#define presto_debug_fail_blkdev(dev,value) do {} while (0)#endifstatic inline int presto_do_kml(struct lento_vfs_context *info, struct inode* inode){        if ( ! (info->flags & LENTO_FL_KML) )                 return 0;        if ( inode->i_gid == presto_excluded_gid )                 return 0;        return 1;}static inline int presto_do_expect(struct lento_vfs_context *info, struct inode *inode){        if ( ! (info->flags & LENTO_FL_EXPECT) )                 return 0;        if ( inode->i_gid == presto_excluded_gid )                 return 0;        return 1;}/* XXX fixme: this should not fail, all these dentries are in memory   when _we_ call this */int presto_settime(struct presto_file_set *fset,                    struct dentry *dentry,                    struct lento_vfs_context *ctx,                    int valid){        int error;         struct inode *inode = dentry->d_inode;        struct inode_operations *iops;        struct iattr iattr;        ENTRY;        if (ctx->flags &  LENTO_FL_IGNORE_TIME ) {                 EXIT;                return 0;        }        iattr.ia_ctime = ctx->updated_time;        iattr.ia_mtime = ctx->updated_time;        iattr.ia_valid = valid;        error = -EROFS;        if (IS_RDONLY(inode)) {                EXIT;                return -EROFS;        }        if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {                EXIT;                return -EPERM;        }        error = -EPERM;        iops = filter_c2cdiops(fset->fset_cache->cache_filter);         if (!iops) {                EXIT;                return error;        }        if (iops->setattr != NULL)                error = iops->setattr(dentry, &iattr);        else {		error = 0;                inode_setattr(dentry->d_inode, &iattr);	}        EXIT;        return error;}int presto_do_setattr(struct presto_file_set *fset, struct dentry *dentry,                      struct iattr *iattr, struct lento_vfs_context *info){        struct rec_info rec;        struct inode *inode = dentry->d_inode;        struct inode_operations *iops;        int error;        struct presto_version old_ver, new_ver;        void *handle;	off_t old_size=inode->i_size;        ENTRY;        error = -EROFS;        if (IS_RDONLY(inode)) {                EXIT;                return -EROFS;        }        if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {                EXIT;                return -EPERM;        }        presto_getversion(&old_ver, dentry->d_inode);        error = -EPERM;        iops = filter_c2cdiops(fset->fset_cache->cache_filter);         if (!iops &&            !iops->setattr) {                EXIT;                return error;        }	error = presto_reserve_space(fset->fset_cache, 2*PRESTO_REQHIGH); 	if (error) {		EXIT;		return error;	}	if  (iattr->ia_valid & ATTR_SIZE) { 		handle = presto_trans_start(fset, dentry->d_inode, PRESTO_OP_TRUNC);	} else {		handle = presto_trans_start(fset, dentry->d_inode, PRESTO_OP_SETATTR);	}        if ( IS_ERR(handle) ) {                printk("presto_do_setattr: no space for transaction\n");		presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH);                 return -ENOSPC;        }        if (dentry->d_inode && iops->setattr) {                error = iops->setattr(dentry, iattr);        } else {                error = inode_change_ok(dentry->d_inode, iattr);                if (!error)                         inode_setattr(inode, iattr);        }	if (!error && (iattr->ia_valid & ATTR_SIZE))		vmtruncate(inode, iattr->ia_size);        if (error) {                EXIT;                goto exit;        }        presto_debug_fail_blkdev(fset, PRESTO_OP_SETATTR | 0x10);        if ( presto_do_kml(info, dentry->d_inode) ) {                if ((iattr->ia_valid & ATTR_SIZE) && (old_size != inode->i_size)) {                	struct file file;                	/* Journal a close whenever we see a potential truncate                 	* At the receiving end, lento should explicitly remove                 	* ATTR_SIZE from the list of valid attributes */                	presto_getversion(&new_ver, inode);                	file.private_data = NULL;                	file.f_dentry = dentry;                	error=presto_journal_close(&rec, fset, &file, dentry, &new_ver);            	}		if (!error)                	error = presto_journal_setattr(&rec, fset, dentry, &old_ver, iattr);        }        presto_debug_fail_blkdev(fset, PRESTO_OP_SETATTR | 0x20);        if ( presto_do_expect(info, dentry->d_inode) )                error = presto_write_last_rcvd(&rec, fset, info);        presto_debug_fail_blkdev(fset, PRESTO_OP_SETATTR | 0x30);        EXIT;exit:	presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH);         presto_trans_commit(fset, handle);        return error;}int lento_setattr(const char *name, struct iattr *iattr,                  struct lento_vfs_context *info){        struct nameidata nd;        struct dentry *dentry;        struct presto_file_set *fset;        int error;#ifdef  CONFIG_FS_POSIX_ACL        int (*set_posix_acl)(struct inode *, int type, posix_acl_t *)=NULL;#endif        ENTRY;        CDEBUG(D_PIOCTL,"name %s, valid %#x, mode %#o, uid %d, gid %d, size %Ld\n",               name, iattr->ia_valid, iattr->ia_mode, iattr->ia_uid,               iattr->ia_gid, iattr->ia_size);        CDEBUG(D_PIOCTL, "atime %#lx, mtime %#lx, ctime %#lx, attr_flags %#x\n",               iattr->ia_atime, iattr->ia_mtime, iattr->ia_ctime,               iattr->ia_attr_flags);        CDEBUG(D_PIOCTL, "offset %d, recno %d, flags %#x\n",               info->slot_offset, info->recno, info->flags);        lock_kernel();        error = presto_walk(name, &nd);        if (error) {                EXIT;                goto exit;        }        dentry = nd.dentry;                fset = presto_fset(dentry);        error = -EINVAL;        if ( !fset ) {                printk("No fileset!\n");                EXIT;                goto exit_lock;        }        /* NOTE: this prevents us from changing the filetype on setattr,         *       as we normally only want to change permission bits.         *       If this is not correct, then we need to fix the perl code         *       to always send the file type OR'ed with the permission.         */        if (iattr->ia_valid & ATTR_MODE) {                int set_mode = iattr->ia_mode;                iattr->ia_mode = (iattr->ia_mode & S_IALLUGO) |                                 (dentry->d_inode->i_mode & ~S_IALLUGO);                CDEBUG(D_PIOCTL, "chmod: orig %#o, set %#o, result %#o\n",                       dentry->d_inode->i_mode, set_mode, iattr->ia_mode);#ifdef CONFIG_FS_POSIX_ACL                /* ACl code interacts badly with setattr                  * since it tries to modify the ACL using                  * set_ext_attr which recurses back into presto.                   * This only happens if ATTR_MODE is set.                 * Here we are doing a "forced" mode set                  * (initiated by lento), so we disable the                  * set_posix_acl operation which                  * prevents such recursion.  -SHP                 *                 * This will probably still be required when native                 * acl journalling is in place.                 */                set_posix_acl=dentry->d_inode->i_op->set_posix_acl;                dentry->d_inode->i_op->set_posix_acl=NULL;#endif        }        error = presto_do_setattr(fset, dentry, iattr, info);#ifdef CONFIG_FS_POSIX_ACL        /* restore the inode_operations if we changed them*/        if (iattr->ia_valid & ATTR_MODE)                 dentry->d_inode->i_op->set_posix_acl=set_posix_acl;#endif        EXIT;exit_lock:        path_release(&nd);exit:        unlock_kernel();        return error;}int presto_do_create(struct presto_file_set *fset, struct dentry *dir,                     struct dentry *dentry, int mode,                     struct lento_vfs_context *info){        struct rec_info rec;        int error;        struct presto_version tgt_dir_ver, new_file_ver;        struct inode_operations *iops;        void *handle;        ENTRY;        mode &= S_IALLUGO;        mode |= S_IFREG;        down(&dir->d_inode->i_zombie);	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 	if (error) {		EXIT;        	up(&dir->d_inode->i_zombie);		return error;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -