Esempio n. 1
0
static int coda_fill_super(struct super_block *sb, void *data, int silent)
{
	struct inode *root = NULL;
	struct venus_comm *vc;
	struct CodaFid fid;
	int error;
	int idx;

	idx = get_device_index((struct coda_mount_data *) data);

	/* Ignore errors in data, for backward compatibility */
	if(idx == -1)
		idx = 0;
	
	printk(KERN_INFO "coda_read_super: device index: %i\n", idx);

	vc = &coda_comms[idx];
	mutex_lock(&vc->vc_mutex);

	if (!vc->vc_inuse) {
		printk("coda_read_super: No pseudo device\n");
		error = -EINVAL;
		goto unlock_out;
	}

	if (vc->vc_sb) {
		printk("coda_read_super: Device already mounted\n");
		error = -EBUSY;
		goto unlock_out;
	}

	error = bdi_setup_and_register(&vc->bdi, "coda", BDI_CAP_MAP_COPY);
	if (error)
		goto unlock_out;

	vc->vc_sb = sb;
	mutex_unlock(&vc->vc_mutex);

	sb->s_fs_info = vc;
	sb->s_flags |= MS_NOATIME;
	sb->s_blocksize = 4096;	/* XXXXX  what do we put here?? */
	sb->s_blocksize_bits = 12;
	sb->s_magic = CODA_SUPER_MAGIC;
	sb->s_op = &coda_super_operations;
	sb->s_d_op = &coda_dentry_operations;
	sb->s_bdi = &vc->bdi;

	/* get root fid from Venus: this needs the root inode */
	error = venus_rootfid(sb, &fid);
	if ( error ) {
	        printk("coda_read_super: coda_get_rootfid failed with %d\n",
		       error);
		goto error;
	}
	printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid));
	
	/* make root inode */
        error = coda_cnode_make(&root, &fid, sb);
        if ( error || !root ) {
	    printk("Failure of coda_cnode_make for root: error %d\n", error);
	    goto error;
	} 

	printk("coda_read_super: rootinode is %ld dev %s\n", 
	       root->i_ino, root->i_sb->s_id);
	sb->s_root = d_make_root(root);
	if (!sb->s_root) {
		error = -EINVAL;
		goto error;
	}
	return 0;

error:
	if (root)
		iput(root);

	mutex_lock(&vc->vc_mutex);
	bdi_destroy(&vc->bdi);
	vc->vc_sb = NULL;
	sb->s_fs_info = NULL;
unlock_out:
	mutex_unlock(&vc->vc_mutex);
	return error;
}
Esempio n. 2
0
File: inode.c Progetto: kprog/linux
static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
{
	struct ncp_mount_data_kernel data;
	struct ncp_server *server;
	struct file *ncp_filp;
	struct inode *root_inode;
	struct inode *sock_inode;
	struct socket *sock;
	int error;
	int default_bufsize;
#ifdef CONFIG_NCPFS_PACKET_SIGNING
	int options;
#endif
	struct ncp_entry_info finfo;

	memset(&data, 0, sizeof(data));
	server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
	if (!server)
		return -ENOMEM;
	sb->s_fs_info = server;

	error = -EFAULT;
	if (raw_data == NULL)
		goto out;
	switch (*(int*)raw_data) {
		case NCP_MOUNT_VERSION:
			{
				struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;

				data.flags = md->flags;
				data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
				data.mounted_uid = md->mounted_uid;
				data.wdog_pid = find_get_pid(md->wdog_pid);
				data.ncp_fd = md->ncp_fd;
				data.time_out = md->time_out;
				data.retry_count = md->retry_count;
				data.uid = md->uid;
				data.gid = md->gid;
				data.file_mode = md->file_mode;
				data.dir_mode = md->dir_mode;
				data.info_fd = -1;
				memcpy(data.mounted_vol, md->mounted_vol,
					NCP_VOLNAME_LEN+1);
			}
			break;
		case NCP_MOUNT_VERSION_V4:
			{
				struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;

				data.flags = md->flags;
				data.mounted_uid = md->mounted_uid;
				data.wdog_pid = find_get_pid(md->wdog_pid);
				data.ncp_fd = md->ncp_fd;
				data.time_out = md->time_out;
				data.retry_count = md->retry_count;
				data.uid = md->uid;
				data.gid = md->gid;
				data.file_mode = md->file_mode;
				data.dir_mode = md->dir_mode;
				data.info_fd = -1;
			}
			break;
		default:
			error = -ECHRNG;
			if (memcmp(raw_data, "vers", 4) == 0) {
				error = ncp_parse_options(&data, raw_data);
			}
			if (error)
				goto out;
			break;
	}
	error = -EBADF;
	ncp_filp = fget(data.ncp_fd);
	if (!ncp_filp)
		goto out;
	error = -ENOTSOCK;
	sock_inode = ncp_filp->f_path.dentry->d_inode;
	if (!S_ISSOCK(sock_inode->i_mode))
		goto out_fput;
	sock = SOCKET_I(sock_inode);
	if (!sock)
		goto out_fput;
		
	if (sock->type == SOCK_STREAM)
		default_bufsize = 0xF000;
	else
		default_bufsize = 1024;

	sb->s_flags |= MS_NODIRATIME;	/* probably even noatime */
	sb->s_maxbytes = 0xFFFFFFFFU;
	sb->s_blocksize = 1024;	/* Eh...  Is this correct? */
	sb->s_blocksize_bits = 10;
	sb->s_magic = NCP_SUPER_MAGIC;
	sb->s_op = &ncp_sops;
	sb->s_d_op = &ncp_dentry_operations;
	sb->s_bdi = &server->bdi;

	server = NCP_SBP(sb);
	memset(server, 0, sizeof(*server));

	error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
	if (error)
		goto out_fput;

	server->ncp_filp = ncp_filp;
	server->ncp_sock = sock;
	
	if (data.info_fd != -1) {
		struct socket *info_sock;

		error = -EBADF;
		server->info_filp = fget(data.info_fd);
		if (!server->info_filp)
			goto out_bdi;
		error = -ENOTSOCK;
		sock_inode = server->info_filp->f_path.dentry->d_inode;
		if (!S_ISSOCK(sock_inode->i_mode))
			goto out_fput2;
		info_sock = SOCKET_I(sock_inode);
		if (!info_sock)
			goto out_fput2;
		error = -EBADFD;
		if (info_sock->type != SOCK_STREAM)
			goto out_fput2;
		server->info_sock = info_sock;
	}

/*	server->lock = 0;	*/
	mutex_init(&server->mutex);
	server->packet = NULL;
/*	server->buffer_size = 0;	*/
/*	server->conn_status = 0;	*/
/*	server->root_dentry = NULL;	*/
/*	server->root_setuped = 0;	*/
	mutex_init(&server->root_setup_lock);
#ifdef CONFIG_NCPFS_PACKET_SIGNING
/*	server->sign_wanted = 0;	*/
/*	server->sign_active = 0;	*/
#endif
	init_rwsem(&server->auth_rwsem);
	server->auth.auth_type = NCP_AUTH_NONE;
/*	server->auth.object_name_len = 0;	*/
/*	server->auth.object_name = NULL;	*/
/*	server->auth.object_type = 0;		*/
/*	server->priv.len = 0;			*/
/*	server->priv.data = NULL;		*/

	server->m = data;
	/* Although anything producing this is buggy, it happens
	   now because of PATH_MAX changes.. */
	if (server->m.time_out < 1) {
		server->m.time_out = 10;
		printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
	}
	server->m.time_out = server->m.time_out * HZ / 100;
	server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
	server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;

#ifdef CONFIG_NCPFS_NLS
	/* load the default NLS charsets */
	server->nls_vol = load_nls_default();
	server->nls_io = load_nls_default();
#endif /* CONFIG_NCPFS_NLS */

	atomic_set(&server->dentry_ttl, 0);	/* no caching */

	INIT_LIST_HEAD(&server->tx.requests);
	mutex_init(&server->rcv.creq_mutex);
	server->tx.creq		= NULL;
	server->rcv.creq	= NULL;

	init_timer(&server->timeout_tm);
#undef NCP_PACKET_SIZE
#define NCP_PACKET_SIZE 131072
	error = -ENOMEM;
	server->packet_size = NCP_PACKET_SIZE;
	server->packet = vmalloc(NCP_PACKET_SIZE);
	if (server->packet == NULL)
		goto out_nls;
	server->txbuf = vmalloc(NCP_PACKET_SIZE);
	if (server->txbuf == NULL)
		goto out_packet;
	server->rxbuf = vmalloc(NCP_PACKET_SIZE);
	if (server->rxbuf == NULL)
		goto out_txbuf;

	lock_sock(sock->sk);
	server->data_ready	= sock->sk->sk_data_ready;
	server->write_space	= sock->sk->sk_write_space;
	server->error_report	= sock->sk->sk_error_report;
	sock->sk->sk_user_data	= server;
	sock->sk->sk_data_ready	  = ncp_tcp_data_ready;
	sock->sk->sk_error_report = ncp_tcp_error_report;
	if (sock->type == SOCK_STREAM) {
		server->rcv.ptr = (unsigned char*)&server->rcv.buf;
		server->rcv.len = 10;
		server->rcv.state = 0;
		INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
		INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
		sock->sk->sk_write_space = ncp_tcp_write_space;
	} else {
		INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
		INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
		server->timeout_tm.data = (unsigned long)server;
		server->timeout_tm.function = ncpdgram_timeout_call;
	}
	release_sock(sock->sk);

	ncp_lock_server(server);
	error = ncp_connect(server);
	ncp_unlock_server(server);
	if (error < 0)
		goto out_rxbuf;
	DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));

	error = -EMSGSIZE;	/* -EREMOTESIDEINCOMPATIBLE */
