Exemplo n.º 1
0
/*
 * Set the Access and/or Default ACL of a file.
 */
static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp,
		struct nfsd3_setaclargs *argp,
		struct nfsd_attrstat *resp)
{
	struct inode *inode;
	svc_fh *fh;
	__be32 nfserr = 0;
	int error;

	dprintk("nfsd: SETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh));

	fh = fh_copy(&resp->fh, &argp->fh);
	nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
	if (nfserr)
		goto out;

	inode = d_inode(fh->fh_dentry);

	error = fh_want_write(fh);
	if (error)
		goto out_errno;

	fh_lock(fh);

	error = set_posix_acl(inode, ACL_TYPE_ACCESS, argp->acl_access);
	if (error)
		goto out_drop_lock;
	error = set_posix_acl(inode, ACL_TYPE_DEFAULT, argp->acl_default);
	if (error)
		goto out_drop_lock;

	fh_unlock(fh);

	fh_drop_write(fh);

	nfserr = fh_getattr(fh, &resp->stat);

out:
	/* argp->acl_{access,default} may have been allocated in
	   nfssvc_decode_setaclargs. */
	posix_acl_release(argp->acl_access);
	posix_acl_release(argp->acl_default);
	return nfserr;
out_drop_lock:
	fh_unlock(fh);
	fh_drop_write(fh);
out_errno:
	nfserr = nfserrno(error);
	goto out;
}
Exemplo n.º 2
0
/* Closes reader R opened by dfm_open_reader(). */
void
dfm_close_reader (struct dfm_reader *r)
{
  if (r == NULL)
    return;

  if (fh_unlock (r->lock))
    {
      /* File is still locked by another client. */
      return;
    }

  /* This was the last client, so close the underlying file. */
  if (fh_get_referent (r->fh) != FH_REF_INLINE)
    fn_close (fh_get_file_name (r->fh), r->file);
  else
    {
      /* Skip any remaining data on the inline file. */
      if (r->flags & DFM_SAW_BEGIN_DATA)
        {
          dfm_reread_record (r, 0);
          while (!dfm_eof (r))
            dfm_forward_record (r);
        }
    }

  fh_unref (r->fh);
  ds_destroy (&r->line);
  ds_destroy (&r->scratch);
  free (r);
}
Exemplo n.º 3
0
/*
 * Lock a parent directory following the VFS locking protocol.
 */
int
fh_lock_parent(struct svc_fh *parent_fh, struct dentry *dchild)
{
	int	nfserr = 0;

	fh_lock(parent_fh);
	/*
	 * Make sure the parent->child relationship still holds,
	 * and that the child is still hashed.
	 */
	if (dchild->d_parent != parent_fh->fh_dentry) 
		goto out_not_parent;
	if (list_empty(&dchild->d_hash))
		goto out_not_hashed; 
out:
	return nfserr;

out_not_parent:
	printk(KERN_WARNING
		"fh_lock_parent: %s/%s parent changed\n",
		dchild->d_parent->d_name.name, dchild->d_name.name);
	goto out_unlock;
out_not_hashed:
	printk(KERN_WARNING
		"fh_lock_parent: %s/%s unhashed\n",
		dchild->d_parent->d_name.name, dchild->d_name.name);
out_unlock:
	nfserr = nfserr_noent;
	fh_unlock(parent_fh);
	goto out;
}
Exemplo n.º 4
0
/* Opens the file designated by file handle FH for reading as a
   data file.  Providing fh_inline_file() for FH designates the
   "inline file", that is, data included inline in the command
   file between BEGIN FILE and END FILE.  Returns a reader if
   successful, or a null pointer otherwise. */
struct dfm_reader *
dfm_open_reader (struct file_handle *fh, struct lexer *lexer)
{
  struct dfm_reader *r;
  struct fh_lock *lock;

  /* TRANSLATORS: this fragment will be interpolated into
     messages in fh_lock() that identify types of files. */
  lock = fh_lock (fh, FH_REF_FILE | FH_REF_INLINE, N_("data file"),
                  FH_ACC_READ, false);
  if (lock == NULL)
    return NULL;

  r = fh_lock_get_aux (lock);
  if (r != NULL)
    return r;

  r = xmalloc (sizeof *r);
  r->fh = fh_ref (fh);
  r->lock = lock;
  r->lexer = lexer;
  ds_init_empty (&r->line);
  ds_init_empty (&r->scratch);
  r->flags = DFM_ADVANCE;
  r->eof_cnt = 0;
  r->block_left = 0;
  if (fh_get_referent (fh) != FH_REF_INLINE)
    {
      struct stat s;
      r->line_number = 0;
      r->file = fn_open (fh_get_file_name (fh), "rb");
      if (r->file == NULL)
        {
          msg (ME, _("Could not open `%s' for reading as a data file: %s."),
               fh_get_file_name (r->fh), strerror (errno));
          fh_unlock (r->lock);
          fh_unref (fh);
          free (r);
          return NULL;
        }
      r->file_size = fstat (fileno (r->file), &s) == 0 ? s.st_size : -1;
    }
  else
    r->file_size = -1;
  fh_lock_set_aux (lock, r);

  return r;
}
Exemplo n.º 5
0
/*
 * Truncate a file.
 * The calling routines must make sure to update the ctime
 * field and call notify_change.
 *
 * XXX Nobody calls this thing? -DaveM
 * N.B. After this call fhp needs an fh_put
 */
int
nfsd_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned long size)
{
	struct dentry	*dentry;
	struct inode	*inode;
	struct iattr	newattrs;
	int		err;
	kernel_cap_t	saved_cap;

	err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE | MAY_TRUNC);
	if (err)
		goto out;

	dentry = fhp->fh_dentry;
	inode = dentry->d_inode;

	err = get_write_access(inode);
	if (err)
		goto out_nfserr;

	/* Things look sane, lock and do it. */
	fh_lock(fhp);
	DQUOT_INIT(inode);
	newattrs.ia_size = size;
	newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
	if (current->fsuid != 0) {
		saved_cap = current->cap_effective;
		cap_clear(current->cap_effective);
	}
	err = notify_change(dentry, &newattrs);
	if (current->fsuid != 0)
		current->cap_effective = saved_cap;
	if (!err) {
		vmtruncate(inode, size);
		if (inode->i_op && inode->i_op->truncate)
			inode->i_op->truncate(inode);
	}
	put_write_access(inode);
	DQUOT_DROP(inode);
	fh_unlock(fhp);
