UPSTREAM: clk: rockchip: remove redundant checking of device_node
[firefly-linux-kernel-4.4.55.git] / fs / ocfs2 / quota_global.c
index e49b4f1cb26b92b3d602b0682dda1f749e327ddf..c93d6722088753901c258151de82dc707e6eb71e 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/jiffies.h>
 #include <linux/writeback.h>
 #include <linux/workqueue.h>
+#include <linux/llist.h>
 
 #include <cluster/masklog.h>
 
@@ -234,7 +235,7 @@ ssize_t ocfs2_quota_write(struct super_block *sb, int type,
                len = sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE - offset;
        }
 
-       if (gqinode->i_size < off + len) {
+       if (i_size_read(gqinode) < off + len) {
                loff_t rounded_end =
                                ocfs2_align_bytes_to_blocks(sb, off + len);
 
@@ -335,8 +336,8 @@ void ocfs2_unlock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex)
 int ocfs2_global_read_info(struct super_block *sb, int type)
 {
        struct inode *gqinode = NULL;
-       unsigned int ino[MAXQUOTAS] = { USER_QUOTA_SYSTEM_INODE,
-                                       GROUP_QUOTA_SYSTEM_INODE };
+       unsigned int ino[OCFS2_MAXQUOTAS] = { USER_QUOTA_SYSTEM_INODE,
+                                             GROUP_QUOTA_SYSTEM_INODE };
        struct ocfs2_global_disk_dqinfo dinfo;
        struct mem_dqinfo *info = sb_dqinfo(sb, type);
        struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
@@ -679,6 +680,27 @@ static int ocfs2_calc_qdel_credits(struct super_block *sb, int type)
               OCFS2_INODE_UPDATE_CREDITS;
 }
 
+void ocfs2_drop_dquot_refs(struct work_struct *work)
+{
+       struct ocfs2_super *osb = container_of(work, struct ocfs2_super,
+                                              dquot_drop_work);
+       struct llist_node *list;
+       struct ocfs2_dquot *odquot, *next_odquot;
+
+       list = llist_del_all(&osb->dquot_drop_list);
+       llist_for_each_entry_safe(odquot, next_odquot, list, list) {
+               /* Drop the reference we acquired in ocfs2_dquot_release() */
+               dqput(&odquot->dq_dquot);
+       }
+}
+
+/*
+ * Called when the last reference to dquot is dropped. If we are called from
+ * downconvert thread, we cannot do all the handling here because grabbing
+ * quota lock could deadlock (the node holding the quota lock could need some
+ * other cluster lock to proceed but with blocked downconvert thread we cannot
+ * release any lock).
+ */
 static int ocfs2_release_dquot(struct dquot *dquot)
 {
        handle_t *handle;
@@ -694,6 +716,19 @@ static int ocfs2_release_dquot(struct dquot *dquot)
        /* Check whether we are not racing with some other dqget() */
        if (atomic_read(&dquot->dq_count) > 1)
                goto out;
+       /* Running from downconvert thread? Postpone quota processing to wq */
+       if (current == osb->dc_task) {
+               /*
+                * Grab our own reference to dquot and queue it for delayed
+                * dropping.  Quota code rechecks after calling
+                * ->release_dquot() and won't free dquot structure.
+                */
+               dqgrab(dquot);
+               /* First entry on list -> queue work */
+               if (llist_add(&OCFS2_DQUOT(dquot)->list, &osb->dquot_drop_list))
+                       queue_work(ocfs2_wq, &osb->dquot_drop_work);
+               goto out;
+       }
        status = ocfs2_lock_global_qf(oinfo, 1);
        if (status < 0)
                goto out;
@@ -785,8 +820,8 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
                 */
                WARN_ON(journal_current_handle());
                status = ocfs2_extend_no_holes(gqinode, NULL,
-                       gqinode->i_size + (need_alloc << sb->s_blocksize_bits),
-                       gqinode->i_size);
+                       i_size_read(gqinode) + (need_alloc << sb->s_blocksize_bits),
+                       i_size_read(gqinode));
                if (status < 0)
                        goto out_dq;
        }