#ifdef CONFIG_NCPFS_PACKET_SIGNING
	if (ncp_negotiate_size_and_options(server, default_bufsize,
		NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
	{
		if (options != NCP_DEFAULT_OPTIONS)
		{
			if (ncp_negotiate_size_and_options(server, 
				default_bufsize,
				options & 2, 
				&(server->buffer_size), &options) != 0)
				
			{
				goto out_disconnect;
			}
		}
		ncp_lock_server(server);
		if (options & 2)
			server->sign_wanted = 1;
		ncp_unlock_server(server);
	}
	else 
#endif	/* CONFIG_NCPFS_PACKET_SIGNING */
	if (ncp_negotiate_buffersize(server, default_bufsize,
  				     &(server->buffer_size)) != 0)
		goto out_disconnect;
	DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);

	memset(&finfo, 0, sizeof(finfo));
	finfo.i.attributes	= aDIR;
	finfo.i.dataStreamSize	= 0;	/* ignored */
	finfo.i.dirEntNum	= 0;
	finfo.i.DosDirNum	= 0;
#ifdef CONFIG_NCPFS_SMALLDOS
	finfo.i.NSCreator	= NW_NS_DOS;
#endif
	finfo.volume		= NCP_NUMBER_OF_VOLUMES;
	/* set dates of mountpoint to Jan 1, 1986; 00:00 */
	finfo.i.creationTime	= finfo.i.modifyTime
				= cpu_to_le16(0x0000);
	finfo.i.creationDate	= finfo.i.modifyDate
				= finfo.i.lastAccessDate
				= cpu_to_le16(0x0C21);
	finfo.i.nameLen		= 0;
	finfo.i.entryName[0]	= '\0';

	finfo.opened		= 0;
	finfo.ino		= 2;	/* tradition */

	server->name_space[finfo.volume] = NW_NS_DOS;

	error = -ENOMEM;
        root_inode = ncp_iget(sb, &finfo);
        if (!root_inode)
		goto out_disconnect;
	DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
	sb->s_root = d_make_root(root_inode);
        if (!sb->s_root)
		goto out_disconnect;
	return 0;

out_disconnect:
	ncp_lock_server(server);
	ncp_disconnect(server);
	ncp_unlock_server(server);
out_rxbuf:
	ncp_stop_tasks(server);
	vfree(server->rxbuf);
out_txbuf:
	vfree(server->txbuf);
out_packet:
	vfree(server->packet);
out_nls:
#ifdef CONFIG_NCPFS_NLS
	unload_nls(server->nls_io);
	unload_nls(server->nls_vol);
#endif
	mutex_destroy(&server->rcv.creq_mutex);
	mutex_destroy(&server->root_setup_lock);
	mutex_destroy(&server->mutex);
out_fput2:
	if (server->info_filp)
		fput(server->info_filp);
out_bdi:
	bdi_destroy(&server->bdi);
out_fput:
	/* 23/12/1998 Marcin Dalecki <*****@*****.**>:
	 * 
	 * The previously used put_filp(ncp_filp); was bogus, since
	 * it doesn't perform proper unlocking.
	 */
	fput(ncp_filp);
out:
	put_pid(data.wdog_pid);
	sb->s_fs_info = NULL;
	kfree(server);
	return error;
}
Esempio n. 3
0
static int
cifs_read_super(struct super_block *sb, struct smb_vol *volume_info,
		const char *devname, int silent)
{
	struct inode *inode;
	struct cifs_sb_info *cifs_sb;
	int rc = 0;

	cifs_sb = CIFS_SB(sb);

	spin_lock_init(&cifs_sb->tlink_tree_lock);
	cifs_sb->tlink_tree = RB_ROOT;

	rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY);
	if (rc)
		return rc;

	cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages;

	rc = cifs_mount(sb, cifs_sb, volume_info, devname);

	if (rc) {
		if (!silent)
			cERROR(1, "cifs_mount failed w/return code = %d", rc);
		goto out_mount_failed;
	}

	sb->s_magic = CIFS_MAGIC_NUMBER;
	sb->s_op = &cifs_super_ops;
	sb->s_bdi = &cifs_sb->bdi;
	sb->s_blocksize = CIFS_MAX_MSGSIZE;
	sb->s_blocksize_bits = 14;	/* default 2**14 = CIFS_MAX_MSGSIZE */
	inode = cifs_root_iget(sb);

	if (IS_ERR(inode)) {
		rc = PTR_ERR(inode);
		inode = NULL;
		goto out_no_root;
	}

	sb->s_root = d_alloc_root(inode);

	if (!sb->s_root) {
		rc = -ENOMEM;
		goto out_no_root;
	}

	/* do that *after* d_alloc_root() - we want NULL ->d_op for root here */
	if (cifs_sb_master_tcon(cifs_sb)->nocase)
		sb->s_d_op = &cifs_ci_dentry_ops;
	else
		sb->s_d_op = &cifs_dentry_ops;

