Skip to content
Snippets Groups Projects
Select Git revision
  • f776c5ec4690b21b3668ad5956774a22c86f541a
  • master default protected
  • android-msm-bullhead-3.10-nougat_kgdb_less_changes
  • android-msm-bullhead-3.10-nougat_kgdb
  • android-msm-bullhead-3.10-nougat_klist
  • android-4.4
  • android-msm-vega-4.4-oreo-daydream
  • android-msm-wahoo-4.4-p-preview-5
  • android-msm-wahoo-4.4-pie
  • android-msm-marlin-3.18-p-preview-5
  • android-msm-marlin-3.18-pie
  • android-msm-wahoo-2018.07-oreo-m2
  • android-msm-wahoo-2018.07-oreo-m4
  • android-msm-wahoo-4.4-p-preview-4
  • android-msm-bullhead-3.10-oreo-m6
  • android-msm-angler-3.10-oreo-m6
  • android-msm-marlin-3.18-p-preview-4
  • android-msm-stargazer-3.18-oreo-wear-dr
  • android-msm-catshark-3.18-oreo-wear-dr
  • android-msm-wahoo-4.4-oreo-m2
  • android-msm-wahoo-4.4-oreo-m4
  • android-daydreamos-8.0.0_r0.5
  • android-8.1.0_r0.92
  • android-8.1.0_r0.91
  • android-daydreamos-8.0.0_r0.4
  • android-p-preview-5_r0.2
  • android-p-preview-5_r0.1
  • android-9.0.0_r0.5
  • android-9.0.0_r0.4
  • android-9.0.0_r0.2
  • android-9.0.0_r0.1
  • android-8.1.0_r0.81
  • android-8.1.0_r0.80
  • android-8.1.0_r0.78
  • android-8.1.0_r0.76
  • android-8.1.0_r0.75
  • android-8.1.0_r0.72
  • android-8.1.0_r0.70
  • android-p-preview-4_r0.2
  • android-p-preview-4_r0.1
  • android-wear-8.0.0_r0.30
41 results

devtmpfs.c

