static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg) { int err; loff_t offset; struct au_rdu_cookie *cookie = &arg->rdu->cookie; offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET); err = offset; if (unlikely(offset != cookie->h_pos)) goto out; err = 0; do { arg->err = 0; au_fclr_rdu(cookie->flags, CALLED); /* smp_mb(); */ err = vfsub_readdir(h_file, au_rdu_fill, arg); if (err >= 0) err = arg->err; } while (!err && au_ftest_rdu(cookie->flags, CALLED) && !au_ftest_rdu(cookie->flags, FULL)); cookie->h_pos = h_file->f_pos; out: AuTraceErr(err); return err; }
static int au_do_copy_file(struct file *dst, struct file *src, loff_t len, char *buf, unsigned long blksize) { int err; size_t sz, rbytes, wbytes; unsigned char all_zero; char *p, *zp; struct mutex *h_mtx; /* reduce stack usage */ struct iattr *ia; zp = page_address(ZERO_PAGE(0)); if (unlikely(!zp)) return -ENOMEM; /* possible? */ err = 0; all_zero = 0; while (len) { AuDbg("len %lld\n", len); sz = blksize; if (len < blksize) sz = len; rbytes = 0; /* todo: signal_pending? */ while (!rbytes || err == -EAGAIN || err == -EINTR) { rbytes = vfsub_read_k(src, buf, sz, &src->f_pos); err = rbytes; } if (unlikely(err < 0)) break; all_zero = 0; if (len >= rbytes && rbytes == blksize) all_zero = !memcmp(buf, zp, rbytes); if (!all_zero) { wbytes = rbytes; p = buf; while (wbytes) { size_t b; b = vfsub_write_k(dst, p, wbytes, &dst->f_pos); err = b; /* todo: signal_pending? */ if (unlikely(err == -EAGAIN || err == -EINTR)) continue; if (unlikely(err < 0)) break; wbytes -= b; p += b; } } else { loff_t res; AuLabel(hole); res = vfsub_llseek(dst, rbytes, SEEK_CUR); err = res; if (unlikely(res < 0)) break; } len -= rbytes; err = 0; } /* the last block may be a hole */ if (!err && all_zero) { AuLabel(last hole); err = 1; if (au_test_nfs(dst->f_dentry->d_sb)) { /* nfs requires this step to make last hole */ /* is this only nfs? */ do { /* todo: signal_pending? */ err = vfsub_write_k(dst, "\0", 1, &dst->f_pos); } while (err == -EAGAIN || err == -EINTR); if (err == 1) dst->f_pos--; } if (err == 1) { ia = (void *)buf; ia->ia_size = dst->f_pos; ia->ia_valid = ATTR_SIZE | ATTR_FILE; ia->ia_file = dst; h_mtx = &dst->f_dentry->d_inode->i_mutex; mutex_lock_nested(h_mtx, AuLsc_I_CHILD2); err = vfsub_notify_change(&dst->f_path, ia); mutex_unlock(h_mtx); } } return err; }