#ifdef CIFS_NFSD_EXPORT
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
		cFYI(1, "export ops supported");
		sb->s_export_op = &cifs_export_ops;
	}
#endif /* CIFS_NFSD_EXPORT */

	return 0;

out_no_root:
	cERROR(1, "cifs_read_super: get root inode failed");
	if (inode)
		iput(inode);

	cifs_umount(sb, cifs_sb);

out_mount_failed:
	bdi_destroy(&cifs_sb->bdi);
	return rc;
}
Esempio n. 4
0
int
zfs_domount(struct super_block *sb, void *data, int silent)
{
	zpl_mount_data_t *zmd = data;
	const char *osname = zmd->z_osname;
	zfs_sb_t *zsb;
	struct inode *root_inode;
	uint64_t recordsize;
	int error;

	error = zfs_sb_create(osname, &zsb);
	if (error)
		return (error);

	if ((error = dsl_prop_get_integer(osname, "recordsize",
	    &recordsize, NULL)))
		goto out;

	zsb->z_sb = sb;
	sb->s_fs_info = zsb;
	sb->s_magic = ZFS_SUPER_MAGIC;
	sb->s_maxbytes = MAX_LFS_FILESIZE;
	sb->s_time_gran = 1;
	sb->s_blocksize = recordsize;
	sb->s_blocksize_bits = ilog2(recordsize);

#ifdef HAVE_BDI
	/*
	 * 2.6.32 API change,
	 * Added backing_device_info (BDI) per super block interfaces.  A BDI
	 * must be configured when using a non-device backed filesystem for
	 * proper writeback.  This is not required for older pdflush kernels.
	 *
	 * NOTE: Linux read-ahead is disabled in favor of zfs read-ahead.
	 */
	zsb->z_bdi.ra_pages = 0;
	sb->s_bdi = &zsb->z_bdi;

	error = -bdi_setup_and_register(&zsb->z_bdi, "zfs", BDI_CAP_MAP_COPY);
	if (error)
		goto out;
#endif /* HAVE_BDI */

	/* Set callback operations for the file system. */
	sb->s_op = &zpl_super_operations;
	sb->s_xattr = zpl_xattr_handlers;
	sb->s_export_op = &zpl_export_operations;
#ifdef HAVE_S_D_OP
	sb->s_d_op = &zpl_dentry_operations;
#endif /* HAVE_S_D_OP */

	/* Set features for file system. */
	zfs_set_fuid_feature(zsb);

	if (dmu_objset_is_snapshot(zsb->z_os)) {
		uint64_t pval;

		atime_changed_cb(zsb, B_FALSE);
		readonly_changed_cb(zsb, B_TRUE);
		if ((error = dsl_prop_get_integer(osname,"xattr",&pval,NULL)))
			goto out;
		xattr_changed_cb(zsb, pval);
		zsb->z_issnap = B_TRUE;
		zsb->z_os->os_sync = ZFS_SYNC_DISABLED;

		mutex_enter(&zsb->z_os->os_user_ptr_lock);
		dmu_objset_set_user(zsb->z_os, zsb);
		mutex_exit(&zsb->z_os->os_user_ptr_lock);
	} else {
		error = zfs_sb_setup(zsb, B_TRUE);
	}

	/* Allocate a root inode for the filesystem. */
	error = zfs_root(zsb, &root_inode);
	if (error) {
		(void) zfs_umount(sb);
		goto out;
	}

	/* Allocate a root dentry for the filesystem */
	sb->s_root = d_make_root(root_inode);
	if (sb->s_root == NULL) {
		(void) zfs_umount(sb);
		error = ENOMEM;
		goto out;
	}

	if (!zsb->z_issnap)
		zfsctl_create(zsb);
out:
	if (error) {
		dmu_objset_disown(zsb->z_os, zsb);
		zfs_sb_free(zsb);
	}

	return (error);
}
Esempio n. 5
0
static int
cifs_read_super(struct super_block *sb, void *data,
                const char *devname, int silent)
{
    struct inode *inode;
    struct cifs_sb_info *cifs_sb;
    int rc = 0;

    /* BB should we make this contingent on mount parm? */
    sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
    sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL);
    cifs_sb = CIFS_SB(sb);
    if (cifs_sb == NULL)
        return -ENOMEM;

    spin_lock_init(&cifs_sb->tlink_tree_lock);
    cifs_sb->tlink_tree = RB_ROOT;

    rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY);
    if (rc) {
        kfree(cifs_sb);
        return rc;
    }
    cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages;

#ifdef CONFIG_CIFS_DFS_UPCALL
    /* copy mount params to sb for use in submounts */
    /* BB: should we move this after the mount so we
     * do not have to do the copy on failed mounts?
     * BB: May be it is better to do simple copy before
     * complex operation (mount), and in case of fail
     * just exit instead of doing mount and attempting
     * undo it if this copy fails?*/
    if (data) {
        int len = strlen(data);
        cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL);
        if (cifs_sb->mountdata == NULL) {
            bdi_destroy(&cifs_sb->bdi);
            kfree(sb->s_fs_info);
            sb->s_fs_info = NULL;
            return -ENOMEM;
        }
        strncpy(cifs_sb->mountdata, data, len + 1);
        cifs_sb->mountdata[len] = '\0';
    }