out_nfserr:
	if (err)
		err = nfserrno(-err);
out:
	return err;
}
Exemplo n.º 6
0
static void test_nfsfh(void){
	dev_t dev=0;
	u32 unfs=0, u32ptr[2];
	ino_t ino=0;
	struct svc_fh A1;
	int i=20;

	u32_to_dev_t((__u32)unfs);
	ino_t_to_u32(ino);
	u32_to_ino_t((__u32)unfs);
	mk_fsid_v0(u32ptr, dev, ino);
	mk_fsid_v1(u32ptr, unfs);
	SVCFH_fmt(&A1);
	fh_init(&A1,i);
	fh_lock(&A1);
	fh_unlock(&A1);
	printk("finished nfsfh test\n");
}
Exemplo n.º 7
0
/* Closes a CSV file after we're done with it.
   Returns true if successful, false if an I/O error occurred. */
bool
close_writer (struct csv_writer *w)
{
  size_t i;
  bool ok;

  if (w == NULL)
    return true;

  ok = true;
  if (w->file != NULL)
    {
      if (write_error (w))
        ok = false;
      if (fclose (w->file) == EOF)
        ok = false;

      if (!ok)
        msg (ME, _("An I/O error occurred writing CSV file `%s'."),
             fh_get_file_name (w->fh));

      if (ok ? !replace_file_commit (w->rf) : !replace_file_abort (w->rf))
        ok = false;
    }

  fh_unlock (w->lock);
  fh_unref (w->fh);

  free (w->encoding);

  for (i = 0; i < w->n_csv_vars; i++)
    {
      struct csv_var *cv = &w->csv_vars[i];
      mv_destroy (&cv->missing);
      val_labs_destroy (cv->val_labs);
    }

  free (w->csv_vars);
  free (w);

  return ok;
}
Exemplo n.º 8
0
/*
 * Release a file handle.
 */
