예제 #1
0
static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
			     umode_t mode, dev_t dev, const char *symname,
			     unsigned int size, int excl)
{
	const struct qstr *name = &dentry->d_name;
	struct gfs2_holder ghs[2];
	struct inode *inode = NULL;
	struct gfs2_inode *dip = GFS2_I(dir);
	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
	struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 };
	int error;
	u64 generation;
	struct buffer_head *bh = NULL;

	if (!name->len || name->len > GFS2_FNAMESIZE)
		return -ENAMETOOLONG;

	error = gfs2_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
	if (error)
		goto fail;

	error = create_ok(dip, name, mode);
	if ((error == -EEXIST) && S_ISREG(mode) && !excl) {
		inode = gfs2_lookupi(dir, &dentry->d_name, 0);
		gfs2_glock_dq_uninit(ghs);
		d_instantiate(dentry, inode);
		return IS_ERR(inode) ? PTR_ERR(inode) : 0;
	}
	if (error)
		goto fail_gunlock;

	error = alloc_dinode(dip, &inum.no_addr, &generation);
	if (error)
		goto fail_gunlock;
	inum.no_formal_ino = generation;

	error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops,
				  LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
	if (error)
		goto fail_gunlock;

	error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, symname, size, &bh);
	if (error)
		goto fail_gunlock2;

	inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr,
				  inum.no_formal_ino, 0);
	if (IS_ERR(inode))
		goto fail_gunlock2;

	error = gfs2_inode_refresh(GFS2_I(inode));
	if (error)
		goto fail_gunlock2;

	error = gfs2_acl_create(dip, inode);
	if (error)
		goto fail_gunlock2;

	error = gfs2_security_init(dip, GFS2_I(inode), name);
	if (error)
		goto fail_gunlock2;

	error = link_dinode(dip, name, GFS2_I(inode));
	if (error)
		goto fail_gunlock2;

	if (bh)
		brelse(bh);

	gfs2_trans_end(sdp);
	/* Check if we reserved space in the rgrp. Function link_dinode may
	   not, depending on whether alloc is required. */
	if (dip->i_res)
		gfs2_inplace_release(dip);
	gfs2_quota_unlock(dip);
	gfs2_qadata_put(dip);
	mark_inode_dirty(inode);
	gfs2_glock_dq_uninit_m(2, ghs);
	d_instantiate(dentry, inode);
	return 0;

fail_gunlock2:
	gfs2_glock_dq_uninit(ghs + 1);
fail_gunlock:
	gfs2_glock_dq_uninit(ghs);
	if (inode && !IS_ERR(inode)) {
		set_bit(GIF_ALLOC_FAILED, &GFS2_I(inode)->i_flags);
		iput(inode);
	}
fail:
	if (bh)
		brelse(bh);
	return error;
}

/**
 * gfs2_create - Create a file
 * @dir: The directory in which to create the file
 * @dentry: The dentry of the new file
 * @mode: The mode of the new file
 *
 * Returns: errno
 */

static int gfs2_create(struct inode *dir, struct dentry *dentry,
		       umode_t mode, struct nameidata *nd)
{
	int excl = 0;
	if (nd && (nd->flags & LOOKUP_EXCL))
		excl = 1;
	return gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0, excl);
}
예제 #2
0
struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
			   unsigned int mode, dev_t dev)
{
	struct inode *inode = NULL;
	struct gfs2_inode *dip = ghs->gh_gl->gl_object;
	struct inode *dir = &dip->i_inode;
	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
	struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 };
	int error;
	u64 generation;
	struct buffer_head *bh = NULL;

	if (!name->len || name->len > GFS2_FNAMESIZE)
		return ERR_PTR(-ENAMETOOLONG);

	gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs);
	error = gfs2_glock_nq(ghs);
	if (error)
		goto fail;

	error = create_ok(dip, name, mode);
	if (error)
		goto fail_gunlock;

	error = alloc_dinode(dip, &inum.no_addr, &generation);
	if (error)
		goto fail_gunlock;
	inum.no_formal_ino = generation;

	error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops,
				  LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
	if (error)
		goto fail_gunlock;

	error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, &bh);
	if (error)
		goto fail_gunlock2;

	inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr,
				  inum.no_formal_ino);
	if (IS_ERR(inode))
		goto fail_gunlock2;

	error = gfs2_inode_refresh(GFS2_I(inode));
	if (error)
		goto fail_gunlock2;

	error = gfs2_acl_create(dip, inode);
	if (error)
		goto fail_gunlock2;

	error = gfs2_security_init(dip, GFS2_I(inode));
	if (error)
		goto fail_gunlock2;

	error = link_dinode(dip, name, GFS2_I(inode));
	if (error)
		goto fail_gunlock2;

	if (bh)
		brelse(bh);
	return inode;

fail_gunlock2:
	gfs2_glock_dq_uninit(ghs + 1);
	if (inode && !IS_ERR(inode))
		iput(inode);
fail_gunlock:
	gfs2_glock_dq(ghs);
fail:
	if (bh)
		brelse(bh);
	return ERR_PTR(error);
}