#endif

    rc = cifs_mount(sb, cifs_sb, data, devname);

    if (rc) {
        if (!silent)
            cERROR(1, "cifs_mount failed w/return code = %d", rc);
        goto out_mount_failed;
    }

    sb->s_magic = CIFS_MAGIC_NUMBER;
    sb->s_op = &cifs_super_ops;
    sb->s_bdi = &cifs_sb->bdi;
    sb->s_blocksize = CIFS_MAX_MSGSIZE;
    sb->s_blocksize_bits = 14;	/* default 2**14 = CIFS_MAX_MSGSIZE */
    inode = cifs_root_iget(sb, ROOT_I);

    if (IS_ERR(inode)) {
        rc = PTR_ERR(inode);
        inode = NULL;
        goto out_no_root;
    }

    sb->s_root = d_alloc_root(inode);

    if (!sb->s_root) {
        rc = -ENOMEM;
        goto out_no_root;
    }

    /* do that *after* d_alloc_root() - we want NULL ->d_op for root here */
    if (cifs_sb_master_tcon(cifs_sb)->nocase)
        sb->s_d_op = &cifs_ci_dentry_ops;
    else
        sb->s_d_op = &cifs_dentry_ops;

#ifdef CONFIG_CIFS_EXPERIMENTAL
    if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
        cFYI(1, "export ops supported");
        sb->s_export_op = &cifs_export_ops;
    }
#endif /* EXPERIMENTAL */

    return 0;

out_no_root:
    cERROR(1, "cifs_read_super: get root inode failed");
    if (inode)
        iput(inode);

    cifs_umount(sb, cifs_sb);

out_mount_failed:
    if (cifs_sb) {
#ifdef CONFIG_CIFS_DFS_UPCALL
        if (cifs_sb->mountdata) {
            kfree(cifs_sb->mountdata);
            cifs_sb->mountdata = NULL;
        }
#endif
        unload_nls(cifs_sb->local_nls);
        bdi_destroy(&cifs_sb->bdi);
        kfree(cifs_sb);
    }
    return rc;
}
Esempio n. 6
0
/*
 * lookup a volume by name
 * - this can be one of the following:
 *	"%[cell:]volume[.]"		R/W volume
 *	"#[cell:]volume[.]"		R/O or R/W volume (rwparent=0),
 *					 or R/W (rwparent=1) volume
 *	"%[cell:]volume.readonly"	R/O volume
 *	"#[cell:]volume.readonly"	R/O volume
 *	"%[cell:]volume.backup"		Backup volume
 *	"#[cell:]volume.backup"		Backup volume
 *
 * The cell name is optional, and defaults to the current cell.
 *
 * See "The Rules of Mount Point Traversal" in Chapter 5 of the AFS SysAdmin
 * Guide
 * - Rule 1: Explicit type suffix forces access of that type or nothing
 *           (no suffix, then use Rule 2 & 3)
 * - Rule 2: If parent volume is R/O, then mount R/O volume by preference, R/W
 *           if not available
 * - Rule 3: If parent volume is R/W, then only mount R/W volume unless
 *           explicitly told otherwise
 */
struct afs_volume *afs_volume_lookup(struct afs_mount_params *params)
{
	struct afs_vlocation *vlocation = NULL;
	struct afs_volume *volume = NULL;
	struct afs_server *server = NULL;
	char srvtmask;
	int ret, loop;

	_enter("{%*.*s,%d}",
	       params->volnamesz, params->volnamesz, params->volname, params->rwpath);

	/* lookup the volume location record */
	vlocation = afs_vlocation_lookup(params->cell, params->key,
					 params->volname, params->volnamesz);
	if (IS_ERR(vlocation)) {
		ret = PTR_ERR(vlocation);
		vlocation = NULL;
		goto error;
	}

	/* make the final decision on the type we want */
	ret = -ENOMEDIUM;
	if (params->force && !(vlocation->vldb.vidmask & (1 << params->type)))
		goto error;

	srvtmask = 0;
	for (loop = 0; loop < vlocation->vldb.nservers; loop++)
		srvtmask |= vlocation->vldb.srvtmask[loop];

	if (params->force) {
		if (!(srvtmask & (1 << params->type)))
			goto error;
	} else if (srvtmask & AFS_VOL_VTM_RO) {
		params->type = AFSVL_ROVOL;
	} else if (srvtmask & AFS_VOL_VTM_RW) {
		params->type = AFSVL_RWVOL;
	} else {
		goto error;
	}

	down_write(&params->cell->vl_sem);

	/* is the volume already active? */
	if (vlocation->vols[params->type]) {
		/* yes - re-use it */
		volume = vlocation->vols[params->type];
		afs_get_volume(volume);
		goto success;
	}

	/* create a new volume record */
	_debug("creating new volume record");

	ret = -ENOMEM;
	volume = kzalloc(sizeof(struct afs_volume), GFP_KERNEL);
	if (!volume)
		goto error_up;

	atomic_set(&volume->usage, 1);
	volume->type		= params->type;
	volume->type_force	= params->force;
	volume->cell		= params->cell;
	volume->vid		= vlocation->vldb.vid[params->type];

	ret = bdi_setup_and_register(&volume->bdi, "afs", BDI_CAP_MAP_COPY);
	if (ret)
		goto error_bdi;

	init_rwsem(&volume->server_sem);

	/* look up all the applicable server records */
	for (loop = 0; loop < 8; loop++) {
		if (vlocation->vldb.srvtmask[loop] & (1 << volume->type)) {
			server = afs_lookup_server(
			       volume->cell, &vlocation->vldb.servers[loop]);
			if (IS_ERR(server)) {
				ret = PTR_ERR(server);
				goto error_discard;
			}

			volume->servers[volume->nservers] = server;
			volume->nservers++;
		}
	}

	/* attach the cache and volume location */
#ifdef CONFIG_AFS_FSCACHE
	volume->cache = fscache_acquire_cookie(vlocation->cache,
					       &afs_volume_cache_index_def,
					       volume, true);
#endif
	afs_get_vlocation(vlocation);
	volume->vlocation = vlocation;

	vlocation->vols[volume->type] = volume;

success:
	_debug("kAFS selected %s volume %08x",
	       afs_voltypes[volume->type], volume->vid);
	up_write(&params->cell->vl_sem);
	afs_put_vlocation(vlocation);
	_leave(" = %p", volume);
	return volume;

	/* clean up */
error_up:
	up_write(&params->cell->vl_sem);
error:
	afs_put_vlocation(vlocation);
	_leave(" = %d", ret);
	return ERR_PTR(ret);

error_discard:
	bdi_destroy(&volume->bdi);
error_bdi:
	up_write(&params->cell->vl_sem);

	for (loop = volume->nservers - 1; loop >= 0; loop--)
		afs_put_server(volume->servers[loop]);