void
fh_put(struct svc_fh *fhp)
{
	struct dentry * dentry = fhp->fh_dentry;
	struct svc_export * exp = fhp->fh_export;
	if (dentry) {
		fh_unlock(fhp);
		fhp->fh_dentry = NULL;
		dput(dentry);
#ifdef CONFIG_NFSD_V3
		fhp->fh_pre_saved = 0;
		fhp->fh_post_saved = 0;
#endif
	}
	if (exp) {
		cache_put(&exp->h, &svc_export_cache);
		fhp->fh_export = NULL;
	}
	return;
}
Exemplo n.º 9
0
/*
 * Set the Access and/or Default ACL of a file.
 */
static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp,
                                struct nfsd3_setaclargs *argp,
                                struct nfsd3_attrstat *resp)
{
    struct inode *inode;
    svc_fh *fh;
    __be32 nfserr = 0;
    int error;

    fh = fh_copy(&resp->fh, &argp->fh);
    nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
    if (nfserr)
        goto out;

    inode = d_inode(fh->fh_dentry);

    error = fh_want_write(fh);
    if (error)
        goto out_errno;

    fh_lock(fh);

    error = set_posix_acl(inode, ACL_TYPE_ACCESS, argp->acl_access);
    if (error)
        goto out_drop_lock;
    error = set_posix_acl(inode, ACL_TYPE_DEFAULT, argp->acl_default);

out_drop_lock:
    fh_unlock(fh);
    fh_drop_write(fh);
out_errno:
    nfserr = nfserrno(error);
out:
    /* argp->acl_{access,default} may have been allocated in
       nfs3svc_decode_setaclargs. */
    posix_acl_release(argp->acl_access);
    posix_acl_release(argp->acl_default);
    RETURN_STATUS(nfserr);
}
Exemplo n.º 10
0
/*
 * Set various file attributes.
 * N.B. After this call fhp needs an fh_put
 */
