}
#ifdef HAVE_LINUX_GENERIC_FILE_AIO_READ
+# ifdef LINUX_HAS_NONVECTOR_AIO
static ssize_t
-afs_linux_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long segs, loff_t pos)
+afs_linux_aio_read(struct kiocb *iocb, char __user *buf, size_t bufsize,
+ loff_t pos)
+# else
+static ssize_t
+afs_linux_aio_read(struct kiocb *iocb, const struct iovec *buf,
+ unsigned long bufsize, loff_t pos)
+# endif
{
struct file *fp = iocb->ki_filp;
ssize_t code = 0;
AFS_GLOCK();
afs_Trace4(afs_iclSetp, CM_TRACE_AIOREADOP, ICL_TYPE_POINTER, vcp,
- ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(pos), ICL_TYPE_INT32, segs, ICL_TYPE_INT32,
- 99999);
+ ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(pos), ICL_TYPE_INT32,
+ (afs_int32)bufsize, ICL_TYPE_INT32, 99999);
code = afs_linux_VerifyVCache(vcp, NULL);
if (code == 0) {
* so we optimise by not using it */
osi_FlushPages(vcp, NULL); /* ensure stale pages are gone */
AFS_GUNLOCK();
- code = generic_file_aio_read(iocb, iov, segs, pos);
+ code = generic_file_aio_read(iocb, buf, bufsize, pos);
AFS_GLOCK();
}
afs_Trace4(afs_iclSetp, CM_TRACE_AIOREADOP, ICL_TYPE_POINTER, vcp,
- ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(pos), ICL_TYPE_INT32, segs, ICL_TYPE_INT32,
- code);
+ ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(pos), ICL_TYPE_INT32,
+ (afs_int32)bufsize, ICL_TYPE_INT32, code);
AFS_GUNLOCK();
return code;
}
* mode. Call fake open/close to ensure we do writes of core dumps.
*/
#ifdef HAVE_LINUX_GENERIC_FILE_AIO_READ
+# ifdef LINUX_HAS_NONVECTOR_AIO
static ssize_t
-afs_linux_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long segs, loff_t pos)
+afs_linux_aio_write(struct kiocb *iocb, const char __user *buf, size_t bufsize,
+ loff_t pos)
+# else
+static ssize_t
+afs_linux_aio_write(struct kiocb *iocb, const struct iovec *buf,
+ unsigned long bufsize, loff_t pos)
+# endif
{
ssize_t code = 0;
struct vcache *vcp = VTOAFS(iocb->ki_filp->f_dentry->d_inode);
AFS_GLOCK();
afs_Trace4(afs_iclSetp, CM_TRACE_AIOWRITEOP, ICL_TYPE_POINTER, vcp,
- ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(pos), ICL_TYPE_INT32, segs, ICL_TYPE_INT32,
+ ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(pos), ICL_TYPE_INT32,
+ (afs_int32)bufsize, ICL_TYPE_INT32,
(iocb->ki_filp->f_flags & O_APPEND) ? 99998 : 99999);
code = afs_linux_VerifyVCache(vcp, &credp);
ReleaseWriteLock(&vcp->lock);
if (code == 0) {
AFS_GUNLOCK();
- code = generic_file_aio_write(iocb, iov, segs, pos);
+ code = generic_file_aio_write(iocb, buf, bufsize, pos);
AFS_GLOCK();
}
ReleaseWriteLock(&vcp->lock);
afs_Trace4(afs_iclSetp, CM_TRACE_AIOWRITEOP, ICL_TYPE_POINTER, vcp,
- ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(pos), ICL_TYPE_INT32, segs, ICL_TYPE_INT32,
- code);
+ ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(pos), ICL_TYPE_INT32,
+ (afs_int32)bufsize, ICL_TYPE_INT32, code);
if (credp)
crfree(credp);
#endif /* F_GETLK64 && F_GETLK != F_GETLK64 */
AFS_GLOCK();
+ if ((vcp->f.states & CRO)) {
+ if (flp->fl_type == F_WRLCK) {
+ code = EBADF;
+ } else {
+ code = 0;
+ }
+ AFS_GUNLOCK();
+ crfree(credp);
+ return code;
+ }
code = afs_convert_code(afs_lockctl(vcp, &flock, cmd, credp));
AFS_GUNLOCK();
{
struct vcache *vcp = VTOAFS(ip);
struct dentry *first = NULL, *ret = NULL, *cur;
-#if defined(D_ALIAS_IS_HLIST)
+#if defined(D_ALIAS_IS_HLIST) && !defined(HLIST_ITERATOR_NO_NODE)
struct hlist_node *p;
#endif
# endif
#if defined(D_ALIAS_IS_HLIST)
+# if defined(HLIST_ITERATOR_NO_NODE)
+ hlist_for_each_entry(cur, &ip->i_dentry, d_alias) {
+# else
hlist_for_each_entry(cur, p, &ip->i_dentry, d_alias) {
+# endif
#else
list_for_each_entry_reverse(cur, &ip->i_dentry, d_alias) {
#endif
* The code here assumes that on entry the global lock is not held
*/
static int
-#ifdef DOP_REVALIDATE_TAKES_NAMEIDATA
+#if defined(DOP_REVALIDATE_TAKES_UNSIGNED)
+afs_linux_dentry_revalidate(struct dentry *dp, unsigned int flags)
+#elif defined(DOP_REVALIDATE_TAKES_NAMEIDATA)
afs_linux_dentry_revalidate(struct dentry *dp, struct nameidata *nd)
#else
afs_linux_dentry_revalidate(struct dentry *dp, int flags)
#ifdef LOOKUP_RCU
/* We don't support RCU path walking */
+# if defined(DOP_REVALIDATE_TAKES_UNSIGNED)
+ if (flags & LOOKUP_RCU)
+# else
if (nd->flags & LOOKUP_RCU)
+# endif
return -ECHILD;
#endif
code = afs_EvalFakeStat(&vcp, &fakestate, &treq);
if ((tryEvalOnly && vcp->mvstat == 1) || code) {
/* a mount point, not yet replaced by its directory */
+ dput(parent);
goto bad_dentry;
}
}
* always require a crref() which would be "slow".
*/
if (vcp->last_looker != treq.uid) {
- if (!afs_AccessOK(vcp, (vType(vcp) == VREG) ? PRSFS_READ : PRSFS_LOOKUP, &treq, CHECK_MODE_BITS))
+ if (!afs_AccessOK(vcp, (vType(vcp) == VREG) ? PRSFS_READ : PRSFS_LOOKUP, &treq, CHECK_MODE_BITS)) {
+ dput(parent);
goto bad_dentry;
+ }
vcp->last_looker = treq.uid;
}
#ifdef STRUCT_DENTRY_OPERATIONS_HAS_D_AUTOMOUNT
static struct vfsmount *
-afs_dentry_automount(struct path *path)
+afs_dentry_automount(afs_linux_path_t *path)
{
struct dentry *target;
+ /* avoid symlink resolution limits when resolving; we cannot contribute to
+ * an infinite symlink loop */
+ current->total_link_count--;
+
target = canonical_dentry(path->dentry->d_inode);
if (target == path->dentry) {
* name is in kernel space at this point.
*/
static int
-#if defined(IOP_CREATE_TAKES_UMODE_T)
+#if defined(IOP_CREATE_TAKES_BOOL)
+afs_linux_create(struct inode *dip, struct dentry *dp, umode_t mode,
+ bool excl)
+#elif defined(IOP_CREATE_TAKES_UMODE_T)
afs_linux_create(struct inode *dip, struct dentry *dp, umode_t mode,
struct nameidata *nd)
-#else
-#ifdef IOP_CREATE_TAKES_NAMEIDATA
+#elif defined(IOP_CREATE_TAKES_NAMEIDATA)
afs_linux_create(struct inode *dip, struct dentry *dp, int mode,
struct nameidata *nd)
#else
afs_linux_create(struct inode *dip, struct dentry *dp, int mode)
#endif
-#endif
{
struct vattr vattr;
cred_t *credp = crref();
/* afs_linux_lookup */
static struct dentry *
-#ifdef IOP_LOOKUP_TAKES_NAMEIDATA
+#if defined(IOP_LOOKUP_TAKES_UNSIGNED)
+afs_linux_lookup(struct inode *dip, struct dentry *dp,
+ unsigned flags)
+#elif defined(IOP_LOOKUP_TAKES_NAMEIDATA)
afs_linux_lookup(struct inode *dip, struct dentry *dp,
struct nameidata *nd)
#else
AFS_GUNLOCK();
if (ip && S_ISDIR(ip->i_mode)) {
- int retry = 1;
- struct dentry *alias;
-
- while (retry) {
- retry = 0;
-
- /* Try to invalidate an existing alias in favor of our new one */
- alias = d_find_alias(ip);
- /* But not if it's disconnected; then we want d_splice_alias below */
- if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
- if (d_invalidate(alias) == 0) {
- /* there may be more aliases; try again until we run out */
- retry = 1;
- }
- }
-
- dput(alias);
- }
+ d_prune_aliases(ip);
#ifdef STRUCT_DENTRY_OPERATIONS_HAS_D_AUTOMOUNT
ip->i_flags |= S_AUTOMOUNT;
if(page_ix == 0) {
offset = page_offset(pp);
- auio->uio_offset = offset;
+ ancr->offset = auio->uio_offset = offset;
base_index = pp->index;
}
iovecp[page_ix].iov_len = PAGE_SIZE;
static inline int
afs_linux_can_bypass(struct inode *ip) {
+
switch(cache_bypass_strategy) {
case NEVER_BYPASS_CACHE:
return 0;
case ALWAYS_BYPASS_CACHE:
return 1;
case LARGE_FILES_BYPASS_CACHE:
- if(i_size_read(ip) > cache_bypass_threshold)
+ if (i_size_read(ip) > cache_bypass_threshold)
return 1;
default:
return 0;
struct dentry **dpp;
struct dentry *target;
+ if (current->total_link_count > 0) {
+ /* avoid symlink resolution limits when resolving; we cannot contribute to
+ * an infinite symlink loop */
+ /* only do this for follow_link when total_link_count is positive to be
+ * on the safe side; there is at least one code path in the Linux
+ * kernel where it seems like it may be possible to get here without
+ * total_link_count getting incremented. it is not clear on how that
+ * path is actually reached, but guard against it just to be safe */
+ current->total_link_count--;
+ }
+
target = canonical_dentry(dentry->d_inode);
# ifdef STRUCT_NAMEIDATA_HAS_PATH
*dpp = dget(dentry);
}
+ nd->last_type = LAST_BIND;
+
return NULL;
}
#endif /* !STRUCT_DENTRY_OPERATIONS_HAS_D_AUTOMOUNT */