	kfree(volume);
	goto error;
}
Esempio n. 7
0
static int exofs_read_lookup_dev_table(struct exofs_sb_info **psbi,
				       unsigned table_count)
{
	struct exofs_sb_info *sbi = *psbi;
	struct osd_dev *fscb_od;
	struct osd_obj_id obj = {.partition = sbi->layout.s_pid,
				 .id = EXOFS_DEVTABLE_ID};
	struct exofs_device_table *dt;
	unsigned table_bytes = table_count * sizeof(dt->dt_dev_table[0]) +
					     sizeof(*dt);
	unsigned numdevs, i;
	int ret;

	dt = kmalloc(table_bytes, GFP_KERNEL);
	if (unlikely(!dt)) {
		EXOFS_ERR("ERROR: allocating %x bytes for device table\n",
			  table_bytes);
		return -ENOMEM;
	}

	fscb_od = sbi->layout.s_ods[0];
	sbi->layout.s_ods[0] = NULL;
	sbi->layout.s_numdevs = 0;
	ret = exofs_read_kern(fscb_od, sbi->s_cred, &obj, 0, dt, table_bytes);
	if (unlikely(ret)) {
		EXOFS_ERR("ERROR: reading device table\n");
		goto out;
	}

	numdevs = le64_to_cpu(dt->dt_num_devices);
	if (unlikely(!numdevs)) {
		ret = -EINVAL;
		goto out;
	}
	WARN_ON(table_count != numdevs);

	ret = _read_and_match_data_map(sbi, numdevs, dt);
	if (unlikely(ret))
		goto out;

	if (likely(numdevs > 1)) {
		unsigned size = numdevs * sizeof(sbi->layout.s_ods[0]);

		sbi = krealloc(sbi, sizeof(*sbi) + size, GFP_KERNEL);
		if (unlikely(!sbi)) {
			ret = -ENOMEM;
			goto out;
		}
		memset(&sbi->layout.s_ods[1], 0,
		       size - sizeof(sbi->layout.s_ods[0]));
		*psbi = sbi;
	}

	for (i = 0; i < numdevs; i++) {
		struct exofs_fscb fscb;
		struct osd_dev_info odi;
		struct osd_dev *od;

		if (exofs_devs_2_odi(&dt->dt_dev_table[i], &odi)) {
			EXOFS_ERR("ERROR: Read all-zeros device entry\n");
			ret = -EINVAL;
			goto out;
		}

		printk(KERN_NOTICE "Add device[%d]: osd_name-%s\n",
		       i, odi.osdname);

		/* On all devices the device table is identical. The user can
		 * specify any one of the participating devices on the command
		 * line. We always keep them in device-table order.
		 */
		if (fscb_od && osduld_device_same(fscb_od, &odi)) {
			sbi->layout.s_ods[i] = fscb_od;
			++sbi->layout.s_numdevs;
			fscb_od = NULL;
			continue;
		}

		od = osduld_info_lookup(&odi);
		if (unlikely(IS_ERR(od))) {
			ret = PTR_ERR(od);
			EXOFS_ERR("ERROR: device requested is not found "
				  "osd_name-%s =>%d\n", odi.osdname, ret);
			goto out;
		}

		sbi->layout.s_ods[i] = od;
		++sbi->layout.s_numdevs;

		/* Read the fscb of the other devices to make sure the FS
		 * partition is there.
		 */
		ret = exofs_read_kern(od, sbi->s_cred, &obj, 0, &fscb,
				      sizeof(fscb));
		if (unlikely(ret)) {
			EXOFS_ERR("ERROR: Malformed participating device "
				  "error reading fscb osd_name-%s\n",
				  odi.osdname);
			goto out;
		}

		/* TODO: verify other information is correct and FS-uuid
		 *	 matches. Benny what did you say about device table
		 *	 generation and old devices?
		 */
	}

out:
	kfree(dt);
	if (unlikely(!ret && fscb_od)) {
		EXOFS_ERR(
		      "ERROR: Bad device-table container device not present\n");
		osduld_put_device(fscb_od);
		ret = -EINVAL;
	}

	return ret;
}

/*
 * Read the superblock from the OSD and fill in the fields
 */
static int exofs_fill_super(struct super_block *sb, void *data, int silent)
{
	struct inode *root;
	struct exofs_mountopt *opts = data;
	struct exofs_sb_info *sbi;	/*extended info                  */
	struct osd_dev *od;		/* Master device                 */
	struct exofs_fscb fscb;		/*on-disk superblock info        */
	struct osd_obj_id obj;
	unsigned table_count;
	int ret;

	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
	if (!sbi)
		return -ENOMEM;

	ret = bdi_setup_and_register(&sbi->bdi, "exofs", BDI_CAP_MAP_COPY);
	if (ret)
		goto free_bdi;

	/* use mount options to fill superblock */
	od = osduld_path_lookup(opts->dev_name);
	if (IS_ERR(od)) {
		ret = PTR_ERR(od);
		goto free_sbi;
	}

	/* Default layout in case we do not have a device-table */
	sbi->layout.stripe_unit = PAGE_SIZE;
	sbi->layout.mirrors_p1 = 1;
	sbi->layout.group_width = 1;
	sbi->layout.group_depth = -1;
	sbi->layout.group_count = 1;
	sbi->layout.s_ods[0] = od;
	sbi->layout.s_numdevs = 1;
	sbi->layout.s_pid = opts->pid;
	sbi->s_timeout = opts->timeout;

	/* fill in some other data by hand */
	memset(sb->s_id, 0, sizeof(sb->s_id));
	strcpy(sb->s_id, "exofs");
	sb->s_blocksize = EXOFS_BLKSIZE;
	sb->s_blocksize_bits = EXOFS_BLKSHIFT;
	sb->s_maxbytes = MAX_LFS_FILESIZE;
	atomic_set(&sbi->s_curr_pending, 0);
	sb->s_bdev = NULL;
	sb->s_dev = 0;

	obj.partition = sbi->layout.s_pid;
	obj.id = EXOFS_SUPER_ID;
	exofs_make_credential(sbi->s_cred, &obj);

	ret = exofs_read_kern(od, sbi->s_cred, &obj, 0, &fscb, sizeof(fscb));
	if (unlikely(ret))
		goto free_sbi;

	sb->s_magic = le16_to_cpu(fscb.s_magic);
	sbi->s_nextid = le64_to_cpu(fscb.s_nextid);
	sbi->s_numfiles = le32_to_cpu(fscb.s_numfiles);

	/* make sure what we read from the object store is correct */
	if (sb->s_magic != EXOFS_SUPER_MAGIC) {
		if (!silent)
			EXOFS_ERR("ERROR: Bad magic value\n");
		ret = -EINVAL;
		goto free_sbi;
	}
	if (le32_to_cpu(fscb.s_version) != EXOFS_FSCB_VER) {
		EXOFS_ERR("ERROR: Bad FSCB version expected-%d got-%d\n",
			  EXOFS_FSCB_VER, le32_to_cpu(fscb.s_version));
		ret = -EINVAL;
		goto free_sbi;
	}

	/* start generation numbers from a random point */
	get_random_bytes(&sbi->s_next_generation, sizeof(u32));
	spin_lock_init(&sbi->s_next_gen_lock);

	table_count = le64_to_cpu(fscb.s_dev_table_count);
	if (table_count) {
		ret = exofs_read_lookup_dev_table(&sbi, table_count);
		if (unlikely(ret))
			goto free_sbi;
	}

	/* set up operation vectors */
	sb->s_bdi = &sbi->bdi;
	sb->s_fs_info = sbi;
	sb->s_op = &exofs_sops;
	sb->s_export_op = &exofs_export_ops;
	root = exofs_iget(sb, EXOFS_ROOT_ID - EXOFS_OBJ_OFF);
	if (IS_ERR(root)) {
		EXOFS_ERR("ERROR: exofs_iget failed\n");
		ret = PTR_ERR(root);
		goto free_sbi;
	}
	sb->s_root = d_alloc_root(root);
	if (!sb->s_root) {
		iput(root);
		EXOFS_ERR("ERROR: get root inode failed\n");
		ret = -ENOMEM;
		goto free_sbi;
	}

	if (!S_ISDIR(root->i_mode)) {
		dput(sb->s_root);
		sb->s_root = NULL;
		EXOFS_ERR("ERROR: corrupt root inode (mode = %hd)\n",
		       root->i_mode);
		ret = -EINVAL;
		goto free_sbi;
	}

	_exofs_print_device("Mounting", opts->dev_name, sbi->layout.s_ods[0],
			    sbi->layout.s_pid);
	return 0;

free_sbi:
	bdi_destroy(&sbi->bdi);
free_bdi:
	EXOFS_ERR("Unable to mount exofs on %s pid=0x%llx err=%d\n",
		  opts->dev_name, sbi->layout.s_pid, ret);
	exofs_free_sbi(sbi);
	return ret;
}