__be32
nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
	     int check_guard, time_t guardtime)
{
	struct dentry	*dentry;
	struct inode	*inode;
	int		accmode = NFSD_MAY_SATTR;
	int		ftype = 0;
	__be32		err;
	int		host_err;
	int		size_change = 0;

	if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
		accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
	if (iap->ia_valid & ATTR_SIZE)
		ftype = S_IFREG;

	/* Get inode */
	err = fh_verify(rqstp, fhp, ftype, accmode);
	if (err)
		goto out;

	dentry = fhp->fh_dentry;
	inode = dentry->d_inode;

	/* Ignore any mode updates on symlinks */
	if (S_ISLNK(inode->i_mode))
		iap->ia_valid &= ~ATTR_MODE;

	if (!iap->ia_valid)
		goto out;

	/*
	 * NFSv2 does not differentiate between "set-[ac]time-to-now"
	 * which only requires access, and "set-[ac]time-to-X" which
	 * requires ownership.
	 * So if it looks like it might be "set both to the same time which
	 * is close to now", and if inode_change_ok fails, then we
	 * convert to "set to now" instead of "set to explicit time"
	 *
	 * We only call inode_change_ok as the last test as technically
	 * it is not an interface that we should be using.  It is only
	 * valid if the filesystem does not define it's own i_op->setattr.
	 */
#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
#define	MAX_TOUCH_TIME_ERROR (30*60)
	if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET &&
	    iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) {
		/*
		 * Looks probable.
		 *
		 * Now just make sure time is in the right ballpark.
		 * Solaris, at least, doesn't seem to care what the time
		 * request is.  We require it be within 30 minutes of now.
		 */
		time_t delta = iap->ia_atime.tv_sec - get_seconds();
		if (delta < 0)
			delta = -delta;
		if (delta < MAX_TOUCH_TIME_ERROR &&
		    inode_change_ok(inode, iap) != 0) {
			/*
			 * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
			 * This will cause notify_change to set these times
			 * to "now"
			 */
			iap->ia_valid &= ~BOTH_TIME_SET;
		}
	}
	    
	/*
	 * The size case is special.
	 * It changes the file as well as the attributes.
	 */
	if (iap->ia_valid & ATTR_SIZE) {
		if (iap->ia_size < inode->i_size) {
			err = nfsd_permission(rqstp, fhp->fh_export, dentry,
					NFSD_MAY_TRUNC|NFSD_MAY_OWNER_OVERRIDE);
			if (err)
				goto out;
		}

		/*
		 * If we are changing the size of the file, then
		 * we need to break all leases.
		 */
		host_err = break_lease(inode, FMODE_WRITE | O_NONBLOCK);
		if (host_err == -EWOULDBLOCK)
			host_err = -ETIMEDOUT;
		if (host_err) /* ENOMEM or EWOULDBLOCK */
			goto out_nfserr;

		host_err = get_write_access(inode);
		if (host_err)
			goto out_nfserr;

		size_change = 1;
		host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
		if (host_err) {
			put_write_access(inode);
			goto out_nfserr;
		}
		DQUOT_INIT(inode);
	}

	/* sanitize the mode change */
	if (iap->ia_valid & ATTR_MODE) {
		iap->ia_mode &= S_IALLUGO;
		iap->ia_mode |= (inode->i_mode & ~S_IALLUGO);
	}

	/* Revoke setuid/setgid on chown */
	if (((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) ||
	    ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)) {
		iap->ia_valid |= ATTR_KILL_PRIV;
		if (iap->ia_valid & ATTR_MODE) {
			/* we're setting mode too, just clear the s*id bits */
			iap->ia_mode &= ~S_ISUID;
			if (iap->ia_mode & S_IXGRP)
				iap->ia_mode &= ~S_ISGID;
		} else {
			/* set ATTR_KILL_* bits and let VFS handle it */
			iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID);
		}
	}

	/* Change the attributes. */

	iap->ia_valid |= ATTR_CTIME;

	err = nfserr_notsync;
	if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
		fh_lock(fhp);
		host_err = notify_change(dentry, iap);
		err = nfserrno(host_err);
		fh_unlock(fhp);
	}
	if (size_change)
		put_write_access(inode);
	if (!err)
		if (EX_ISSYNC(fhp->fh_export))
			write_inode_now(inode, 1);
out:
	return err;

out_nfserr:
	err = nfserrno(host_err);
	goto out;
}
Exemplo n.º 11
0
/*
 * Set various file attributes.
 * N.B. After this call fhp needs an fh_put
 */
