WIP: update tizen_qemu_defconfig
[platform/kernel/linux-starfive.git] / fs / libfs.c
index 31b0ddf..aada4e7 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/mutex.h>
 #include <linux/namei.h>
 #include <linux/exportfs.h>
+#include <linux/iversion.h>
 #include <linux/writeback.h>
 #include <linux/buffer_head.h> /* sync_mapping_buffers */
 #include <linux/fs_context.h>
@@ -994,8 +995,8 @@ out:
 EXPORT_SYMBOL_GPL(simple_attr_read);
 
 /* interpret the buffer as a number to call the set function with */
-ssize_t simple_attr_write(struct file *file, const char __user *buf,
-                         size_t len, loff_t *ppos)
+static ssize_t simple_attr_write_xsigned(struct file *file, const char __user *buf,
+                         size_t len, loff_t *ppos, bool is_signed)
 {
        struct simple_attr *attr;
        unsigned long long val;
@@ -1016,7 +1017,10 @@ ssize_t simple_attr_write(struct file *file, const char __user *buf,
                goto out;
 
        attr->set_buf[size] = '\0';
-       ret = kstrtoull(attr->set_buf, 0, &val);
+       if (is_signed)
+               ret = kstrtoll(attr->set_buf, 0, &val);
+       else
+               ret = kstrtoull(attr->set_buf, 0, &val);
        if (ret)
                goto out;
        ret = attr->set(attr->data, val);
@@ -1026,8 +1030,21 @@ out:
        mutex_unlock(&attr->mutex);
        return ret;
 }
+
+ssize_t simple_attr_write(struct file *file, const char __user *buf,
+                         size_t len, loff_t *ppos)
+{
+       return simple_attr_write_xsigned(file, buf, len, ppos, false);
+}
 EXPORT_SYMBOL_GPL(simple_attr_write);
 
+ssize_t simple_attr_write_signed(struct file *file, const char __user *buf,
+                         size_t len, loff_t *ppos)
+{
+       return simple_attr_write_xsigned(file, buf, len, ppos, true);
+}
+EXPORT_SYMBOL_GPL(simple_attr_write_signed);
+
 /**
  * generic_fh_to_dentry - generic helper for the fh_to_dentry export operation
  * @sb:                filesystem to do the file handle conversion on
@@ -1520,3 +1537,48 @@ void generic_set_encrypted_ci_d_ops(struct dentry *dentry)
 #endif
 }
 EXPORT_SYMBOL(generic_set_encrypted_ci_d_ops);
+
+/**
+ * inode_maybe_inc_iversion - increments i_version
+ * @inode: inode with the i_version that should be updated
+ * @force: increment the counter even if it's not necessary?
+ *
+ * Every time the inode is modified, the i_version field must be seen to have
+ * changed by any observer.
+ *
+ * If "force" is set or the QUERIED flag is set, then ensure that we increment
+ * the value, and clear the queried flag.
+ *
+ * In the common case where neither is set, then we can return "false" without
+ * updating i_version.
+ *
+ * If this function returns false, and no other metadata has changed, then we
+ * can avoid logging the metadata.
+ */
+bool inode_maybe_inc_iversion(struct inode *inode, bool force)
+{
+       u64 cur, new;
+
+       /*
+        * The i_version field is not strictly ordered with any other inode
+        * information, but the legacy inode_inc_iversion code used a spinlock
+        * to serialize increments.
+        *
+        * Here, we add full memory barriers to ensure that any de-facto
+        * ordering with other info is preserved.
+        *
+        * This barrier pairs with the barrier in inode_query_iversion()
+        */
+       smp_mb();
+       cur = inode_peek_iversion_raw(inode);
+       do {
+               /* If flag is clear then we needn't do anything */
+               if (!force && !(cur & I_VERSION_QUERIED))
+                       return false;
+
+               /* Since lowest bit is flag, add 2 to avoid it */
+               new = (cur & ~I_VERSION_QUERIED) + I_VERSION_INCREMENT;
+       } while (!atomic64_try_cmpxchg(&inode->i_version, &cur, new));
+       return true;
+}
+EXPORT_SYMBOL(inode_maybe_inc_iversion);