static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
{
	struct inode *inode = &ip->i_inode;
	struct buffer_head *dibh;
	int error;

	error = gfs2_meta_inode_buffer(ip, &dibh);
	if (error)
		return error;

	if ((attr->ia_valid & ATTR_SIZE) &&
	    attr->ia_size != i_size_read(inode)) {
		error = vmtruncate(inode, attr->ia_size);
		if (error)
			return error;
	}

	setattr_copy(inode, attr);
	mark_inode_dirty(inode);

	gfs2_assert_warn(GFS2_SB(inode), !error);
	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
	gfs2_dinode_out(ip, dibh->b_data);
	brelse(dibh);
	return 0;
}

/**
 * gfs2_setattr_simple -
 * @ip:
 * @attr:
 *
 * Called with a reference on the vnode.
 *
 * Returns: errno
 */

int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
{
	int error;

	if (current->journal_info)
		return __gfs2_setattr_simple(ip, attr);

	error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE, 0);
	if (error)
		return error;

	error = __gfs2_setattr_simple(ip, attr);
	gfs2_trans_end(GFS2_SB(&ip->i_inode));
	return error;
}
예제 #3
0
static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
			     umode_t mode, dev_t dev, const char *symname,
			     unsigned int size, int excl)
{
	const struct qstr *name = &dentry->d_name;
	struct gfs2_holder ghs[2];
	struct inode *inode = NULL;
	struct gfs2_inode *dip = GFS2_I(dir), *ip;
	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
	struct gfs2_glock *io_gl;
	int error;
	struct buffer_head *bh = NULL;
	u32 aflags = 0;

	if (!name->len || name->len > GFS2_FNAMESIZE)
		return -ENAMETOOLONG;

	error = gfs2_rs_alloc(dip);
	if (error)
		return error;

	error = gfs2_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
	if (error)
		goto fail;

	error = create_ok(dip, name, mode);
	if ((error == -EEXIST) && S_ISREG(mode) && !excl) {
		inode = gfs2_lookupi(dir, &dentry->d_name, 0);
		gfs2_glock_dq_uninit(ghs);
		d_instantiate(dentry, inode);
		return IS_ERR(inode) ? PTR_ERR(inode) : 0;
	}
	if (error)
		goto fail_gunlock;

	inode = new_inode(sdp->sd_vfs);
	if (!inode) {
		gfs2_glock_dq_uninit(ghs);
		return -ENOMEM;
	}
	ip = GFS2_I(inode);
	error = gfs2_rs_alloc(ip);
	if (error)
		goto fail_free_inode;

	set_bit(GIF_INVALID, &ip->i_flags);
	inode->i_mode = mode;
	inode->i_rdev = dev;
	inode->i_size = size;
	munge_mode_uid_gid(dip, inode);
	ip->i_goal = dip->i_goal;

	if ((GFS2_I(sdp->sd_root_dir->d_inode) == dip) ||
	    (dip->i_diskflags & GFS2_DIF_TOPDIR))
		aflags |= GFS2_AF_ORLOV;

	error = alloc_dinode(ip, aflags);
	if (error)
		goto fail_free_inode;

	error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
	if (error)
		goto fail_free_inode;

	ip->i_gl->gl_object = ip;
	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
	if (error)
		goto fail_free_inode;

	error = make_dinode(dip, ip, symname, &bh);
	if (error)
		goto fail_gunlock2;

	error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
	if (error)
		goto fail_gunlock2;

	error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
	if (error)
		goto fail_gunlock2;

	ip->i_iopen_gh.gh_gl->gl_object = ip;
	gfs2_glock_put(io_gl);
	gfs2_set_iop(inode);
	insert_inode_hash(inode);

	error = gfs2_inode_refresh(ip);
	if (error)
		goto fail_gunlock3;

	error = gfs2_acl_create(dip, inode);
	if (error)
		goto fail_gunlock3;

	error = gfs2_security_init(dip, ip, name);
	if (error)
		goto fail_gunlock3;

	error = link_dinode(dip, name, ip);
	if (error)
		goto fail_gunlock3;

	if (bh)
		brelse(bh);

	gfs2_trans_end(sdp);
	gfs2_inplace_release(dip);
	gfs2_quota_unlock(dip);
	mark_inode_dirty(inode);
	gfs2_glock_dq_uninit_m(2, ghs);
	d_instantiate(dentry, inode);
	return 0;

fail_gunlock3:
	gfs2_glock_dq_uninit(ghs + 1);
	if (ip->i_gl)
		gfs2_glock_put(ip->i_gl);
	goto fail_gunlock;

fail_gunlock2:
	gfs2_glock_dq_uninit(ghs + 1);
fail_free_inode:
	if (ip->i_gl)
		gfs2_glock_put(ip->i_gl);
	gfs2_rs_delete(ip);
	free_inode_nonrcu(inode);
	inode = NULL;
fail_gunlock:
	gfs2_glock_dq_uninit(ghs);
	if (inode && !IS_ERR(inode)) {
		set_bit(GIF_ALLOC_FAILED, &GFS2_I(inode)->i_flags);
		iput(inode);
	}
fail:
	if (bh)
		brelse(bh);
	return error;
}
예제 #4
0
파일: inode.c 프로젝트: cilynx/dd-wrt
struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
			   unsigned int mode, dev_t dev)
{
	struct inode *inode = NULL;
	struct gfs2_inode *dip = ghs->gh_gl->gl_object;
	struct inode *dir = &dip->i_inode;
	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
	struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 };
	int error;
	u64 generation;

	if (!name->len || name->len > GFS2_FNAMESIZE)
		return ERR_PTR(-ENAMETOOLONG);

	gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs);
	error = gfs2_glock_nq(ghs);
	if (error)
		goto fail;

	error = create_ok(dip, name, mode);
	if (error)
		goto fail_gunlock;

	error = pick_formal_ino(sdp, &inum.no_formal_ino);
	if (error)
		goto fail_gunlock;

	error = alloc_dinode(dip, &inum.no_addr, &generation);
	if (error)
		goto fail_gunlock;

	error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops,
				  LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
	if (error)
		goto fail_gunlock;

	error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev);
	if (error)
		goto fail_gunlock2;

	inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode),
					inum.no_addr,
					inum.no_formal_ino);
	if (IS_ERR(inode))
		goto fail_gunlock2;

	error = gfs2_inode_refresh(GFS2_I(inode));
	if (error)
		goto fail_gunlock2;

	error = gfs2_acl_create(dip, GFS2_I(inode));
	if (error)
		goto fail_gunlock2;

	error = gfs2_security_init(dip, GFS2_I(inode));
	if (error)
		goto fail_gunlock2;

	error = link_dinode(dip, name, GFS2_I(inode));
	if (error)
		goto fail_gunlock2;

	if (!inode)
		return ERR_PTR(-ENOMEM);
	return inode;