Blame
  • user avatar
    Heiko Carstens authored and Greg Kroah-Hartman committed
    On Mon, Jan 18, 2010 at 05:26:20PM +0530, Sachin Sant wrote:
    > Hello Heiko,
    >
    > Today while trying to boot next-20100118 i came across
    > the following Oops :
    >
    > Brought up 4 CPUs
    > Unable to handle kernel pointer dereference at virtual kernel address 0000000000
    > 543000
    > Oops: 0004 #1 SMP
    > Modules linked in:
    > CPU: 0 Not tainted 2.6.33-rc4-autotest-next-20100118-5-default #1
    > Process swapper (pid: 1, task: 00000000fd792038, ksp: 00000000fd797a30)
    > Krnl PSW : 0704200180000000 00000000001eb0b8 (shmem_parse_options+0xc0/0x328)
    >           R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:0 CC:2 PM:0 EA:3
    > Krnl GPRS: 000000000054388a 000000000000003d 0000000000543836 000000000000003d
    >           0000000000000000 0000000000483f28 0000000000536112 00000000fd797d00
    >           00000000fd4ba100 0000000000000100 0000000000483978 0000000000543832
    >           0000000000000000 0000000000465958 00000000001eb0b0 00000000fd797c58
    > Krnl Code: 00000000001eb0aa: c0e5000994f1       brasl   %r14,31da8c
    >           00000000001eb0b0: b9020022           ltgr    %r2,%r2
    >           00000000001eb0b4: a784010b           brc     8,1eb2ca
    >          >00000000001eb0b8: 92002000           mvi     0(%r2),0
    >           00000000001eb0bc: a7080000           lhi     %r0,0
    >           00000000001eb0c0: 41902001           la      %r9,1(%r2)
    >           00000000001eb0c4: b9040016           lgr     %r1,%r6
    >           00000000001eb0c8: b904002b           lgr     %r2,%r11
    > Call Trace:
    > (<00000000fd797c50> 0xfd797c50)
    > <00000000001eb5da> shmem_fill_super+0x13a/0x25c
    > <0000000000228cfa> get_sb_single+0xbe/0xdc
    > <000000000034ffc0> dev_get_sb+0x2c/0x38
    > <000000000066c602> devtmpfs_init+0x46/0xc0
    > <000000000066c53e> driver_init+0x22/0x60
    > <000000000064d40a> kernel_init+0x24e/0x3d0
    > <000000000010a7ea> kernel_thread_starter+0x6/0xc
    > <000000000010a7e4> kernel_thread_starter+0x0/0xc
    >
    > I never tried to boot a kernel with DEVTMPFS enabled on a s390 box.
    > So am wondering if this is supported or not ? If you think this
    > is supported i will send a mail to community on this.
    
    There is nothing arch specific to devtmpfs. This part crashes because the
    kernel tries to modify the data read-only section which is write protected
    on s390.
    
    Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
    Acked-by: default avatarKay Sievers <kay.sievers@vrfy.org>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
    f776c5ec
    History
    devtmpfs.c 7.67 KiB
    /*
     * devtmpfs - kernel-maintained tmpfs-based /dev
     *
     * Copyright (C) 2009, Kay Sievers <kay.sievers@vrfy.org>
     *
     * During bootup, before any driver core device is registered,
     * devtmpfs, a tmpfs-based filesystem is created. Every driver-core
     * device which requests a device node, will add a node in this
     * filesystem.
     * By default, all devices are named after the the name of the
     * device, owned by root and have a default mode of 0600. Subsystems
     * can overwrite the default setting if needed.
     */
    
    #include <linux/kernel.h>
    #include <linux/syscalls.h>
    #include <linux/mount.h>
    #include <linux/device.h>
    #include <linux/genhd.h>
    #include <linux/namei.h>
    #include <linux/fs.h>
    #include <linux/shmem_fs.h>
    #include <linux/cred.h>
    #include <linux/sched.h>
    #include <linux/init_task.h>
    
    static struct vfsmount *dev_mnt;
    
    #if defined CONFIG_DEVTMPFS_MOUNT
    static int dev_mount = 1;
    #else
    static int dev_mount;
    #endif
    
    static DEFINE_MUTEX(dirlock);
    
    static int __init mount_param(char *str)
    {
    	dev_mount = simple_strtoul(str, NULL, 0);
    	return 1;
    }
    __setup("devtmpfs.mount=", mount_param);
    
    static int dev_get_sb(struct file_system_type *fs_type, int flags,
    		      const char *dev_name, void *data, struct vfsmount *mnt)
    {
    	return get_sb_single(fs_type, flags, data, shmem_fill_super, mnt);
    }
    
    static struct file_system_type dev_fs_type = {
    	.name = "devtmpfs",
    	.get_sb = dev_get_sb,
    	.kill_sb = kill_litter_super,
    };
    
    #ifdef CONFIG_BLOCK
    static inline int is_blockdev(struct device *dev)
    {
    	return dev->class == &block_class;
    }
    #else
    static inline int is_blockdev(struct device *dev) { return 0; }
    #endif
    
    static int dev_mkdir(const char *name, mode_t mode)
    {
    	struct nameidata nd;
    	struct dentry *dentry;
    	int err;
    
    	err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
    			      name, LOOKUP_PARENT, &nd);
    	if (err)
    		return err;
    
    	dentry = lookup_create(&nd, 1);
    	if (!IS_ERR(dentry)) {
    		err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
    		if (!err)
    			/* mark as kernel-created inode */
    			dentry->d_inode->i_private = &dev_mnt;
    		dput(dentry);
    	} else {
    		err = PTR_ERR(dentry);
    	}
    
    	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
    	path_put(&nd.path);
    	return err;
    }
    
    static int create_path(const char *nodepath)
    {
    	int err;
    
    	mutex_lock(&dirlock);
    	err = dev_mkdir(nodepath, 0755);
    	if (err == -ENOENT) {
    		char *path;
    		char *s;
    
    		/* parent directories do not exist, create them */
    		path = kstrdup(nodepath, GFP_KERNEL);
    		if (!path) {
    			err = -ENOMEM;
    			goto out;
    		}
    		s = path;
    		for (;;) {
    			s = strchr(s, '/');
    			if (!s)
    				break;
    			s[0] = '\0';
    			err = dev_mkdir(path, 0755);
    			if (err && err != -EEXIST)
    				break;
    			s[0] = '/';
    			s++;
    		}
    		kfree(path);
    	}
    out:
    	mutex_unlock(&dirlock);
    	return err;
    }
    
    int devtmpfs_create_node(struct device *dev)
    {
    	const char *tmp = NULL;
    	const char *nodename;
    	const struct cred *curr_cred;
    	mode_t mode = 0;
    	struct nameidata nd;
    	struct dentry *dentry;
    	int err;
    
    	if (!dev_mnt)
    		return 0;
    
    	nodename = device_get_devnode(dev, &mode, &tmp);
    	if (!nodename)
    		return -ENOMEM;
    
    	if (mode == 0)
    		mode = 0600;
    	if (is_blockdev(dev))
    		mode |= S_IFBLK;
    	else
    		mode |= S_IFCHR;
    
    	curr_cred = override_creds(&init_cred);
    
    	err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
    			      nodename, LOOKUP_PARENT, &nd);
    	if (err == -ENOENT) {
    		create_path(nodename);
    		err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
    				      nodename, LOOKUP_PARENT, &nd);
    	}
    	if (err)
    		goto out;
    
    	dentry = lookup_create(&nd, 0);
    	if (!IS_ERR(dentry)) {
    		err = vfs_mknod(nd.path.dentry->d_inode,
    				dentry, mode, dev->devt);
    		if (!err) {
    			struct iattr newattrs;
    
    			/* fixup possibly umasked mode */
    			newattrs.ia_mode = mode;
    			newattrs.ia_valid = ATTR_MODE;
    			mutex_lock(&dentry->d_inode->i_mutex);
    			notify_change(dentry, &newattrs);
    			mutex_unlock(&dentry->d_inode->i_mutex);
    
    			/* mark as kernel-created inode */
    			dentry->d_inode->i_private = &dev_mnt;
    		}
    		dput(dentry);
    	} else {
    		err = PTR_ERR(dentry);
    	}
    
    	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
    	path_put(&nd.path);
    out:
    	kfree(tmp);
    	revert_creds(curr_cred);
    	return err;
    }
    
    static int dev_rmdir(const char *name)
    {
    	struct nameidata nd;
    	struct dentry *dentry;
    	int err;
    
    	err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
    			      name, LOOKUP_PARENT, &nd);
    	if (err)
    		return err;
    
    	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
    	dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
    	if (!IS_ERR(dentry)) {
    		if (dentry->d_inode) {
    			if (dentry->d_inode->i_private == &dev_mnt)
    				err = vfs_rmdir(nd.path.dentry->d_inode,
    						dentry);
    			else
    				err = -EPERM;
    		} else {
    			err = -ENOENT;
    		}
    		dput(dentry);
    	} else {
    		err = PTR_ERR(dentry);
    	}
    
    	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
    	path_put(&nd.path);
    	return err;
    }
    
    static int delete_path(const char *nodepath)
    {
    	const char *path;
    	int err = 0;
    
    	path = kstrdup(nodepath, GFP_KERNEL);
    	if (!path)
    		return -ENOMEM;
    
    	mutex_lock(&dirlock);
    	for (;;) {
    		char *base;
    
    		base = strrchr(path, '/');
    		if (!base)
    			break;
    		base[0] = '\0';
    		err = dev_rmdir(path);
    		if (err)
    			break;
    	}
    	mutex_unlock(&dirlock);
    
    	kfree(path);
    	return err;
    }
    
    static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *stat)
    {
    	/* did we create it */
    	if (inode->i_private != &dev_mnt)
    		return 0;
    
    	/* does the dev_t match */
    	if (is_blockdev(dev)) {
    		if (!S_ISBLK(stat->mode))
    			return 0;
    	} else {
    		if (!S_ISCHR(stat->mode))
    			return 0;
    	}
    	if (stat->rdev != dev->devt)
    		return 0;
    
    	/* ours */
    	return 1;
    }
    
    int devtmpfs_delete_node(struct device *dev)
    {
    	const char *tmp = NULL;
    	const char *nodename;
    	const struct cred *curr_cred;
    	struct nameidata nd;
    	struct dentry *dentry;
    	struct kstat stat;
    	int deleted = 1;
    	int err;
    
    	if (!dev_mnt)
    		return 0;
    
    	nodename = device_get_devnode(dev, NULL, &tmp);
    	if (!nodename)
    		return -ENOMEM;
    
    	curr_cred = override_creds(&init_cred);
    	err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
    			      nodename, LOOKUP_PARENT, &nd);
    	if (err)
    		goto out;
    
    	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
    	dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
    	if (!IS_ERR(dentry)) {
    		if (dentry->d_inode) {
    			err = vfs_getattr(nd.path.mnt, dentry, &stat);
    			if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
    				err = vfs_unlink(nd.path.dentry->d_inode,
    						 dentry);
    				if (!err || err == -ENOENT)
    					deleted = 1;
    			}
    		} else {
    			err = -ENOENT;
    		}
    		dput(dentry);
    	} else {
    		err = PTR_ERR(dentry);
    	}
    	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
    
    	path_put(&nd.path);
    	if (deleted && strchr(nodename, '/'))
    		delete_path(nodename);
    out:
    	kfree(tmp);
    	revert_creds(curr_cred);
    	return err;
    }
    
    /*
     * If configured, or requested by the commandline, devtmpfs will be
     * auto-mounted after the kernel mounted the root filesystem.
     */
    int devtmpfs_mount(const char *mntdir)
    {
    	int err;
    
    	if (!dev_mount)
    		return 0;
    
    	if (!dev_mnt)
    		return 0;
    
    	err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, NULL);
    	if (err)
    		printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
    	else
    		printk(KERN_INFO "devtmpfs: mounted\n");
    	return err;
    }
    
    /*
     * Create devtmpfs instance, driver-core devices will add their device
     * nodes here.
     */
    int __init devtmpfs_init(void)
    {
    	int err;
    	struct vfsmount *mnt;
    	char options[] = "mode=0755";
    
    	err = register_filesystem(&dev_fs_type);
    	if (err) {
    		printk(KERN_ERR "devtmpfs: unable to register devtmpfs "
    		       "type %i\n", err);
    		return err;
    	}
    
    	mnt = kern_mount_data(&dev_fs_type, options);
    	if (IS_ERR(mnt)) {
    		err = PTR_ERR(mnt);
    		printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err);
    		unregister_filesystem(&dev_fs_type);
    		return err;
    	}
    	dev_mnt = mnt;
    
    	printk(KERN_INFO "devtmpfs: initialized\n");
    	return 0;
    }