if (!skb)
return -ENOMEM;
- if (copy_from_iter(skb_put(skb, len), len, from) != len) {
+ if (!copy_from_iter_full(skb_put(skb, len), len, from)) {
kfree_skb(skb);
return -EFAULT;
}
int depth;
bool zerocopy = false;
size_t linear;
- ssize_t n;
if (q->flags & IFF_VNET_HDR) {
vnet_hdr_len = q->vnet_hdr_sz;
len -= vnet_hdr_len;
err = -EFAULT;
- n = copy_from_iter(&vnet_hdr, sizeof(vnet_hdr), from);
- if (n != sizeof(vnet_hdr))
+ if (!copy_from_iter_full(&vnet_hdr, sizeof(vnet_hdr), from))
goto err;
iov_iter_advance(from, vnet_hdr_len - sizeof(vnet_hdr));
if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
bool zerocopy = false;
int err;
u32 rxhash;
- ssize_t n;
if (!(tun->dev->flags & IFF_UP))
return -EIO;
return -EINVAL;
len -= sizeof(pi);
- n = copy_from_iter(&pi, sizeof(pi), from);
- if (n != sizeof(pi))
+ if (!copy_from_iter_full(&pi, sizeof(pi), from))
return -EFAULT;
}
return -EINVAL;
len -= tun->vnet_hdr_sz;
- n = copy_from_iter(&gso, sizeof(gso), from);
- if (n != sizeof(gso))
+ if (!copy_from_iter_full(&gso, sizeof(gso), from))
return -EFAULT;
if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
LASSERT(de);
lld = ll_d2d(de);
- if (!lld) /* NFS copies the de->d_op methods (bug 4655) */
- return;
-
if (lld->lld_it) {
ll_intent_release(lld->lld_it);
kfree(lld->lld_it);
return 0;
}
-int ll_d_init(struct dentry *de)
+static int ll_d_init(struct dentry *de)
{
- CDEBUG(D_DENTRY, "ldd on dentry %pd (%p) parent %p inode %p refc %d\n",
- de, de, de->d_parent, d_inode(de), d_count(de));
-
- if (!de->d_fsdata) {
- struct ll_dentry_data *lld;
-
- lld = kzalloc(sizeof(*lld), GFP_NOFS);
- if (likely(lld)) {
- spin_lock(&de->d_lock);
- if (likely(!de->d_fsdata)) {
- de->d_fsdata = lld;
- __d_lustre_invalidate(de);
- } else {
- kfree(lld);
- }
- spin_unlock(&de->d_lock);
- } else {
- return -ENOMEM;
- }
- }
- LASSERT(de->d_op == &ll_d_ops);
-
+ struct ll_dentry_data *lld = kzalloc(sizeof(*lld), GFP_KERNEL);
+ if (unlikely(!lld))
+ return -ENOMEM;
+ lld->lld_invalid = 1;
+ de->d_fsdata = lld;
return 0;
}
}
const struct dentry_operations ll_d_ops = {
+ .d_init = ll_d_init,
.d_revalidate = ll_revalidate_nd,
.d_release = ll_release,
.d_delete = ll_ddelete,
/* llite/dcache.c */
-int ll_d_init(struct dentry *de);
extern const struct dentry_operations ll_d_ops;
void ll_intent_drop_lock(struct lookup_intent *);
void ll_intent_release(struct lookup_intent *);
* 'lld_sa_generation == lli->lli_sa_generation'.
*/
ldd = ll_d2d(dentry);
- if (ldd && ldd->lld_sa_generation == lli->lli_sa_generation)
+ if (ldd->lld_sa_generation == lli->lli_sa_generation)
return false;
return true;
static inline int d_lustre_invalid(const struct dentry *dentry)
{
- struct ll_dentry_data *lld = ll_d2d(dentry);
-
- return !lld || lld->lld_invalid;
-}
-
-static inline void __d_lustre_invalidate(struct dentry *dentry)
-{
- struct ll_dentry_data *lld = ll_d2d(dentry);
-
- if (lld)
- lld->lld_invalid = 1;
+ return ll_d2d(dentry)->lld_invalid;
}
/*
spin_lock_nested(&dentry->d_lock,
nested ? DENTRY_D_LOCK_NESTED : DENTRY_D_LOCK_NORMAL);
- __d_lustre_invalidate(dentry);
+ ll_d2d(dentry)->lld_invalid = 1;
/*
* We should be careful about dentries created by d_obtain_alias().
* These dentries are not put in the dentry tree, instead they are
/* N.B. d_obtain_alias() drops inode ref on error */
result = d_obtain_alias(inode);
if (!IS_ERR(result)) {
- int rc;
-
- rc = ll_d_init(result);
- if (rc < 0) {
- dput(result);
- result = ERR_PTR(rc);
- } else {
- struct ll_dentry_data *ldd = ll_d2d(result);
-
- /*
- * Need to signal to the ll_intent_file_open that
- * we came from NFS and so opencache needs to be
- * enabled for this one
- */
- ldd->lld_nfs_dentry = 1;
- }
+ /*
+ * Need to signal to the ll_intent_file_open that
+ * we came from NFS and so opencache needs to be
+ * enabled for this one
+ */
+ ll_d2d(result)->lld_nfs_dentry = 1;
}
return result;
*/
struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de)
{
- struct dentry *new;
- int rc;
-
if (inode) {
- new = ll_find_alias(inode, de);
+ struct dentry *new = ll_find_alias(inode, de);
if (new) {
- rc = ll_d_init(new);
- if (rc < 0) {
- dput(new);
- return ERR_PTR(rc);
- }
d_move(new, de);
iput(inode);
CDEBUG(D_DENTRY,
return new;
}
}
- rc = ll_d_init(de);
- if (rc < 0)
- return ERR_PTR(rc);
d_add(de, inode);
CDEBUG(D_DENTRY, "Add dentry %p inode %p refc %d flags %#x\n",
de, d_inode(de), d_count(de), de->d_flags);
*/
ldd = ll_d2d(*dentryp);
lli = ll_i2info(dir);
- /* ldd can be NULL if llite lookup failed. */
- if (ldd)
- ldd->lld_sa_generation = lli->lli_sa_generation;
+ ldd->lld_sa_generation = lli->lli_sa_generation;
sa_put(sai, entry);
return rc;
}
goto error_mutex;
}
if (!io_data->read &&
- copy_from_iter(data, data_len, &io_data->data) != data_len) {
+ !copy_from_iter_full(data, data_len, &io_data->data)) {
ret = -EFAULT;
goto error_mutex;
}
return -ENOMEM;
}
- if (unlikely(copy_from_iter(buf, len, from) != len)) {
+ if (unlikely(!copy_from_iter_full(buf, len, from))) {
value = -EFAULT;
goto out;
}
*/
iov_iter_init(&out_iter, WRITE, vq->iov, out, out_size);
- ret = copy_from_iter(req, req_size, &out_iter);
- if (unlikely(ret != req_size)) {
+ if (unlikely(!copy_from_iter_full(req, req_size, &out_iter))) {
vq_err(vq, "Faulted on copy_from_iter\n");
vhost_scsi_send_bad_target(vs, vq, head, out);
continue;
i, count);
return -EINVAL;
}
- if (unlikely(copy_from_iter(&desc, sizeof(desc), &from) !=
- sizeof(desc))) {
+ if (unlikely(!copy_from_iter_full(&desc, sizeof(desc), &from))) {
vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n",
i, (size_t)vhost64_to_cpu(vq, indirect->addr) + i * sizeof desc);
return -EINVAL;
/*
* Initialize ceph dentry state.
*/
-int ceph_init_dentry(struct dentry *dentry)
+static int ceph_d_init(struct dentry *dentry)
{
struct ceph_dentry_info *di;
- if (dentry->d_fsdata)
- return 0;
-
di = kmem_cache_zalloc(ceph_dentry_cachep, GFP_KERNEL);
if (!di)
return -ENOMEM; /* oh well */
- spin_lock(&dentry->d_lock);
- if (dentry->d_fsdata) {
- /* lost a race */
- kmem_cache_free(ceph_dentry_cachep, di);
- goto out_unlock;
- }
-
- if (ceph_snap(d_inode(dentry->d_parent)) == CEPH_NOSNAP)
- d_set_d_op(dentry, &ceph_dentry_ops);
- else if (ceph_snap(d_inode(dentry->d_parent)) == CEPH_SNAPDIR)
- d_set_d_op(dentry, &ceph_snapdir_dentry_ops);
- else
- d_set_d_op(dentry, &ceph_snap_dentry_ops);
-
di->dentry = dentry;
di->lease_session = NULL;
di->time = jiffies;
- /* avoid reordering d_fsdata setup so that the check above is safe */
- smp_mb();
dentry->d_fsdata = di;
ceph_dentry_lru_add(dentry);
-out_unlock:
- spin_unlock(&dentry->d_lock);
return 0;
}
if (dentry->d_name.len > NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
- err = ceph_init_dentry(dentry);
- if (err < 0)
- return ERR_PTR(err);
-
/* can we conclude ENOENT locally? */
if (d_really_is_negative(dentry)) {
struct ceph_inode_info *ci = ceph_inode(dir);
kmem_cache_free(ceph_dentry_cachep, di);
}
-static int ceph_snapdir_d_revalidate(struct dentry *dentry,
- unsigned int flags)
-{
- /*
- * Eventually, we'll want to revalidate snapped metadata
- * too... probably...
- */
- return 1;
-}
-
/*
* When the VFS prunes a dentry from the cache, we need to clear the
* complete flag on the parent directory.
if (d_unhashed(dentry))
return;
+ if (ceph_snap(d_inode(dentry->d_parent)) == CEPH_SNAPDIR)
+ return;
+
/*
* we hold d_lock, so d_parent is stable, and d_fsdata is never
* cleared until d_release
.d_revalidate = ceph_d_revalidate,
.d_release = ceph_d_release,
.d_prune = ceph_d_prune,
-};
-
-const struct dentry_operations ceph_snapdir_dentry_ops = {
- .d_revalidate = ceph_snapdir_d_revalidate,
- .d_release = ceph_d_release,
-};
-
-const struct dentry_operations ceph_snap_dentry_ops = {
- .d_release = ceph_d_release,
- .d_prune = ceph_d_prune,
+ .d_init = ceph_d_init,
};
{
struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
struct inode *inode;
- struct dentry *dentry;
struct ceph_vino vino;
int err;
return ERR_PTR(-ESTALE);
}
- dentry = d_obtain_alias(inode);
- if (IS_ERR(dentry))
- return dentry;
- err = ceph_init_dentry(dentry);
- if (err < 0) {
- dput(dentry);
- return ERR_PTR(err);
- }
- dout("__fh_to_dentry %llx %p dentry %p\n", ino, inode, dentry);
- return dentry;
+ return d_obtain_alias(inode);
}
/*
struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
struct ceph_mds_request *req;
struct inode *inode;
- struct dentry *dentry;
int mask;
int err;
if (!inode)
return ERR_PTR(-ENOENT);
- dentry = d_obtain_alias(inode);
- if (IS_ERR(dentry))
- return dentry;
- err = ceph_init_dentry(dentry);
- if (err < 0) {
- dput(dentry);
- return ERR_PTR(err);
- }
- dout("__get_parent ino %llx parent %p ino %llx.%llx\n",
- child ? ceph_ino(d_inode(child)) : ino,
- dentry, ceph_vinop(inode));
- return dentry;
+ return d_obtain_alias(inode);
}
static struct dentry *ceph_get_parent(struct dentry *child)
if (dentry->d_name.len > NAME_MAX)
return -ENAMETOOLONG;
- err = ceph_init_dentry(dentry);
- if (err < 0)
- return err;
-
if (flags & O_CREAT) {
err = ceph_pre_init_acls(dir, &mode, &acls);
if (err < 0)
long unsigned half_ttl = from_time + (duration * HZ / 2) / 1000;
struct inode *dir;
- /* only track leases on regular dentries */
- if (dentry->d_op != &ceph_dentry_ops)
- return;
-
spin_lock(&dentry->d_lock);
dout("update_dentry_lease %p duration %lu ms ttl %lu\n",
dentry, duration, ttl);
/* make lease_rdcache_gen match directory */
dir = d_inode(dentry->d_parent);
+
+ /* only track leases on regular dentries */
+ if (ceph_snap(dir) != CEPH_NOSNAP)
+ goto out_unlock;
+
di->lease_shared_gen = ceph_inode(dir)->i_shared_gen;
if (duration == 0)
err = -ENOMEM;
goto done;
}
- err = ceph_init_dentry(dn);
- if (err < 0) {
- dput(dn);
- dput(parent);
- goto done;
- }
+ err = 0;
} else if (d_really_is_positive(dn) &&
(ceph_ino(d_inode(dn)) != vino.ino ||
ceph_snap(d_inode(dn)) != vino.snap)) {
err = -ENOMEM;
goto out;
}
- ret = ceph_init_dentry(dn);
- if (ret < 0) {
- dput(dn);
- err = ret;
- goto out;
- }
} else if (d_really_is_positive(dn) &&
(ceph_ino(d_inode(dn)) != vino.ino ||
ceph_snap(d_inode(dn)) != vino.snap)) {
root = ERR_PTR(-ENOMEM);
goto out;
}
- ceph_init_dentry(root);
dout("open_root_inode success, root dentry is %p\n", root);
} else {
root = ERR_PTR(err);
fsc->sb = s;
s->s_op = &ceph_super_ops;
+ s->s_d_op = &ceph_dentry_ops;
s->s_export_op = &ceph_export_ops;
s->s_time_gran = 1000; /* 1000 ns == 1 us */
extern const struct file_operations ceph_snapdir_fops;
extern const struct inode_operations ceph_dir_iops;
extern const struct inode_operations ceph_snapdir_iops;
-extern const struct dentry_operations ceph_dentry_ops, ceph_snap_dentry_ops,
- ceph_snapdir_dentry_ops;
+extern const struct dentry_operations ceph_dentry_ops;
extern loff_t ceph_make_fpos(unsigned high, unsigned off, bool hash_order);
extern int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry);
extern unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn);
extern void ceph_readdir_cache_release(struct ceph_readdir_cache_control *ctl);
-/*
- * our d_ops vary depending on whether the inode is live,
- * snapshotted (read-only), or a virtual ".snap" directory.
- */
-int ceph_init_dentry(struct dentry *dentry);
-
-
/* ioctl.c */
extern long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
return 1;
}
+enum {WALK_FOLLOW = 1, WALK_MORE = 2};
+
/*
* Do we need to follow links? We _really_ want to be able
* to do this check without having to look at inode->i_op,
* so we keep a cache of "no, this doesn't need follow_link"
* for the common case.
*/
-static inline int should_follow_link(struct nameidata *nd, struct path *link,
- int follow,
- struct inode *inode, unsigned seq)
+static inline int step_into(struct nameidata *nd, struct path *path,
+ int flags, struct inode *inode, unsigned seq)
{
- if (likely(!d_is_symlink(link->dentry)))
- return 0;
- if (!follow)
+ if (!(flags & WALK_MORE) && nd->depth)
+ put_link(nd);
+ if (likely(!d_is_symlink(path->dentry)) ||
+ !(flags & WALK_FOLLOW || nd->flags & LOOKUP_FOLLOW)) {
+ /* not a symlink or should not follow */
+ path_to_nameidata(path, nd);
+ nd->inode = inode;
+ nd->seq = seq;
return 0;
+ }
/* make sure that d_is_symlink above matches inode */
if (nd->flags & LOOKUP_RCU) {
- if (read_seqcount_retry(&link->dentry->d_seq, seq))
+ if (read_seqcount_retry(&path->dentry->d_seq, seq))
return -ECHILD;
}
- return pick_link(nd, link, inode, seq);
+ return pick_link(nd, path, inode, seq);
}
-enum {WALK_GET = 1, WALK_PUT = 2};
-
static int walk_component(struct nameidata *nd, int flags)
{
struct path path;
*/
if (unlikely(nd->last_type != LAST_NORM)) {
err = handle_dots(nd, nd->last_type);
- if (flags & WALK_PUT)
+ if (!(flags & WALK_MORE) && nd->depth)
put_link(nd);
return err;
}
inode = d_backing_inode(path.dentry);
}
- if (flags & WALK_PUT)
- put_link(nd);
- err = should_follow_link(nd, &path, flags & WALK_GET, inode, seq);
- if (unlikely(err))
- return err;
- path_to_nameidata(&path, nd);
- nd->inode = inode;
- nd->seq = seq;
- return 0;
+ return step_into(nd, &path, flags, inode, seq);
}
/*
if (!name)
return 0;
/* last component of nested symlink */
- err = walk_component(nd, WALK_GET | WALK_PUT);
+ err = walk_component(nd, WALK_FOLLOW);
} else {
- err = walk_component(nd, WALK_GET);
+ /* not the last component */
+ err = walk_component(nd, WALK_FOLLOW | WALK_MORE);
}
if (err < 0)
return err;
nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
nd->flags &= ~LOOKUP_PARENT;
- return walk_component(nd,
- nd->flags & LOOKUP_FOLLOW
- ? nd->depth
- ? WALK_PUT | WALK_GET
- : WALK_GET
- : 0);
+ return walk_component(nd, 0);
}
/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
}
EXPORT_SYMBOL(user_path_at_empty);
-/*
- * NB: most callers don't do anything directly with the reference to the
- * to struct filename, but the nd->last pointer points into the name string
- * allocated by getname. So we must hold the reference to it until all
- * path-walking is complete.
- */
-static inline struct filename *
-user_path_parent(int dfd, const char __user *path,
- struct path *parent,
- struct qstr *last,
- int *type,
- unsigned int flags)
-{
- /* only LOOKUP_REVAL is allowed in extra flags */
- return filename_parentat(dfd, getname(path), flags & LOOKUP_REVAL,
- parent, last, type);
-}
-
/**
* mountpoint_last - look up last component for umount
* @nd: pathwalk nameidata - currently pointing at parent directory of "last"
- * @path: pointer to container for result
*
* This is a special lookup_last function just for umount. In this case, we
* need to resolve the path without doing any revalidation.
*
* Returns:
* -error: if there was an error during lookup. This includes -ENOENT if the
- * lookup found a negative dentry. The nd->path reference will also be
- * put in this case.
+ * lookup found a negative dentry.
*
- * 0: if we successfully resolved nd->path and found it to not to be a
- * symlink that needs to be followed. "path" will also be populated.
- * The nd->path reference will also be put.
+ * 0: if we successfully resolved nd->last and found it to not to be a
+ * symlink that needs to be followed.
*
* 1: if we successfully resolved nd->last and found it to be a symlink
- * that needs to be followed. "path" will be populated with the path
- * to the link, and nd->path will *not* be put.
+ * that needs to be followed.
*/
static int
-mountpoint_last(struct nameidata *nd, struct path *path)
+mountpoint_last(struct nameidata *nd)
{
int error = 0;
- struct dentry *dentry;
struct dentry *dir = nd->path.dentry;
+ struct path path;
/* If we're in rcuwalk, drop out of it to handle last component */
if (nd->flags & LOOKUP_RCU) {
error = handle_dots(nd, nd->last_type);
if (error)
return error;
- dentry = dget(nd->path.dentry);
+ path.dentry = dget(nd->path.dentry);
} else {
- dentry = d_lookup(dir, &nd->last);
- if (!dentry) {
+ path.dentry = d_lookup(dir, &nd->last);
+ if (!path.dentry) {
/*
* No cached dentry. Mounted dentries are pinned in the
* cache, so that means that this dentry is probably
* a symlink or the path doesn't actually point
* to a mounted dentry.
*/
- dentry = lookup_slow(&nd->last, dir,
+ path.dentry = lookup_slow(&nd->last, dir,
nd->flags | LOOKUP_NO_REVAL);
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
+ if (IS_ERR(path.dentry))
+ return PTR_ERR(path.dentry);
}
}
- if (d_is_negative(dentry)) {
- dput(dentry);
+ if (d_is_negative(path.dentry)) {
+ dput(path.dentry);
return -ENOENT;
}
- if (nd->depth)
- put_link(nd);
- path->dentry = dentry;
- path->mnt = nd->path.mnt;
- error = should_follow_link(nd, path, nd->flags & LOOKUP_FOLLOW,
- d_backing_inode(dentry), 0);
- if (unlikely(error))
- return error;
- mntget(path->mnt);
- follow_mount(path);
- return 0;
+ path.mnt = nd->path.mnt;
+ return step_into(nd, &path, 0, d_backing_inode(path.dentry), 0);
}
/**
if (IS_ERR(s))
return PTR_ERR(s);
while (!(err = link_path_walk(s, nd)) &&
- (err = mountpoint_last(nd, path)) > 0) {
+ (err = mountpoint_last(nd)) > 0) {
s = trailing_symlink(nd);
if (IS_ERR(s)) {
err = PTR_ERR(s);
break;
}
}
+ if (!err) {
+ *path = nd->path;
+ nd->path.mnt = NULL;
+ nd->path.dentry = NULL;
+ follow_mount(path);
+ }
terminate_walk(nd);
return err;
}
seq = 0; /* out of RCU mode, so the value doesn't matter */
inode = d_backing_inode(path.dentry);
finish_lookup:
- if (nd->depth)
- put_link(nd);
- error = should_follow_link(nd, &path, nd->flags & LOOKUP_FOLLOW,
- inode, seq);
+ error = step_into(nd, &path, 0, inode, seq);
if (unlikely(error))
return error;
-
- path_to_nameidata(&path, nd);
- nd->inode = inode;
- nd->seq = seq;
- /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */
finish_open:
+ /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */
error = complete_walk(nd);
if (error)
return error;
int type;
unsigned int lookup_flags = 0;
retry:
- name = user_path_parent(dfd, pathname,
- &path, &last, &type, lookup_flags);
+ name = filename_parentat(dfd, getname(pathname), lookup_flags,
+ &path, &last, &type);
if (IS_ERR(name))
return PTR_ERR(name);
struct inode *delegated_inode = NULL;
unsigned int lookup_flags = 0;
retry:
- name = user_path_parent(dfd, pathname,
- &path, &last, &type, lookup_flags);
+ name = filename_parentat(dfd, getname(pathname), lookup_flags,
+ &path, &last, &type);
if (IS_ERR(name))
return PTR_ERR(name);
target_flags = 0;
retry:
- from = user_path_parent(olddfd, oldname,
- &old_path, &old_last, &old_type, lookup_flags);
+ from = filename_parentat(olddfd, getname(oldname), lookup_flags,
+ &old_path, &old_last, &old_type);
if (IS_ERR(from)) {
error = PTR_ERR(from);
goto exit;
}
- to = user_path_parent(newdfd, newname,
- &new_path, &new_last, &new_type, lookup_flags);
+ to = filename_parentat(newdfd, getname(newname), lookup_flags,
+ &new_path, &new_last, &new_type);
if (IS_ERR(to)) {
error = PTR_ERR(to);
goto exit1;
bufsize - (pos % bufsize),
iov_iter_count(from));
- if (copy_from_iter(bouncebuffer, to_write, from) != to_write) {
+ if (!copy_from_iter_full(bouncebuffer, to_write, from)) {
errno = -EFAULT;
break;
}
__u64 tag;
} head;
int total = ret = iov_iter_count(iter);
- int n;
int downcall_size = sizeof(struct orangefs_downcall_s);
int head_size = sizeof(head);
return -EFAULT;
}
- n = copy_from_iter(&head, head_size, iter);
- if (n < head_size) {
+ if (!copy_from_iter_full(&head, head_size, iter)) {
gossip_err("%s: failed to copy head.\n", __func__);
return -EFAULT;
}
return ret;
}
- n = copy_from_iter(&op->downcall, downcall_size, iter);
- if (n != downcall_size) {
+ if (!copy_from_iter_full(&op->downcall, downcall_size, iter)) {
gossip_err("%s: failed to copy downcall.\n", __func__);
goto Efault;
}
goto Enomem;
}
memset(op->downcall.trailer_buf, 0, op->downcall.trailer_size);
- n = copy_from_iter(op->downcall.trailer_buf,
- op->downcall.trailer_size,
- iter);
- if (n != op->downcall.trailer_size) {
+ if (!copy_from_iter_full(op->downcall.trailer_buf,
+ op->downcall.trailer_size, iter)) {
gossip_err("%s: failed to copy trailer.\n", __func__);
vfree(op->downcall.trailer_buf);
goto Efault;
if (skb->ip_summed == CHECKSUM_NONE) {
__wsum csum = 0;
- if (csum_and_copy_from_iter(skb_put(skb, copy), copy,
- &csum, from) == copy) {
+ if (csum_and_copy_from_iter_full(skb_put(skb, copy), copy,
+ &csum, from)) {
skb->csum = csum_block_add(skb->csum, csum, off);
return 0;
}
- } else if (copy_from_iter(skb_put(skb, copy), copy, from) == copy)
+ } else if (copy_from_iter_full(skb_put(skb, copy), copy, from))
return 0;
__skb_trim(skb, off);
struct iov_iter *i);
size_t copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i);
size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i);
+bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i);
size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i);
+bool copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i);
size_t iov_iter_zero(size_t bytes, struct iov_iter *);
unsigned long iov_iter_alignment(const struct iov_iter *i);
unsigned long iov_iter_gap_alignment(const struct iov_iter *i);
}
size_t csum_and_copy_to_iter(const void *addr, size_t bytes, __wsum *csum, struct iov_iter *i);
size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i);
+bool csum_and_copy_from_iter_full(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i);
int import_iovec(int type, const struct iovec __user * uvector,
unsigned nr_segs, unsigned fast_segs,
{
if (skb->ip_summed == CHECKSUM_NONE) {
__wsum csum = 0;
- if (csum_and_copy_from_iter(to, copy, &csum, from) != copy)
+ if (!csum_and_copy_from_iter_full(to, copy, &csum, from))
return -EFAULT;
skb->csum = csum_block_add(skb->csum, csum, offset);
} else if (sk->sk_route_caps & NETIF_F_NOCACHE_COPY) {
- if (copy_from_iter_nocache(to, copy, from) != copy)
+ if (!copy_from_iter_full_nocache(to, copy, from))
return -EFAULT;
- } else if (copy_from_iter(to, copy, from) != copy)
+ } else if (!copy_from_iter_full(to, copy, from))
return -EFAULT;
return 0;
int len, int odd, struct sk_buff *skb)
{
struct msghdr *msg = from;
- return copy_from_iter(to, len, &msg->msg_iter) != len ? -EFAULT : 0;
+ return copy_from_iter_full(to, len, &msg->msg_iter) ? 0 : -EFAULT;
}
/* Designate sk as UDP-Lite socket */
return -ENOMEM;
buf[len] = '\0';
- if (copy_from_iter(buf, len, from) != len) {
+ if (!copy_from_iter_full(buf, len, from)) {
kfree(buf);
return -EFAULT;
}
}
EXPORT_SYMBOL(copy_from_iter);
+bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i)
+{
+ char *to = addr;
+ if (unlikely(i->type & ITER_PIPE)) {
+ WARN_ON(1);
+ return false;
+ }
+ if (unlikely(i->count < bytes)) \
+ return false;
+
+ iterate_all_kinds(i, bytes, v, ({
+ if (__copy_from_user((to += v.iov_len) - v.iov_len,
+ v.iov_base, v.iov_len))
+ return false;
+ 0;}),
+ memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
+ v.bv_offset, v.bv_len),
+ memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
+ )
+
+ iov_iter_advance(i, bytes);
+ return true;
+}
+EXPORT_SYMBOL(copy_from_iter_full);
+
size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i)
{
char *to = addr;
}
EXPORT_SYMBOL(copy_from_iter_nocache);
+bool copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i)
+{
+ char *to = addr;
+ if (unlikely(i->type & ITER_PIPE)) {
+ WARN_ON(1);
+ return false;
+ }
+ if (unlikely(i->count < bytes)) \
+ return false;
+ iterate_all_kinds(i, bytes, v, ({
+ if (__copy_from_user_nocache((to += v.iov_len) - v.iov_len,
+ v.iov_base, v.iov_len))
+ return false;
+ 0;}),
+ memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
+ v.bv_offset, v.bv_len),
+ memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
+ )
+
+ iov_iter_advance(i, bytes);
+ return true;
+}
+EXPORT_SYMBOL(copy_from_iter_full_nocache);
+
size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
struct iov_iter *i)
{
}
iterate_and_advance(i, bytes, v, ({
int err = 0;
- next = csum_and_copy_from_user(v.iov_base,
+ next = csum_and_copy_from_user(v.iov_base,
(to += v.iov_len) - v.iov_len,
v.iov_len, 0, &err);
if (!err) {
}
EXPORT_SYMBOL(csum_and_copy_from_iter);
+bool csum_and_copy_from_iter_full(void *addr, size_t bytes, __wsum *csum,
+ struct iov_iter *i)
+{
+ char *to = addr;
+ __wsum sum, next;
+ size_t off = 0;
+ sum = *csum;
+ if (unlikely(i->type & ITER_PIPE)) {
+ WARN_ON(1);
+ return false;
+ }
+ if (unlikely(i->count < bytes))
+ return false;
+ iterate_all_kinds(i, bytes, v, ({
+ int err = 0;
+ next = csum_and_copy_from_user(v.iov_base,
+ (to += v.iov_len) - v.iov_len,
+ v.iov_len, 0, &err);
+ if (err)
+ return false;
+ sum = csum_block_add(sum, next, off);
+ off += v.iov_len;
+ 0;
+ }), ({
+ char *p = kmap_atomic(v.bv_page);
+ next = csum_partial_copy_nocheck(p + v.bv_offset,
+ (to += v.bv_len) - v.bv_len,
+ v.bv_len, 0);
+ kunmap_atomic(p);
+ sum = csum_block_add(sum, next, off);
+ off += v.bv_len;
+ }),({
+ next = csum_partial_copy_nocheck(v.iov_base,
+ (to += v.iov_len) - v.iov_len,
+ v.iov_len, 0);
+ sum = csum_block_add(sum, next, off);
+ off += v.iov_len;
+ })
+ )
+ *csum = sum;
+ iov_iter_advance(i, bytes);
+ return true;
+}
+EXPORT_SYMBOL(csum_and_copy_from_iter_full);
+
size_t csum_and_copy_to_iter(const void *addr, size_t bytes, __wsum *csum,
struct iov_iter *i)
{
iterate_and_advance(i, bytes, v, ({
int err = 0;
next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len,
- v.iov_base,
+ v.iov_base,
v.iov_len, 0, &err);
if (!err) {
sum = csum_block_add(sum, next, off);
goto out;
skb->dev = NULL; /* for paths shared with net_device interfaces */
ATM_SKB(skb)->atm_options = vcc->atm_options;
- if (copy_from_iter(skb_put(skb, size), size, &m->msg_iter) != size) {
+ if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) {
kfree_skb(skb);
error = -EFAULT;
goto out;
struct sk_buff **frag;
int sent = 0;
- if (copy_from_iter(skb_put(skb, count), count, &msg->msg_iter) != count)
+ if (!copy_from_iter_full(skb_put(skb, count), count, &msg->msg_iter))
return -EFAULT;
sent += count;
*frag = tmp;
- if (copy_from_iter(skb_put(*frag, count), count,
- &msg->msg_iter) != count)
+ if (!copy_from_iter_full(skb_put(*frag, count), count,
+ &msg->msg_iter))
return -EFAULT;
sent += count;
struct msghdr *msg = from;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- if (copy_from_iter(to, len, &msg->msg_iter) != len)
+ if (!copy_from_iter_full(to, len, &msg->msg_iter))
return -EFAULT;
} else {
__wsum csum = 0;
- if (csum_and_copy_from_iter(to, len, &csum, &msg->msg_iter) != len)
+ if (!csum_and_copy_from_iter_full(to, len, &csum, &msg->msg_iter))
return -EFAULT;
skb->csum = csum_block_add(skb->csum, csum, odd);
}
fraglen -= sizeof(struct icmphdr);
if (fraglen < 0)
BUG();
- if (csum_and_copy_from_iter(to + sizeof(struct icmphdr),
+ if (!csum_and_copy_from_iter_full(to + sizeof(struct icmphdr),
fraglen, &pfh->wcheck,
- &pfh->msg->msg_iter) != fraglen)
+ &pfh->msg->msg_iter))
return -EFAULT;
} else if (offset < sizeof(struct icmphdr)) {
BUG();
} else {
- if (csum_and_copy_from_iter(to, fraglen, &pfh->wcheck,
- &pfh->msg->msg_iter) != fraglen)
+ if (!csum_and_copy_from_iter_full(to, fraglen, &pfh->wcheck,
+ &pfh->msg->msg_iter))
return -EFAULT;
}
static int packet_snd_vnet_parse(struct msghdr *msg, size_t *len,
struct virtio_net_hdr *vnet_hdr)
{
- int n;
-
if (*len < sizeof(*vnet_hdr))
return -EINVAL;
*len -= sizeof(*vnet_hdr);
- n = copy_from_iter(vnet_hdr, sizeof(*vnet_hdr), &msg->msg_iter);
- if (n != sizeof(*vnet_hdr))
+ if (!copy_from_iter_full(vnet_hdr, sizeof(*vnet_hdr), &msg->msg_iter))
return -EFAULT;
return __packet_snd_vnet_parse(vnet_hdr, *len);
__skb_queue_tail(list, skb);
skb_copy_to_linear_data(skb, mhdr, mhsz);
pktpos = skb->data + mhsz;
- if (copy_from_iter(pktpos, dsz, &m->msg_iter) == dsz)
+ if (copy_from_iter_full(pktpos, dsz, &m->msg_iter))
return dsz;
rc = -EFAULT;
goto error;
if (drem < pktrem)
pktrem = drem;
- if (copy_from_iter(pktpos, pktrem, &m->msg_iter) != pktrem) {
+ if (!copy_from_iter_full(pktpos, pktrem, &m->msg_iter)) {
rc = -EFAULT;
goto error;
}
}
ret = -EFAULT;
- if (copy_from_iter(payload, plen, from) != plen)
+ if (!copy_from_iter_full(payload, plen, from))
goto error2;
}