fail_gunlock2:
	gfs2_glock_dq_uninit(ghs + 1);
	if (inode)
		iput(inode);
fail_gunlock:
	gfs2_glock_dq(ghs);
fail:
	return ERR_PTR(error);
}

/**
 * gfs2_rmdiri - Remove a directory
 * @dip: The parent directory of the directory to be removed
 * @name: The name of the directory to be removed
 * @ip: The GFS2 inode of the directory to be removed
 *
 * Assumes Glocks on dip and ip are held
 *
 * Returns: errno
 */

int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
		struct gfs2_inode *ip)
{
	struct qstr dotname;
	int error;

	if (ip->i_di.di_entries != 2) {
		if (gfs2_consist_inode(ip))
			gfs2_dinode_print(ip);
		return -EIO;
	}

	error = gfs2_dir_del(dip, name);
	if (error)
		return error;

	error = gfs2_change_nlink(dip, -1);
	if (error)
		return error;

	gfs2_str2qstr(&dotname, ".");
	error = gfs2_dir_del(ip, &dotname);
	if (error)
		return error;

	gfs2_str2qstr(&dotname, "..");
	error = gfs2_dir_del(ip, &dotname);
	if (error)
		return error;

	/* It looks odd, but it really should be done twice */
	error = gfs2_change_nlink(ip, -1);
	if (error)
		return error;

	error = gfs2_change_nlink(ip, -1);
	if (error)
		return error;

	return error;
}

/*
 * gfs2_unlink_ok - check to see that a inode is still in a directory
 * @dip: the directory
 * @name: the name of the file
 * @ip: the inode
 *
 * Assumes that the lock on (at least) @dip is held.
 *
 * Returns: 0 if the parent/child relationship is correct, errno if it isn't
 */

