LINUX: Dir follow_link should set LAST_BIND
[openafs.git] / src / afs / LINUX / osi_vnodeops.c
index 1a4602e..de1a703 100644 (file)
@@ -571,6 +571,16 @@ afs_linux_lock(struct file *fp, int cmd, struct file_lock *flp)
 #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();
 
@@ -1257,6 +1267,10 @@ 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) {
@@ -2115,7 +2129,7 @@ afs_linux_bypass_readpages(struct file *fp, struct address_space *mapping,
 
        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;
@@ -2227,13 +2241,14 @@ afs_linux_bypass_readpage(struct file *fp, struct page *pp)
 
 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;
@@ -2721,6 +2736,17 @@ afs_linux_dir_follow_link(struct dentry *dentry, struct nameidata *nd)
     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
@@ -2737,6 +2763,8 @@ afs_linux_dir_follow_link(struct dentry *dentry, struct nameidata *nd)
        *dpp = dget(dentry);
     }
 
+    nd->last_type = LAST_BIND;
+
     return NULL;
 }
 #endif /* !STRUCT_DENTRY_OPERATIONS_HAS_D_AUTOMOUNT */