Push BKL into do_mount()
[safe/jmp/linux-2.6] / fs / gfs2 / ops_inode.c
index b932d72..f8bd20b 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/posix_acl.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
-#include <linux/lm_interface.h>
 #include <linux/fiemap.h>
 #include <asm/uaccess.h>
 
@@ -263,6 +262,44 @@ out_parent:
        return error;
 }
 
+/*
+ * gfs2_unlink_ok - check to see that a inode is still in a directory
+ * @dip: the directory
+ * @name: the name of the file
+ * @ip: the inode
+ *
+ * Assumes that the lock on (at least) @dip is held.
+ *
+ * Returns: 0 if the parent/child relationship is correct, errno if it isn't
+ */
+
+static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
+                         const struct gfs2_inode *ip)
+{
+       int error;
+
+       if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode))
+               return -EPERM;
+
+       if ((dip->i_inode.i_mode & S_ISVTX) &&
+           dip->i_inode.i_uid != current_fsuid() &&
+           ip->i_inode.i_uid != current_fsuid() && !capable(CAP_FOWNER))
+               return -EPERM;
+
+       if (IS_APPEND(&dip->i_inode))
+               return -EPERM;
+
+       error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC);
+       if (error)
+               return error;
+
+       error = gfs2_dir_check(&dip->i_inode, name, ip);
+       if (error)
+               return error;
+
+       return 0;
+}
+
 /**
  * gfs2_unlink - Unlink a file
  * @dir: The inode of the directory containing the file to unlink
@@ -372,6 +409,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
        ip = ghs[1].gh_gl->gl_object;
 
        ip->i_disksize = size;
+       i_size_write(inode, size);
 
        error = gfs2_meta_inode_buffer(ip, &dibh);
 
@@ -426,7 +464,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 
        ip->i_inode.i_nlink = 2;
        ip->i_disksize = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode);
-       ip->i_di.di_flags |= GFS2_DIF_JDATA;
+       ip->i_diskflags |= GFS2_DIF_JDATA;
        ip->i_entries = 2;
 
        error = gfs2_meta_inode_buffer(ip, &dibh);
@@ -473,6 +511,59 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 }
 
 /**
+ * gfs2_rmdiri - Remove a directory
+ * @dip: The parent directory of the directory to be removed
+ * @name: The name of the directory to be removed
+ * @ip: The GFS2 inode of the directory to be removed
+ *
+ * Assumes Glocks on dip and ip are held
+ *
+ * Returns: errno
+ */
+
+static int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
+                      struct gfs2_inode *ip)
+{
+       struct qstr dotname;
+       int error;
+
+       if (ip->i_entries != 2) {
+               if (gfs2_consist_inode(ip))
+                       gfs2_dinode_print(ip);
+               return -EIO;
+       }
+
+       error = gfs2_dir_del(dip, name);
+       if (error)
+               return error;
+
+       error = gfs2_change_nlink(dip, -1);
+       if (error)
+               return error;
+
+       gfs2_str2qstr(&dotname, ".");
+       error = gfs2_dir_del(ip, &dotname);
+       if (error)
+               return error;
+
+       gfs2_str2qstr(&dotname, "..");
+       error = gfs2_dir_del(ip, &dotname);
+       if (error)
+               return error;
+
+       /* It looks odd, but it really should be done twice */
+       error = gfs2_change_nlink(ip, -1);
+       if (error)
+               return error;
+
+       error = gfs2_change_nlink(ip, -1);
+       if (error)
+               return error;
+
+       return error;
+}
+
+/**
  * gfs2_rmdir - Remove a directory
  * @dir: The parent directory of the directory to be removed
  * @dentry: The dentry of the directory to remove
@@ -885,6 +976,61 @@ out:
 }
 
 /**
+ * gfs2_readlinki - return the contents of a symlink
+ * @ip: the symlink's inode
+ * @buf: a pointer to the buffer to be filled
+ * @len: a pointer to the length of @buf
+ *
+ * If @buf is too small, a piece of memory is kmalloc()ed and needs
+ * to be freed by the caller.
+ *
+ * Returns: errno
+ */
+
+static int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len)
+{
+       struct gfs2_holder i_gh;
+       struct buffer_head *dibh;
+       unsigned int x;
+       int error;
+
+       gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
+       error = gfs2_glock_nq(&i_gh);
+       if (error) {
+               gfs2_holder_uninit(&i_gh);
+               return error;
+       }
+
+       if (!ip->i_disksize) {
+               gfs2_consist_inode(ip);
+               error = -EIO;
+               goto out;
+       }
+
+       error = gfs2_meta_inode_buffer(ip, &dibh);
+       if (error)
+               goto out;
+
+       x = ip->i_disksize + 1;
+       if (x > *len) {
+               *buf = kmalloc(x, GFP_NOFS);
+               if (!*buf) {
+                       error = -ENOMEM;
+                       goto out_brelse;
+               }
+       }
+
+       memcpy(*buf, dibh->b_data + sizeof(struct gfs2_dinode), x);
+       *len = x;
+
+out_brelse:
+       brelse(dibh);
+out:
+       gfs2_glock_dq_uninit(&i_gh);
+       return error;
+}
+
+/**
  * gfs2_readlink - Read the value of a symlink
  * @dentry: the symlink
  * @buf: the buffer to read the symlink data into