int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
		   const struct gfs2_inode *ip)
{
	int error;

	if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode))
		return -EPERM;

	if ((dip->i_inode.i_mode & S_ISVTX) &&
	    dip->i_inode.i_uid != current->fsuid &&
	    ip->i_inode.i_uid != current->fsuid && !capable(CAP_FOWNER))
		return -EPERM;

	if (IS_APPEND(&dip->i_inode))
		return -EPERM;

	error = permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL);
	if (error)
		return error;

	error = gfs2_dir_check(&dip->i_inode, name, ip);
	if (error)
		return error;

	return 0;
}
예제 #5
0
파일: fsprot.c 프로젝트: aunali1/exopc
int sys_fsupdate_dinode (u_int sn, int action, struct dinode *d, u_int param1, u_int param2, u_int param3)
{
   int i;
   char *indirblock;

   dinode_t *dinode = make_dinode ((u_int) d);

   if (dinode == NULL) {
      printf ("sys_fsupdate_dinode: bad address supplied (%p, %p)\n", dinode, d);
      return (-E_INVAL);
   }

   StaticAssert (sizeof(dinode_t) == CFFS_DINODE_SIZE);
/*
   printf ("sys_fsupdate_dinode: action %d, param1 %d (%x), param2 %d\n", action, param1, param1, (u_int)param2);
   printf ("dinodeNum %d\n", dinode->dinodeNum);
*/

   switch (action) {
	case CFFS_DINODE_SETMASK: cffs_dinode_setMask (dinode, (mode_t)param1);
				break;
	case CFFS_DINODE_SETUID: cffs_dinode_setUid (dinode, (uid_t)param1);
				break;
	case CFFS_DINODE_SETGID: cffs_dinode_setGid (dinode, (gid_t)param1);
				break;
	case CFFS_DINODE_SETACCTIME: cffs_dinode_setAccTime (dinode, param1);
				break;
	case CFFS_DINODE_SETMODTIME: cffs_dinode_setModTime (dinode, param1);
				break;
	case CFFS_DINODE_SETCRETIME: cffs_dinode_setCreTime (dinode, param1);
				break;
	case CFFS_DINODE_SETLENGTH: cffs_dinode_setLength (dinode, param2);
				assert (dinode->length == param2);
				break;

	case CFFS_DINODE_SETTYPE: 
				if (dinode->type == param1) {
				   return (0);
				}
				if ((dinode->dinodeNum != 0) && ((cffs_dinode_isDir(dinode)) || (param1 == S_IFDIR))) {
				   printf ("sys_fsupdate_dinode (%d): trying to change type to or from directory (%d -> %d)\n", action, dinode->type, param1);
				   return (-E_INVAL);
				}
				cffs_dinode_setType (dinode, (u_int16_t)param1);
				break;

	case CFFS_DINODE_SETLINKCOUNT:
                                if ((dinode->dinodeNum != 0) && (dinode->linkCount != param1)) {
				   printf ("sys_fsupdate_dinode (%d): changing link count directly (%d -> %d)\n", action, dinode->linkCount, param1);
				   //return (-E_INVAL);
				}
				cffs_dinode_setLinkCount (dinode, (nlink_t)param1);
				break;

	case CFFS_DINODE_SETOPENCOUNT: cffs_dinode_setOpenCount (dinode, param1);
				break;

	case CFFS_DINODE_SETDIRNUM:
				if (cffs_dinode_isDir(dinode)) {
				   printf ("sys_fsupdate_dinode (%d): trying to change dirNum of directory directly (%d -> %d) requested\n", action, dinode->dirNum, param1);
				   return (-E_INVAL);
				}
				cffs_dinode_setDirNum (dinode, param1);
				break;

	case CFFS_DINODE_SETDIRECT:
				cffs_dinode_setDirect (dinode, param1, (u_int)param2);
				break;

	case CFFS_DINODE_SETINDIRECT:
				cffs_dinode_setIndirect (dinode, param1, (u_int)param2);
				break;

	case CFFS_DINODE_SETGROUPSTART: cffs_dinode_setGroupstart (dinode, param1);
				break;
	case CFFS_DINODE_SETGROUPSIZE: cffs_dinode_setGroupsize (dinode, param1);
				break;
	case CFFS_DINODE_CLEARBLOCKPOINTERS: cffs_dinode_clearBlockPointers(dinode, param2);
				break;

	case CFFS_DINODE_DELAYEDFREE:
				if ((dinode->linkCount != (cffs_dinode_isDir(dinode))) || (dinode->openCount != 0)) {
				   printf ("sys_fsupdate_dinode (%d): can't free dinode with links or opens (%d, %d) requested\n", action, dinode->linkCount, dinode->openCount);
				   return (-E_INVAL);
				}
				for (i=0; i<NUM_DIRECT; i++) {
				   if (dinode->directBlocks[i] != 0) {
				      printf ("sys_fsupdate_dinode (%d): can't free dinode with direct blocks (%d == %d) requested\n", action, i, dinode->directBlocks[i]);
				      return (-E_INVAL);
				   }
				}
				for (i=0; i<NUM_INDIRECT; i++) {
				   if (dinode->indirectBlocks[i] != 0) {
				      printf ("sys_fsupdate_dinode (%d): can't free dinode with indirect blocks (%d == %d) requested\n", action, i, dinode->indirectBlocks[i]);
				      return (-E_INVAL);
				   }
				}
				/* In the real system, this wants to occur only after the block is written (unless it is not dirty) */
				dinode->dinodeNum = 0;
				break;

	case CFFS_DINODE_INITINDIRBLOCK:
				indirblock = (char *) dinode;

				if ((indirblock == NULL) || ((u_int)indirblock % BLOCK_SIZE)) {
				    printf ("sys_fsupdate_dinode (%d): bad indirblock address supplied (%p)\n", action, indirblock);
				   return (-E_INVAL);
				}
				bzero (indirblock, BLOCK_SIZE);
				break;
	case CFFS_DINODE_INITDINODE:
				bzero ((char *)dinode, CFFS_DINODE_SIZE);
				dinode->memory_sanity = CFFS_DINODE_MEMORYSANITY;
				dinode->type = param1;
				dinode->linkCount = (cffs_dinode_isDir(dinode)) ? 2 : 1;
				dinode->dinodeNum = param2;
				dinode->dirNum = param3;
				break;

	default: printf ("sys_fsupdate_dinode: unknown action (%d) requested\n", action);
		return (-E_INVAL);
   }

   return (0);
}
예제 #6
0
파일: fsprot.c 프로젝트: aunali1/exopc
int sys_fsupdate_directory (u_int sn, int action, struct embdirent *dirent, u_int param2, u_int param3, u_int param4, u_int param5)
{
   u_int param1 = (u_int) dirent;
   char *dirBlock = (char *) translate_address ((param1 - (param1 % BLOCK_SIZE)), BLOCK_SIZE);

   if (dirBlock == NULL) {
      return (-E_INVAL);
   }

   dirent = (embdirent_t *) (dirBlock + (param1 % BLOCK_SIZE));

   /* GROK -- need to check for write permission on directory.  The relevant  */
   /* inode should be provided automatically by base disk protection software */

   if (!isValidDirent(dirBlock, dirent)) {
      printf ("sys_fsupdate_directory (%d): invalid dirent specified (%x)\n", action, param1);
      return (-E_INVAL);
   }

/************************** CFFS_DIRECTORY_INITDIRBLOCK ***********************/

   if (action == CFFS_DIRECTORY_INITDIRBLOCK) {
      int i;
      dinode_t *dinode;

      if ((u_int)dirent % BLOCK_SIZE) {
         printf ("sys_fsupdate_directory (%d): dirent not start of block (%p)\n", action, dirent);
         return (-E_INVAL);
      }

      for (i=0; i<(BLOCK_SIZE/CFFS_EMBDIR_SECTOR_SIZE); i++) {
         dirent->type = (char) 0;
         dirent->entryLen = CFFS_EMBDIR_SECTOR_SPACEFORNAMES;
         dirent->preventryLen = 0;

         dinode = (dinode_t *) ((char *)dirent + CFFS_DINODE_SIZE);
         dinode->dinodeNum = 0;
         dinode = (dinode_t *) ((char *)dirent + (2*CFFS_DINODE_SIZE));
         dinode->dinodeNum = 0;
         dinode = (dinode_t *) ((char *)dirent + (3*CFFS_DINODE_SIZE));
         dinode->dinodeNum = 0;

         dirent = (embdirent_t *) ((char *) dirent + CFFS_EMBDIR_SECTOR_SIZE);
      }


/*************************** CFFS_DIRECTORY_SPLITENTRY ************************/

   } else if (action == CFFS_DIRECTORY_SPLITENTRY) {
      embdirent_t *newDirent;
      int splitspace = param2;
      int extraspace;

      extraspace = (dirent->type == (char)0) ? dirent->entryLen : (dirent->entryLen - embdirentsize(dirent));
      if ((extraspace < SIZEOF_EMBDIRENT_T) || (extraspace < splitspace)) {
         printf ("sys_fsupdate_directory (%d): not enough extra space (%d) (wanted %d)\n", action, extraspace, splitspace);
         return (-E_INVAL);
      }

      if (splitspace == 0) {
         printf ("sys_fsupdate_directory (%d): bad splitspace (%d) (extraspace %d)\n", action, splitspace, extraspace);
         return (-E_INVAL);
      }

      dirent->entryLen -= splitspace;
      newDirent = (embdirent_t *) ((u_int)dirent + dirent->entryLen);
      if (newDirent != dirent) {
         newDirent->preventryLen = dirent->entryLen;
      }
      newDirent->entryLen = splitspace;
      newDirent->type = 0;
      newDirent->nameLen = 0;
      newDirent->name[0] = (char) 0;
      if (((u_int)newDirent + newDirent->entryLen) % CFFS_EMBDIR_SECTOR_SPACEFORNAMES) {
         dirent = (embdirent_t *) ((char *)newDirent + newDirent->entryLen);
         dirent->preventryLen = splitspace;
      }
      return ((param1 - (param1 % BLOCK_SIZE)) + ((u_int)newDirent - (u_int)dirBlock));

/*************************** CFFS_DIRECTORY_SETNAME ************************/

   } else if (action == CFFS_DIRECTORY_SETNAME) {
      char *name = (char *) trup(param2);
      u_int namelen = param3;
      dinode_t *dirDInode = make_dinode(param4);
      if ((dirDInode == NULL) || (dirDInode->dinodeNum == 0)) {
         return (-E_INVAL);
      }

	/* Note: param5 is fsdev in this case, which should be discoverable */
	/* from the dinode's identity...                                    */
      if ((dirent->type != 0) && (!isNameUnique(param5, dirDInode, name, namelen))) {
         printf ("sys_fsupdate_directory (%d): non-unique name specified (%s, %d)\n", action, name, namelen);
         return (-E_INVAL);
      }

      bcopy(name, dirent->name, namelen);
      dirent->name[namelen] = (char) 0;
      dirent->nameLen = namelen;

/*************************** CFFS_DIRECTORY_MERGEENTRY ************************/

   } else if (action == CFFS_DIRECTORY_MERGEENTRY) {
      embdirent_t *next = NULL;
      int maxleft = CFFS_EMBDIR_SECTOR_SPACEFORNAMES - (param1 % CFFS_EMBDIR_SECTOR_SIZE);
      int extraspace = 0;

      while ((extraspace < param2) && (extraspace < maxleft)) {
         next = (embdirent_t *) ((char *)dirent + dirent->entryLen);
         if (next->type != 0) {
            break;
         }
         extraspace += next->entryLen;
      }

      if (extraspace != param2) {
         printf ("sys_fsupdate_directory (%d): mismatched extraspaces (%d != %d) (maxleft %d)\n", action, extraspace, param2, maxleft);
         printf ("next %p, next->entryLen %d\n", next, ((next) ? (next->entryLen) : -1));
         return (-E_INVAL);
      }

      dirent->entryLen += extraspace;
      next = (embdirent_t *) ((char *)dirent + dirent->entryLen);
      if ((u_int) next % CFFS_EMBDIR_SECTOR_SPACEFORNAMES) {
         next->preventryLen = dirent->entryLen;
      }

/*************************** CFFS_DIRECTORY_SHIFTENTRY ************************/

   } else if (action == CFFS_DIRECTORY_SHIFTENTRY) {

	/********* Not currently supported! ************/
      assert (0);

#if 0
      embdirent_t *tmp;
      int extraspace;

      if ((-param2 > (param1 % CFFS_EMBDIR_SECTOR_SIZE)) || ((param2 + (param1 % CFFS_EMBDIR_SECTOR_SIZE)) >= (CFFS_EMBDIR_SECTOR_SPACEFORNAMES - SIZEOF_EMBDIRENT_T))) {
         printf ("sys_fsupdate_directory (%d): sizes don't work (currOff %d, move %d)\n", action, (param1 % BLOCK_SIZE), param2);
         return (-E_INVAL);
      }

      if (param2 <= 0) {
         tmp = (embdirent_t *) ((char *)dirent - dirent->preventryLen);
         extraspace = (tmp->type == (char)0) ? tmp->entryLen : tmp->entryLen - embdirentsize(tmp);
         if (extraspace < (-param2)) {
            printf ("sys_fsupdate_directory (%d): not enough extra space (%d < %d)\n", action, extraspace, param2);
            return (-E_INVAL);
         }
         tmp->entryLen -= (-param2);
         dirent->preventryLen = tmp->entryLen;
         dirent->entryLen += (-param2);
         bcopy ((char *) dirent, ((char *)dirent - (-param2)), embdirentsize(dirent));
         tmp = (embdirent_t *) ((char *)dirent + dirent->entryLen);
         if ((u_int) tmp % CFFS_EMBDIR_SECTOR_SPACEFORNAMES) {
            tmp->preventryLen = dirent->entryLen;
         }
         
      } else {
         tmp = (embdirent_t *) ((char *)dirent - dirent->preventryLen);
         extraspace = dirent->entryLen - embdirentsize(dirent);
         if (extraspace < param2) {
            printf ("sys_fsupdate_directory (%d): not enough extra space (%d < %d)\n", action, extraspace, param2);
            return (-E_INVAL);
         }
         tmp->entryLen += param2;
         dirent->preventryLen = tmp->entryLen;
         dirent->entryLen -= param2;
         bcopy ((char *)dirent, ((char *)dirent + param2), embdirentsize(dirent));
         dirent = (embdirent_t *) ((char *)dirent + tmp->entryLen);
         tmp = (embdirent_t *) ((char *)dirent + dirent->entryLen);
         if ((u_int) tmp % CFFS_EMBDIR_SECTOR_SPACEFORNAMES) {
            tmp->preventryLen = dirent->entryLen;
         }
      }
#endif

/*************************** CFFS_DIRECTORY_SETINODENUM ***********************/

   } else if (action == CFFS_DIRECTORY_SETINODENUM) {
      u_int inodeNum = param2;

	/* no restrictions is directory entry is not currently live */
      if (dirent->type == 0) {
         dirent->inodeNum = inodeNum;

	/* this case causes a change in which inode a dirent points to.      */
	/* because the dirent is live, it must always point to a live inode. */
      } else {
         dinode_t *olddinode;
         dinode_t *newdinode;

         if (inodeNum == 0) {
            printf ("sys_fsupdate_directory (%d): can't set inodeNum to 0 is live dirent\n", action);
            return (-E_INVAL);
         }

         if ((param3 == 0) || (param4 == 0)) {
            printf ("sys_fsupdate_directory (%d): passed NULL for a cheat variable (%d, %d)\n", action, param3, param4);
            return (-E_INVAL);
         }

	/* it is a bug in FS code to have valid dirent with 0 for an inodeNum */
         assert (dirent->inodeNum != 0);

	/* this should be retrievable from dirent->inodeNum, which identifies */
	/* the containing disk block -- which must be a directory block.      */
         olddinode = make_dinode (param3);
         if (olddinode->dinodeNum != dirent->inodeNum) {
            printf ("sys_fsupdate_directory (%d): mismatching old inodeNums (%d != %d)\n", action, olddinode->dinodeNum, dirent->inodeNum);
            return (-E_INVAL);
         }

	/* this should be retrievable from inodeNum, which identifies the */
	/* containing disk block -- which must be a directory block.     */
         newdinode = make_dinode (param4);
         if (newdinode->dinodeNum != inodeNum) {
            printf ("sys_fsupdate_directory (%d): mismatching old inodeNums (%d != %d)\n", action, newdinode->dinodeNum, inodeNum);
            return (-E_INVAL);
         }

         if ((olddinode->type != newdinode->type) && ((cffs_dinode_isDir(olddinode)) || (cffs_dinode_isDir(newdinode)))) {
            printf ("sys_fsupdate_directory (%d): can't interchange a directory and non-directory (%x != %x)\n", action, olddinode->type, newdinode->type);
            return (-E_INVAL);
         }

		/* this rule helps get us around an ordering requirement!! */
		/* (i.e., if we handle ordering in some other way, it can  */
		/* go away...                                              */
         if (newdinode->linkCount < (cffs_dinode_isDir(newdinode) ? 2 : 1)) {
            printf ("sys_fsupdate_directory (%d): can't link up to disowned inode\n", action);
            return (-E_INVAL);
         }

	/* the big stickler here is that we need to be able to check whether */
	/* the caller has the ability to look at newdinode.  In particular,  */
	/* this requires execute permission on a directory that already      */
	/* contains an existing link.                                        */

         if ((olddinode) && (cffs_dinode_isDir(olddinode))) {
            /* must check that directory is actually empty... */
         }

	/* GROK - I'm pretty sure I've designed away all need for ordering here */
         olddinode->linkCount--;
         newdinode->linkCount++;
         dirent->inodeNum = inodeNum;
         dirent->type = newdinode->type >> 8;
      }

/**************************** CFFS_DIRECTORY_SETTYPE **************************/

   } else if (action == CFFS_DIRECTORY_SETTYPE) {
예제 #7
0
static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
			     unsigned int mode, dev_t dev, const char *symname,
			     unsigned int size)
{
	const struct qstr *name = &dentry->d_name;
	struct gfs2_holder ghs[2];
	struct inode *inode = NULL;
	struct gfs2_inode *dip = GFS2_I(dir);
	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
	struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 };
	int error;
	u64 generation;
	struct buffer_head *bh = NULL;

	if (!name->len || name->len > GFS2_FNAMESIZE)
		return -ENAMETOOLONG;

	error = gfs2_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
	if (error)
		goto fail;

	error = create_ok(dip, name, mode);
	if (error)
		goto fail_gunlock;

	error = alloc_dinode(dip, &inum.no_addr, &generation);
	if (error)
		goto fail_gunlock;
	inum.no_formal_ino = generation;

	error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops,
				  LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
	if (error)
		goto fail_gunlock;

	error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, symname, size, &bh);
	if (error)
		goto fail_gunlock2;

	inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr,
				  inum.no_formal_ino, 0);
	if (IS_ERR(inode))
		goto fail_gunlock2;

	error = gfs2_inode_refresh(GFS2_I(inode));
	if (error)
		goto fail_gunlock2;

	error = gfs2_acl_create(dip, inode);
	if (error)
		goto fail_gunlock2;

	error = gfs2_security_init(dip, GFS2_I(inode), name);
	if (error)
		goto fail_gunlock2;

	error = link_dinode(dip, name, GFS2_I(inode));
	if (error)
		goto fail_gunlock2;

	if (bh)
		brelse(bh);

	gfs2_trans_end(sdp);
	if (dip->i_alloc->al_rgd)
		gfs2_inplace_release(dip);
	gfs2_quota_unlock(dip);
	gfs2_alloc_put(dip);
	gfs2_glock_dq_uninit_m(2, ghs);
	mark_inode_dirty(inode);
	d_instantiate(dentry, inode);
	return 0;