int
nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
	     int check_guard, time_t guardtime)
{
	struct dentry	*dentry;
	struct inode	*inode;
	int		accmode = MAY_SATTR;
	int		ftype = 0;
	int		imode;
	int		err;
	int		size_change = 0;

	if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
		accmode |= MAY_WRITE|MAY_OWNER_OVERRIDE;
	if (iap->ia_valid & ATTR_SIZE)
		ftype = S_IFREG;

	/* Get inode */
	err = fh_verify(rqstp, fhp, ftype, accmode);
	if (err || !iap->ia_valid)
		goto out;

	dentry = fhp->fh_dentry;
	inode = dentry->d_inode;

	/* NFSv2 does not differentiate between "set-[ac]time-to-now"
	 * which only requires access, and "set-[ac]time-to-X" which
	 * requires ownership.
	 * So if it looks like it might be "set both to the same time which
	 * is close to now", and if inode_change_ok fails, then we
	 * convert to "set to now" instead of "set to explicit time"
	 *
	 * We only call inode_change_ok as the last test as technically
	 * it is not an interface that we should be using.  It is only
	 * valid if the filesystem does not define it's own i_op->setattr.
	 */
#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
#define	MAX_TOUCH_TIME_ERROR (30*60)
	if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET
	    && iap->ia_mtime == iap->ia_atime
	    ) {
	    /* Looks probable.  Now just make sure time is in the right ballpark.
	     * Solaris, at least, doesn't seem to care what the time request is.
	     * We require it be within 30 minutes of now.
	     */
	    time_t delta = iap->ia_atime - CURRENT_TIME;
	    if (delta<0) delta = -delta;
	    if (delta < MAX_TOUCH_TIME_ERROR &&
		inode_change_ok(inode, iap) != 0) {
		/* turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME
		 * this will cause notify_change to set these times to "now"
		 */
		iap->ia_valid &= ~BOTH_TIME_SET;
	    }
	}
	    
	/* The size case is special. It changes the file as well as the attributes.  */
	if (iap->ia_valid & ATTR_SIZE) {
		if (iap->ia_size < inode->i_size) {
			err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE);
			if (err)
				goto out;
		}

		/*
		 * If we are changing the size of the file, then
		 * we need to break all leases.
		 */
		err = get_lease(inode, FMODE_WRITE);
		if (err)
			goto out_nfserr;

		err = get_write_access(inode);
		if (err)
			goto out_nfserr;

		err = locks_verify_truncate(inode, NULL, iap->ia_size);
		if (err) {
			put_write_access(inode);
			goto out_nfserr;
		}
		DQUOT_INIT(inode);
	}

	imode = inode->i_mode;
	if (iap->ia_valid & ATTR_MODE) {
		iap->ia_mode &= S_IALLUGO;
		imode = iap->ia_mode |= (imode & ~S_IALLUGO);
	}

	/* Revoke setuid/setgid bit on chown/chgrp */
	if ((iap->ia_valid & ATTR_UID) && (imode & S_ISUID)
	 && iap->ia_uid != inode->i_uid) {
		iap->ia_valid |= ATTR_MODE;
		iap->ia_mode = imode &= ~S_ISUID;
	}
	if ((iap->ia_valid & ATTR_GID) && (imode & S_ISGID)
	 && iap->ia_gid != inode->i_gid) {
		iap->ia_valid |= ATTR_MODE;
		iap->ia_mode = imode &= ~S_ISGID;
	}

	/* Change the attributes. */


	iap->ia_valid |= ATTR_CTIME;

	if (iap->ia_valid & ATTR_SIZE) {
		fh_lock(fhp);
		size_change = 1;
	}
	err = nfserr_notsync;
	if (!check_guard || guardtime == inode->i_ctime) {
		err = notify_change(dentry, iap);
		err = nfserrno(err);
	}
	if (size_change) {
		fh_unlock(fhp);
		put_write_access(inode);
	}
	if (!err)
		if (EX_ISSYNC(fhp->fh_export))
			write_inode_now(inode, 1);
out:
	return err;

out_nfserr:
	err = nfserrno(err);
	goto out;
}
Exemplo n.º 12
0
/*
 * Create a hardlink
 * N.B. After this call _both_ ffhp and tfhp need an fh_put
 */
int
nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
				char *fname, int len, struct svc_fh *tfhp)
{
	struct dentry	*ddir, *dnew, *dold;
	struct inode	*dirp, *dest;
	int		err;

	err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE);
	if (err)
		goto out;
	err = fh_verify(rqstp, tfhp, S_IFREG, MAY_NOP);
	if (err)
		goto out;

	err = nfserr_perm;
	if (!len)
		goto out;

	ddir = ffhp->fh_dentry;
	dirp = ddir->d_inode;

	dnew = lookup_dentry(fname, dget(ddir), 0);
	err = PTR_ERR(dnew);
	if (IS_ERR(dnew))
		goto out_nfserr;
	/*
	 * Lock the parent before checking for existence
	 */
	err = fh_lock_parent(ffhp, dnew);
	if (err)
		goto out_dput;

	err = nfserr_exist;
	if (dnew->d_inode)
		goto out_unlock;

	dold = tfhp->fh_dentry;
	dest = dold->d_inode;

	err = nfserr_acces;
	if (nfsd_iscovered(ddir, ffhp->fh_export))
		goto out_unlock;
	/* FIXME: nxdev for NFSv3 */
	if (dirp->i_dev != dest->i_dev)
		goto out_unlock;

	err = nfserr_perm;
	if (IS_IMMUTABLE(dest) /* || IS_APPEND(dest) */ )
		goto out_unlock;
	if (!dirp->i_op || !dirp->i_op->link)
		goto out_unlock;

	DQUOT_INIT(dirp);
	err = dirp->i_op->link(dold, dirp, dnew);
	DQUOT_DROP(dirp);
	if (!err) {
		if (EX_ISSYNC(ffhp->fh_export)) {
			write_inode_now(dirp);
			write_inode_now(dest);
		}
	} else
		err = nfserrno(-err);

