vfs: default to generic_readlink()
authorMiklos Szeredi <mszeredi@redhat.com>
Fri, 9 Dec 2016 15:45:04 +0000 (16:45 +0100)
committerMiklos Szeredi <mszeredi@redhat.com>
Fri, 9 Dec 2016 15:45:04 +0000 (16:45 +0100)
If i_op->readlink is NULL, but i_op->get_link is set then vfs_readlink()
defaults to calling generic_readlink().

The IOP_DEFAULT_READLINK flag indicates that the above conditions are met
and the default action can be taken.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Documentation/filesystems/porting
Documentation/filesystems/vfs.txt
fs/namei.c
include/linux/fs.h

index bdd025ceb763b112a01ff18dc6d04d866e7240e7..95280079c0b3af0c217270e6838b723eb818cbcd 100644 (file)
@@ -596,3 +596,7 @@ in your dentry operations instead.
 [mandatory]
        ->rename() has an added flags argument.  Any flags not handled by the
         filesystem should result in EINVAL being returned.
+--
+[recommended]
+       ->readlink is optional for symlinks.  Don't set, unless filesystem needs
+       to fake something for readlink(2).
index b5039a00caafae44660514da3829994436a35e84..038241123ca5a6a4cc32e3cc3eac3c35af111eff 100644 (file)
@@ -451,9 +451,6 @@ otherwise noted.
        exist; this is checked by the VFS.  Unlike plain rename,
        source and target may be of different type.
 
-  readlink: called by the readlink(2) system call. Only required if
-       you want to support reading symbolic links
-
   get_link: called by the VFS to follow a symbolic link to the
        inode it points to.  Only required if you want to support
        symbolic links.  This method returns the symlink body
@@ -468,6 +465,12 @@ otherwise noted.
        argument.  If request can't be handled without leaving RCU mode,
        have it return ERR_PTR(-ECHILD).
 
+  readlink: this is now just an override for use by readlink(2) for the
+       cases when ->get_link uses nd_jump_link() or object is not in
+       fact a symlink.  Normally filesystems should only implement
+       ->get_link for symlinks and readlink(2) will automatically use
+       that.
+
   permission: called by the VFS to check for access rights on a POSIX-like
        filesystem.
 
index 12a4159de72a93e41d6c272ee416a049be6aa05d..b87465d67c60ec18266ee2c7c022b415b984c608 100644 (file)
@@ -4682,10 +4682,19 @@ int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
 {
        struct inode *inode = d_inode(dentry);
 
-       if (!inode->i_op->readlink)
-               return -EINVAL;
+       if (unlikely(!(inode->i_opflags & IOP_DEFAULT_READLINK))) {
+               if (unlikely(inode->i_op->readlink))
+                       return inode->i_op->readlink(dentry, buffer, buflen);
+
+               if (!d_is_symlink(dentry))
+                       return -EINVAL;
+
+               spin_lock(&inode->i_lock);
+               inode->i_opflags |= IOP_DEFAULT_READLINK;
+               spin_unlock(&inode->i_lock);
+       }
 
-       return inode->i_op->readlink(dentry, buffer, buflen);
+       return generic_readlink(dentry, buffer, buflen);
 }
 EXPORT_SYMBOL(vfs_readlink);
 
index eba20d1c068d0c3b49bf746daf5bd04e339f3500..f6c206eae6ac2cdb42a6d6817b5b976b6fca09d9 100644 (file)
@@ -595,6 +595,7 @@ is_uncached_acl(struct posix_acl *acl)
 #define IOP_LOOKUP     0x0002
 #define IOP_NOFOLLOW   0x0004
 #define IOP_XATTR      0x0008
+#define IOP_DEFAULT_READLINK   0x0010
 
 /*
  * Keep mostly read-only and often accessed (especially for