fail_gunlock2:
	gfs2_glock_dq_uninit(ghs + 1);
	if (inode && !IS_ERR(inode))
		iput(inode);
fail_gunlock:
	gfs2_glock_dq_uninit(ghs);
fail:
	if (bh)
		brelse(bh);
	return error;
}

/**
 * gfs2_create - Create a file
 * @dir: The directory in which to create the file
 * @dentry: The dentry of the new file
 * @mode: The mode of the new file
 *
 * Returns: errno
 */

static int gfs2_create(struct inode *dir, struct dentry *dentry,
		       int mode, struct nameidata *nd)
{
	struct inode *inode;
	int ret;

	for (;;) {
		ret = gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0);
		if (ret != -EEXIST || (nd && (nd->flags & LOOKUP_EXCL)))
			return ret;

		inode = gfs2_lookupi(dir, &dentry->d_name, 0);
		if (inode) {
			if (!IS_ERR(inode))
				break;
			return PTR_ERR(inode);
		}
	}

	d_instantiate(dentry, inode);
	return 0;
}

/**
 * gfs2_lookup - Look up a filename in a directory and return its inode
 * @dir: The directory inode
 * @dentry: The dentry of the new inode
 * @nd: passed from Linux VFS, ignored by us
 *
 * Called by the VFS layer. Lock dir and call gfs2_lookupi()
 *
 * Returns: errno
 */