/*
 * Set up the superblock (calls exofs_fill_super eventually)
 */
static struct dentry *exofs_mount(struct file_system_type *type,
			  int flags, const char *dev_name,
			  void *data)
{
	struct exofs_mountopt opts;
	int ret;

	ret = parse_options(data, &opts);
	if (ret)
		return ERR_PTR(ret);

	opts.dev_name = dev_name;
	return mount_nodev(type, flags, &opts, exofs_fill_super);
}

/*
 * Return information about the file system state in the buffer.  This is used
 * by the 'df' command, for example.
 */
static int exofs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
	struct super_block *sb = dentry->d_sb;
	struct exofs_sb_info *sbi = sb->s_fs_info;
	struct exofs_io_state *ios;
	struct osd_attr attrs[] = {
		ATTR_DEF(OSD_APAGE_PARTITION_QUOTAS,
			OSD_ATTR_PQ_CAPACITY_QUOTA, sizeof(__be64)),
		ATTR_DEF(OSD_APAGE_PARTITION_INFORMATION,
			OSD_ATTR_PI_USED_CAPACITY, sizeof(__be64)),
	};
	uint64_t capacity = ULLONG_MAX;
	uint64_t used = ULLONG_MAX;
	uint8_t cred_a[OSD_CAP_LEN];
	int ret;

	ret = exofs_get_io_state(&sbi->layout, &ios);
	if (ret) {
		EXOFS_DBGMSG("exofs_get_io_state failed.\n");
		return ret;
	}

	exofs_make_credential(cred_a, &ios->obj);
	ios->cred = sbi->s_cred;
	ios->in_attr = attrs;
	ios->in_attr_len = ARRAY_SIZE(attrs);

	ret = exofs_sbi_read(ios);
	if (unlikely(ret))
		goto out;

	ret = extract_attr_from_ios(ios, &attrs[0]);
	if (likely(!ret)) {
		capacity = get_unaligned_be64(attrs[0].val_ptr);
		if (unlikely(!capacity))
			capacity = ULLONG_MAX;
	} else
		EXOFS_DBGMSG("exofs_statfs: get capacity failed.\n");

	ret = extract_attr_from_ios(ios, &attrs[1]);
	if (likely(!ret))
		used = get_unaligned_be64(attrs[1].val_ptr);
	else
		EXOFS_DBGMSG("exofs_statfs: get used-space failed.\n");

	/* fill in the stats buffer */
	buf->f_type = EXOFS_SUPER_MAGIC;
	buf->f_bsize = EXOFS_BLKSIZE;
	buf->f_blocks = capacity >> 9;
	buf->f_bfree = (capacity - used) >> 9;
	buf->f_bavail = buf->f_bfree;
	buf->f_files = sbi->s_numfiles;
	buf->f_ffree = EXOFS_MAX_ID - sbi->s_numfiles;
	buf->f_namelen = EXOFS_NAME_LEN;

out:
	exofs_put_io_state(ios);
	return ret;
}

static const struct super_operations exofs_sops = {
	.alloc_inode    = exofs_alloc_inode,
	.destroy_inode  = exofs_destroy_inode,
	.write_inode    = exofs_write_inode,
	.evict_inode    = exofs_evict_inode,
	.put_super      = exofs_put_super,
	.write_super    = exofs_write_super,
	.sync_fs	= exofs_sync_fs,
	.statfs         = exofs_statfs,
};

/******************************************************************************
 * EXPORT OPERATIONS
 *****************************************************************************/

struct dentry *exofs_get_parent(struct dentry *child)
{
	unsigned long ino = exofs_parent_ino(child);

	if (!ino)
		return NULL;