out_unlock:
	fh_unlock(ffhp);
out_dput:
	dput(dnew);
out:
	return err;

out_nfserr:
	err = nfserrno(-err);
	goto out;
}
Exemplo n.º 13
0
/*
 * Create a symlink and look up its inode
 * N.B. After this call _both_ fhp and resfhp need an fh_put
 */
int
nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
				char *fname, int flen,
				char *path,  int plen,
				struct svc_fh *resfhp)
{
	struct dentry	*dentry, *dnew;
	struct inode	*dirp;
	int		err;

	err = nfserr_noent;
	if (!flen || !plen)
		goto out;

	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
	if (err)
		goto out;
	dentry = fhp->fh_dentry;

	err = nfserr_perm;
	if (nfsd_iscovered(dentry, fhp->fh_export))
		goto out;
	dirp = dentry->d_inode;
	if (!dirp->i_op	|| !dirp->i_op->symlink)
		goto out;

	dnew = lookup_dentry(fname, dget(dentry), 0);
	err = PTR_ERR(dnew);
	if (IS_ERR(dnew))
		goto out_nfserr;

	/*
	 * Lock the parent before checking for existence
	 */
	err = fh_lock_parent(fhp, dnew);
	if (err)
		goto out_compose;

	err = nfserr_exist;
	if (!dnew->d_inode) {
		DQUOT_INIT(dirp);
		err = dirp->i_op->symlink(dirp, dnew, path);
		DQUOT_DROP(dirp);
		if (!err) {
			if (EX_ISSYNC(fhp->fh_export))
				write_inode_now(dirp);
		} else
			err = nfserrno(-err);
	}
	fh_unlock(fhp);

	/* Compose the fh so the dentry will be freed ... */
out_compose:
	fh_compose(resfhp, fhp->fh_export, dnew);
out:
	return err;

out_nfserr:
	err = nfserrno(-err);
	goto out;
}
Exemplo n.º 14
0
/*
 * Write data to a file.
 * The stable flag requests synchronous writes.
 * N.B. After this call fhp needs an fh_put
 */
int
nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
				char *buf, unsigned long cnt, int stable)
{
	struct svc_export	*exp;
	struct file		file;
	struct dentry		*dentry;
	struct inode		*inode;
	mm_segment_t		oldfs;
	int			err = 0;
#ifdef CONFIG_QUOTA
	uid_t			saved_euid;
#endif

	if (!cnt)
		goto out;
	err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_WRITE, &file);
	if (err)
		goto out;
	err = nfserr_perm;
	if (!file.f_op->write)
		goto out_close;

	dentry = file.f_dentry;
	inode = dentry->d_inode;
	exp   = fhp->fh_export;

	/*
	 * Request sync writes if
	 *  -	the sync export option has been set, or
	 *  -	the client requested O_SYNC behavior (NFSv3 feature).
	 * When gathered writes have been configured for this volume,
	 * flushing the data to disk is handled separately below.
	 */
	if ((stable || (stable = EX_ISSYNC(exp))) && !EX_WGATHER(exp))
		file.f_flags |= O_SYNC;

	fh_lock(fhp);			/* lock inode */
	file.f_pos = offset;		/* set write offset */

	/* Write the data. */
	oldfs = get_fs(); set_fs(KERNEL_DS);
#ifdef CONFIG_QUOTA
	/* This is for disk quota. */
	saved_euid = current->euid;
	current->euid = current->fsuid;
	err = file.f_op->write(&file, buf, cnt, &file.f_pos);
	current->euid = saved_euid;
#else
	err = file.f_op->write(&file, buf, cnt, &file.f_pos);