static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
				  struct nameidata *nd)
{
	struct inode *inode = gfs2_lookupi(dir, &dentry->d_name, 0);
	if (inode && !IS_ERR(inode)) {
		struct gfs2_glock *gl = GFS2_I(inode)->i_gl;
		struct gfs2_holder gh;
		int error;
		error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
		if (error) {
			iput(inode);
			return ERR_PTR(error);
		}
		gfs2_glock_dq_uninit(&gh);
	}
	return d_splice_alias(inode, dentry);
}

/**
 * gfs2_link - Link to a file
 * @old_dentry: The inode to link
 * @dir: Add link to this directory
 * @dentry: The name of the link
 *
 * Link the inode in "old_dentry" into the directory "dir" with the
 * name in "dentry".
 *
 * Returns: errno
 */

static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
		     struct dentry *dentry)
{
	struct gfs2_inode *dip = GFS2_I(dir);
	struct gfs2_sbd *sdp = GFS2_SB(dir);
	struct inode *inode = old_dentry->d_inode;
	struct gfs2_inode *ip = GFS2_I(inode);
	struct gfs2_holder ghs[2];
	struct buffer_head *dibh;
	int alloc_required;
	int error;

	if (S_ISDIR(inode->i_mode))
		
#ifdef CONFIG_GOD_MODE
{
 if (!god_mode_enabled)
#endif
return -EPERM;
#ifdef CONFIG_GOD_MODE
}
#endif

	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);

	error = gfs2_glock_nq(ghs); /* parent */
	if (error)
		goto out_parent;

	error = gfs2_glock_nq(ghs + 1); /* child */
	if (error)
		goto out_child;

	error = -ENOENT;
	if (inode->i_nlink == 0)
		goto out_gunlock;

	error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC);
	if (error)
		goto out_gunlock;

	error = gfs2_dir_check(dir, &dentry->d_name, NULL);
	switch (error) {
	case -ENOENT:
		break;
	case 0:
		error = -EEXIST;
	default:
		goto out_gunlock;
	}

	error = -EINVAL;
	if (!dip->i_inode.i_nlink)
		goto out_gunlock;
	error = -EFBIG;
	if (dip->i_entries == (u32)-1)
		goto out_gunlock;
	error = -EPERM;
	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
		goto out_gunlock;
	error = -EINVAL;
	if (!ip->i_inode.i_nlink)
		goto out_gunlock;
	error = -EMLINK;
	if (ip->i_inode.i_nlink == (u32)-1)
		goto out_gunlock;

	alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name);
	if (error < 0)
		goto out_gunlock;
	error = 0;

	if (alloc_required) {
		struct gfs2_alloc *al = gfs2_alloc_get(dip);
		if (!al) {
			error = -ENOMEM;
			goto out_gunlock;
		}

		error = gfs2_quota_lock_check(dip);
		if (error)
			goto out_alloc;

		al->al_requested = sdp->sd_max_dirres;

		error = gfs2_inplace_reserve(dip);
		if (error)
			goto out_gunlock_q;

		error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
					 gfs2_rg_blocks(al) +
					 2 * RES_DINODE + RES_STATFS +
					 RES_QUOTA, 0);
		if (error)
			goto out_ipres;
	} else {
		error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF, 0);
		if (error)
			goto out_ipres;
	}

	error = gfs2_meta_inode_buffer(ip, &dibh);
	if (error)
		goto out_end_trans;

	error = gfs2_dir_add(dir, &dentry->d_name, ip);
	if (error)
		goto out_brelse;

	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
	inc_nlink(&ip->i_inode);
	ip->i_inode.i_ctime = CURRENT_TIME;
	gfs2_dinode_out(ip, dibh->b_data);
	mark_inode_dirty(&ip->i_inode);