	return d_obtain_alias(exofs_iget(child->d_inode->i_sb, ino));
}
Esempio n. 8
0
static int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
{
	struct smb_sb_info *server;
	struct smb_mount_data_kernel *mnt;
	struct smb_mount_data *oldmnt;
	struct inode *root_inode;
	struct smb_fattr root;
	int ver;
	void *mem;
	static int warn_count;

	lock_kernel();

	if (warn_count < 5) {
		warn_count++;
		printk(KERN_EMERG "smbfs is deprecated and will be removed"
			" from the 2.6.37 kernel. Please migrate to cifs\n");
	}

	if (!raw_data)
		goto out_no_data;

	oldmnt = (struct smb_mount_data *) raw_data;
	ver = oldmnt->version;
	if (ver != SMB_MOUNT_OLDVERSION && cpu_to_be32(ver) != SMB_MOUNT_ASCII)
		goto out_wrong_data;

	sb->s_flags |= MS_NODIRATIME;
	sb->s_blocksize = 1024;	/* Eh...  Is this correct? */
	sb->s_blocksize_bits = 10;
	sb->s_magic = SMB_SUPER_MAGIC;
	sb->s_op = &smb_sops;
	sb->s_time_gran = 100;

	server = kzalloc(sizeof(struct smb_sb_info), GFP_KERNEL);
	if (!server)
		goto out_no_server;
	sb->s_fs_info = server;
	
	if (bdi_setup_and_register(&server->bdi, "smbfs", BDI_CAP_MAP_COPY))
		goto out_bdi;

	sb->s_bdi = &server->bdi;

	server->super_block = sb;
	server->mnt = NULL;
	server->sock_file = NULL;
	init_waitqueue_head(&server->conn_wq);
	init_MUTEX(&server->sem);
	INIT_LIST_HEAD(&server->entry);
	INIT_LIST_HEAD(&server->xmitq);
	INIT_LIST_HEAD(&server->recvq);
	server->conn_error = 0;
	server->conn_pid = NULL;
	server->state = CONN_INVALID; /* no connection yet */
	server->generation = 0;

	/* Allocate the global temp buffer and some superblock helper structs */
	/* FIXME: move these to the smb_sb_info struct */
	VERBOSE("alloc chunk = %lu\n", sizeof(struct smb_ops) +
		sizeof(struct smb_mount_data_kernel));
	mem = kmalloc(sizeof(struct smb_ops) +
		      sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
	if (!mem)
		goto out_no_mem;

	server->ops = mem;
	smb_install_null_ops(server->ops);
	server->mnt = mem + sizeof(struct smb_ops);

	/* Setup NLS stuff */
	server->remote_nls = NULL;
	server->local_nls = NULL;

	mnt = server->mnt;

	memset(mnt, 0, sizeof(struct smb_mount_data_kernel));
	strlcpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT,
		SMB_NLS_MAXNAMELEN);
	strlcpy(mnt->codepage.remote_name, SMB_NLS_REMOTE,
		SMB_NLS_MAXNAMELEN);

	mnt->ttl = SMB_TTL_DEFAULT;
	if (ver == SMB_MOUNT_OLDVERSION) {
		mnt->version = oldmnt->version;

		SET_UID(mnt->uid, oldmnt->uid);
		SET_GID(mnt->gid, oldmnt->gid);

		mnt->file_mode = (oldmnt->file_mode & S_IRWXUGO) | S_IFREG;
		mnt->dir_mode = (oldmnt->dir_mode & S_IRWXUGO) | S_IFDIR;

		mnt->flags = (oldmnt->file_mode >> 9) | SMB_MOUNT_UID |
			SMB_MOUNT_GID | SMB_MOUNT_FMODE | SMB_MOUNT_DMODE;
	} else {
Esempio n. 9
0
static HgfsSuperInfo *
HgfsInitSuperInfo(void *rawData,            // IN: Passed down from the user
                  uint32 mountInfoVersion)  // IN: version
{
   HgfsSuperInfo *si = NULL;
   int result = 0;
   int len;
   char *tmpName = NULL;
   Bool hostValid;
   uint32 mntFlags = 0;
   uint32 ttl = 0;
   uid_t uid = 0;
   gid_t gid = 0;
   mode_t fmask = 0;
   mode_t dmask = 0;
   const char *shareHost;
   const char *shareDir;

   si = kmalloc(sizeof *si, GFP_KERNEL);
   if (!si) {
      result = -ENOMEM;
      goto out_error_si;
   }
   memset(si, 0, sizeof *si);

#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
   result = bdi_setup_and_register(&si->bdi, HGFS_NAME);
   if (result) {
      LOG(6, (KERN_DEBUG "VMware hgfs: %s: initialize backing device info"
              "failed. (%d)\n", __func__, result));
      goto out_error_si;
   }
#endif

   result = HgfsGetMountInfo(rawData,
                             mountInfoVersion,
                             &mntFlags,
                             &ttl,
                             &uid,
                             &gid,
                             &fmask,
                             &dmask,
                             &shareHost,
                             &shareDir);
   if (result < 0) {
      LOG(6, (KERN_DEBUG LGPFX "%s: error: get mount info %d\n", __func__, result));
      goto out_error_last;
   }

   /*
    * Initialize with the default flags.
    */
   si->mntFlags = mntFlags;

   si->uid = current_uid();
   if ((si->mntFlags & HGFS_MNT_SET_UID) != 0) {
      kuid_t mntUid = make_kuid(current_user_ns(), uid);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
      if (uid_valid(mntUid))
#endif
         si->uid = mntUid;
   }

   si->gid = current_gid();
   if ((si->mntFlags & HGFS_MNT_SET_GID) != 0) {
      kgid_t mntGid = make_kgid(current_user_ns(), gid);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
      if (gid_valid(mntGid))
#endif
         si->gid = mntGid;
   }
   si->fmask = fmask;
   si->dmask = dmask;
   si->ttl = ttl * HZ; // in ticks

   /*
    * We don't actually care about this field (though we may care in the
    * future). For now, just make sure it is set to ".host" as a sanity check.
    *
    * We can't call getname() directly because on certain kernels we can't call
    * putname() directly.  For more details, see the change description of
    * change 464782 or the second comment in bug 159623, which fixed the same
    * problem for vmblock.
    */
   tmpName = compat___getname();
   if (!tmpName) {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: could not obtain "
              "memory for filename\n"));
      result = -ENOMEM;
      goto out_error_last;
   }

   len = strncpy_from_user(tmpName, shareHost, PATH_MAX);
   if (len < 0 || len >= PATH_MAX) {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: strncpy_from_user "
              "on host string failed\n"));
      result = len < 0 ? len : -ENAMETOOLONG;
      goto out_error_last;
   }

   hostValid = strcmp(tmpName, ".host") == 0;
   if (!hostValid) {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: host string is "
              "invalid\n"));
      result = -EINVAL;
      goto out_error_last;
   }

   /*
    * Perform a simple sanity check on the directory portion: it must begin
    * with forward slash.
    */
   len = strncpy_from_user(tmpName, shareDir, PATH_MAX);
   if (len < 0 || len >= PATH_MAX) {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: strncpy_from_user "
              "on dir string failed\n"));
      result = len < 0 ? len : -ENAMETOOLONG;
      goto out_error_last;
   }

   if (*tmpName != '/') {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: dir string is "
              "invalid\n"));
      result = -EINVAL;
      goto out_error_last;
   }

   /*
    * The SELinux audit subsystem will delay the putname() of a string until
    * the end of a system call so that it may be audited at any point. At that
    * time, it also unconditionally calls putname() on every string allocated
    * by getname().
    *
    * This means we can't safely retain strings allocated by getname() beyond
    * the syscall boundary. So after getting the string, use kstrdup() to
    * duplicate it, and store that (audit-safe) result in the SuperInfo struct.
    */
   si->shareName = compat_kstrdup(tmpName, GFP_KERNEL);
   if (si->shareName == NULL) {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: kstrdup on "
              "dir string failed\n"));
      result = -ENOMEM;
      goto out_error_last;
   }
   si->shareNameLen = strlen(si->shareName);

out_error_last:
   if (tmpName) {
      compat___putname(tmpName);
   }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
   if (result) {
      bdi_destroy(&si->bdi);
   }