#endif
	set_fs(oldfs);

	/* clear setuid/setgid flag after write */
	if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) {
		struct iattr	ia;
		kernel_cap_t	saved_cap;

		ia.ia_valid = ATTR_MODE;
		ia.ia_mode  = inode->i_mode & ~(S_ISUID | S_ISGID);
		if (current->fsuid != 0) {
			saved_cap = current->cap_effective;
			cap_clear(current->cap_effective);
		}
		notify_change(dentry, &ia);
		if (current->fsuid != 0)
			current->cap_effective = saved_cap;
	}

	fh_unlock(fhp);			/* unlock inode */

	if (err >= 0 && stable) {
		static unsigned long	last_ino = 0;
		static kdev_t		last_dev = NODEV;

		/*
		 * Gathered writes: If another process is currently
		 * writing to the file, there's a high chance
		 * this is another nfsd (triggered by a bulk write
		 * from a client's biod). Rather than syncing the
		 * file with each write request, we sleep for 10 msec.
		 *
		 * I don't know if this roughly approximates
		 * C. Juszak's idea of gathered writes, but it's a
		 * nice and simple solution (IMHO), and it seems to
		 * work:-)
		 */
		if (EX_WGATHER(exp) && (inode->i_writecount > 1
		 || (last_ino == inode->i_ino && last_dev == inode->i_dev))) {
#if 0
			interruptible_sleep_on_timeout(&inode->i_wait, 10 * HZ / 1000);
#else
			dprintk("nfsd: write defer %d\n", current->pid);
			schedule_timeout((HZ+99)/100);
			dprintk("nfsd: write resume %d\n", current->pid);
#endif
		}

		if (inode->i_state & I_DIRTY) {
			dprintk("nfsd: write sync %d\n", current->pid);
			nfsd_sync(inode, &file);
			write_inode_now(inode);
		}
		wake_up(&inode->i_wait);
		last_ino = inode->i_ino;
		last_dev = inode->i_dev;
	}

	dprintk("nfsd: write complete\n");
	if (err >= 0)
		err = 0;
	else 
		err = nfserrno(-err);
out_close:
	nfsd_close(&file);
out:
	return err;
}
Exemplo n.º 15
0
/*
 * Unlink a file or directory
 * N.B. After this call fhp needs an fh_put
 */
int
nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
				char *fname, int flen)
{
	struct dentry	*dentry, *rdentry;
	struct inode	*dirp;
	int		err;

	/* N.B. We shouldn't need this test ... handled by dentry layer */
	err = nfserr_acces;
	if (!flen || isdotent(fname, flen))
		goto out;
	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE);
	if (err)
		goto out;

	dentry = fhp->fh_dentry;
	dirp = dentry->d_inode;

	rdentry = lookup_dentry(fname, dget(dentry), 0);
	err = PTR_ERR(rdentry);
	if (IS_ERR(rdentry))
		goto out_nfserr;

	if (!rdentry->d_inode) {
		dput(rdentry);
		err = nfserr_noent;
		goto out;
	}

	if (type != S_IFDIR) {
		/* It's UNLINK */
		err = fh_lock_parent(fhp, rdentry);
		if (err)
			goto out;

		err = vfs_unlink(dirp, rdentry);

		DQUOT_DROP(dirp);
		fh_unlock(fhp);

		dput(rdentry);

	} else {
		/* It's RMDIR */
		/* See comments in fs/namei.c:do_rmdir */
		rdentry->d_count++;
		nfsd_double_down(&dirp->i_sem, &rdentry->d_inode->i_sem);
		if (!fhp->fh_pre_mtime)
			fhp->fh_pre_mtime = dirp->i_mtime;
		fhp->fh_locked = 1;

		err = -ENOENT;
		if (check_parent(dirp, rdentry))
			err = vfs_rmdir(dirp, rdentry);

		rdentry->d_count--;
		DQUOT_DROP(dirp);
		if (!fhp->fh_post_version)
			fhp->fh_post_version = dirp->i_version;
		fhp->fh_locked = 0;
		nfsd_double_up(&dirp->i_sem, &rdentry->d_inode->i_sem);

		dput(rdentry);
	}

	if (err)
		goto out_nfserr;
	if (EX_ISSYNC(fhp->fh_export))
		write_inode_now(dirp);
out:
	return err;

out_nfserr:
	err = nfserrno(-err);
	goto out;
}