fs/9p: add 9P2000.L unlinkat operation
[linux-block.git] / fs / 9p / vfs_inode.c
index bce66f56c62c8b3a5ff0e23ce9358b3252239d13..8bb5507e822f4151574f564150f48acd4531f002 100644 (file)
@@ -534,38 +534,50 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
 /**
  * v9fs_remove - helper function to remove files and directories
  * @dir: directory inode that is being deleted
- * @file:  dentry that is being deleted
+ * @dentry:  dentry that is being deleted
  * @rmdir: removing a directory
  *
  */
 
-static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
+static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)
 {
-       int retval;
-       struct p9_fid *v9fid;
-       struct inode *file_inode;
-
-       P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file,
-               rmdir);
+       struct inode *inode;
+       int retval = -EOPNOTSUPP;
+       struct p9_fid *v9fid, *dfid;
+       struct v9fs_session_info *v9ses;
 
-       file_inode = file->d_inode;
-       v9fid = v9fs_fid_clone(file);
-       if (IS_ERR(v9fid))
-               return PTR_ERR(v9fid);
+       P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %x\n",
+                  dir, dentry, flags);
 
-       retval = p9_client_remove(v9fid);
+       v9ses = v9fs_inode2v9ses(dir);
+       inode = dentry->d_inode;
+       dfid = v9fs_fid_lookup(dentry->d_parent);
+       if (IS_ERR(dfid)) {
+               retval = PTR_ERR(dfid);
+               P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", retval);
+               return retval;
+       }
+       if (v9fs_proto_dotl(v9ses))
+               retval = p9_client_unlinkat(dfid, dentry->d_name.name, flags);
+       if (retval == -EOPNOTSUPP) {
+               /* Try the one based on path */
+               v9fid = v9fs_fid_clone(dentry);
+               if (IS_ERR(v9fid))
+                       return PTR_ERR(v9fid);
+               retval = p9_client_remove(v9fid);
+       }
        if (!retval) {
                /*
                 * directories on unlink should have zero
                 * link count
                 */
-               if (rmdir) {
-                       clear_nlink(file_inode);
+               if (flags & AT_REMOVEDIR) {
+                       clear_nlink(inode);
                        drop_nlink(dir);
                } else
-                       drop_nlink(file_inode);
+                       drop_nlink(inode);
 
-               v9fs_invalidate_inode_attr(file_inode);
+               v9fs_invalidate_inode_attr(inode);
                v9fs_invalidate_inode_attr(dir);
        }
        return retval;
@@ -856,7 +868,7 @@ int v9fs_vfs_unlink(struct inode *i, struct dentry *d)
 
 int v9fs_vfs_rmdir(struct inode *i, struct dentry *d)
 {
-       return v9fs_remove(i, d, 1);
+       return v9fs_remove(i, d, AT_REMOVEDIR);
 }
 
 /**