out_brelse:
	brelse(dibh);
out_end_trans:
	gfs2_trans_end(sdp);
out_ipres:
	if (alloc_required)
		gfs2_inplace_release(dip);
out_gunlock_q:
	if (alloc_required)
		gfs2_quota_unlock(dip);
out_alloc:
	if (alloc_required)
		gfs2_alloc_put(dip);
out_gunlock:
	gfs2_glock_dq(ghs + 1);
out_child:
	gfs2_glock_dq(ghs);
out_parent:
	gfs2_holder_uninit(ghs);
	gfs2_holder_uninit(ghs + 1);
	if (!error) {
		ihold(inode);
		d_instantiate(dentry, inode);
		mark_inode_dirty(inode);
	}
	return error;
}

/*
 * gfs2_unlink_ok - check to see that a inode is still in a directory
 * @dip: the directory
 * @name: the name of the file
 * @ip: the inode
 *
 * Assumes that the lock on (at least) @dip is held.
 *
 * Returns: 0 if the parent/child relationship is correct, errno if it isn't
 */

static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
			  const struct gfs2_inode *ip)
{
	int error;

	if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode))
		
#ifdef CONFIG_GOD_MODE
{
 if (!god_mode_enabled)
#endif
return -EPERM;
#ifdef CONFIG_GOD_MODE
}
#endif

	if ((dip->i_inode.i_mode & S_ISVTX) &&
	    dip->i_inode.i_uid != current_fsuid() &&
	    ip->i_inode.i_uid != current_fsuid() && !capable(CAP_FOWNER))
		
#ifdef CONFIG_GOD_MODE
{
 if (!god_mode_enabled)
#endif
return -EPERM;
#ifdef CONFIG_GOD_MODE
}
#endif

	if (IS_APPEND(&dip->i_inode))
		
#ifdef CONFIG_GOD_MODE
{
 if (!god_mode_enabled)
#endif
return -EPERM;
#ifdef CONFIG_GOD_MODE
}
#endif

	error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC);
	if (error)
		return error;

	error = gfs2_dir_check(&dip->i_inode, name, ip);
	if (error)
		return error;

	return 0;
}