#endif
out_error_si:
   if (result) {
      kfree(si);
      si = ERR_PTR(result);
   }

   return si;
}
Esempio n. 10
0
static struct dentry *lofs_mount(
    struct file_system_type *fs_type,
    int flags,
    const char *dev_name,
    void *raw_data)
{
    static const struct qstr slash = { .name = "/", .len = 1 };
    struct super_block *s;
    struct lofs_sb_info *sbi;
    struct lofs_dentry_info *root_info;
    struct inode *inode;
    const char *err = "Getting sb failed";
    struct path path;
    int rc;

    sbi = kmem_cache_zalloc(lofs_sb_info_cache, GFP_KERNEL);
    if (!sbi) {
        rc = -ENOMEM;
        goto out;
    }

    s = sget(fs_type, NULL, set_anon_super, NULL);
    if (IS_ERR(s)) {
        rc = PTR_ERR(s);
        goto out;
    }

    s->s_flags = flags;
#if defined(HAVE_BACKING_DEV)
    rc = bdi_setup_and_register(&sbi->bdi, "lofs", BDI_CAP_MAP_COPY);
    if (rc)
        goto out1;

    s->s_bdi = &sbi->bdi;
#endif
    lofs_set_superblock_private(s, sbi);

    /* ->kill_sb() will take care of sbi after that point */
    sbi = NULL;
    s->s_op   = &lofs_sops;
    s->s_d_op = &lofs_dops;

    err = "Reading sb failed";
    rc = kern_path(slash.name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
    if (rc) {
        lofs_printk(KERN_WARNING, "kern_path() failed\n");
        goto out1;
    }

    lofs_set_superblock_lower(s, path.dentry->d_sb);
    s->s_maxbytes = path.dentry->d_sb->s_maxbytes;
    s->s_blocksize = path.dentry->d_sb->s_blocksize;
    s->s_magic = 0x10f5;

    inode = lofs_get_inode(path.dentry->d_inode, s);
    rc = PTR_ERR(inode);
    if (IS_ERR(inode)) {
        goto out_free;
    }

#ifdef HAVE_D_MAKE_ROOT
    s->s_root = d_make_root(inode);
#else
    s->s_root = d_alloc_root(inode);
    if (!s->s_root) {
        iput(inode);
    }
#endif
    if (!s->s_root) {
        rc = -ENOMEM;
        goto out_free;
    }

    rc = -ENOMEM;
    root_info = kmem_cache_zalloc(lofs_dentry_info_cache, GFP_KERNEL);
    if (!root_info)
        goto out_free;

    /* ->kill_sb() will take care of root_info */
    lofs_set_dentry_private(s->s_root, root_info);
    lofs_set_dentry_lower(s->s_root, path.dentry);
    lofs_set_dentry_lower_mnt(s->s_root, path.mnt);

    s->s_flags |= MS_ACTIVE;
    return dget(s->s_root);

out_free:
    path_put(&path);
out1:
    deactivate_locked_super(s);
out:
    if (sbi) {
        kmem_cache_free(lofs_sb_info_cache, sbi);
    }
    printk(KERN_ERR "%s; rc = [%d]\n", err, rc);
    return ERR_PTR(rc);
}

/**
 * lofs_kill_block_super
 * @sb: The lofs super block
 *
 * Used to bring the superblock down and free the private data.
 */
static void lofs_kill_block_super(struct super_block *sb)
{
    struct lofs_sb_info *sb_info = lofs_superblock_to_private(sb);
    kill_anon_super(sb);
#if defined(HAVE_BACKING_DEV)
    if (sb_info) {
        bdi_destroy(&sb_info->bdi);
    }
#endif
    kmem_cache_free(lofs_sb_info_cache, sb_info);
}

#else /* !HAVE_MOUNT_IN_FS_TYPE */

/**
 * lofs_fill_super
 * @sb: The lofs super block
 * @raw_data: The options passed to mount
 * @silent: Not used but required by function prototype
 *
 * Sets up what we can of the sb, rest is done in lofs_read_super
 *
 * Returns zero on success; non-zero otherwise
 */
static int
lofs_fill_super(struct super_block *sb, void *raw_data, int silent)
{
    int rc = 0;
    struct inode *inode;
    struct nameidata nd;

    /* Released in lofs_put_super() */
    struct lofs_sb_info *sbi;
    sbi = kmem_cache_zalloc(lofs_sb_info_cache, GFP_KERNEL);
    if (!sbi) {
        lofs_printk(KERN_WARNING, "Out of memory\n");
        return -ENOMEM;
    }
    lofs_set_superblock_private(sb, sbi);
    sb->s_op = (struct super_operations *) &lofs_sops;

    /* Released through deactivate_super(sb) from get_sb_nodev */
#if defined(HAVE_S_D_OP)
    sb->s_d_op = &lofs_dops;
#endif

    rc = path_lookup("/", LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd);
    if (rc) {
        lofs_printk(KERN_WARNING, "path_lookup() failed\n");
        return rc;
    }
    lofs_set_superblock_lower(sb, NAMEIDATA_TO_DENTRY(&nd)->d_sb);
    sb->s_maxbytes =  NAMEIDATA_TO_DENTRY(&nd)->d_sb->s_maxbytes;
    sb->s_blocksize = NAMEIDATA_TO_DENTRY(&nd)->d_sb->s_blocksize;
#ifdef HAVE_ADDRESS_SPACE_OPS_EXT
    sb->s_flags |= MS_HAS_NEW_AOPS;
#endif

    /* Get the root inode and dentry.  We have to bootstrap this one,
     * since it doesn't get created via the regular lookup mechanism.
     */

    inode = lofs_get_inode(NAMEIDATA_TO_DENTRY(&nd)->d_inode, sb);
    if (IS_ERR(inode)) {
        dput(NAMEIDATA_TO_DENTRY(&nd));
        mntput(NAMEIDATA_TO_VFSMNT(&nd));
        return PTR_ERR(inode);
    }

    sb->s_root = d_alloc_root(inode);
    if (!sb->s_root) {
        iput(inode);
        dput(NAMEIDATA_TO_DENTRY(&nd));
        mntput(NAMEIDATA_TO_VFSMNT(&nd));
        return -ENOMEM;
    }
    lofs_set_dentry_private(sb->s_root,
            kmem_cache_zalloc(lofs_dentry_info_cache, GFP_KERNEL));
    lofs_set_dentry_lower(sb->s_root, NAMEIDATA_TO_DENTRY(&nd));
    lofs_set_dentry_lower_mnt(sb->s_root, NAMEIDATA_TO_VFSMNT(&nd));

#if !defined(HAVE_S_D_OP)
    sb->s_root->d_op = (struct dentry_operations *) &lofs_dops;
#endif

    return 0;
}