Merge tag 'libnvdimm-for-4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdim...
[sfrench/cifs-2.6.git] / fs / xfs / xfs_ioctl.c
index 91e73d6630990461ed058e34ab2018e217b01b83..32b680522abd808acff0dacf1199b16cfaba1edc 100644 (file)
@@ -1099,7 +1099,8 @@ xfs_ioctl_setattr_dax_invalidate(
        if (fa->fsx_xflags & FS_XFLAG_DAX) {
                if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
                        return -EINVAL;
-               if (bdev_dax_supported(sb, sb->s_blocksize) < 0)
+               if (!bdev_dax_supported(xfs_find_bdev_for_inode(VFS_I(ip)),
+                               sb->s_blocksize))
                        return -EINVAL;
        }
 
@@ -1807,6 +1808,88 @@ xfs_ioc_swapext(
        return error;
 }
 
+static int
+xfs_ioc_getlabel(
+       struct xfs_mount        *mp,
+       char                    __user *user_label)
+{
+       struct xfs_sb           *sbp = &mp->m_sb;
+       char                    label[XFSLABEL_MAX + 1];
+
+       /* Paranoia */
+       BUILD_BUG_ON(sizeof(sbp->sb_fname) > FSLABEL_MAX);
+
+       spin_lock(&mp->m_sb_lock);
+       strncpy(label, sbp->sb_fname, sizeof(sbp->sb_fname));
+       spin_unlock(&mp->m_sb_lock);
+
+       /* xfs on-disk label is 12 chars, be sure we send a null to user */
+       label[XFSLABEL_MAX] = '\0';
+       if (copy_to_user(user_label, label, sizeof(sbp->sb_fname)))
+               return -EFAULT;
+       return 0;
+}
+
+static int
+xfs_ioc_setlabel(
+       struct file             *filp,
+       struct xfs_mount        *mp,
+       char                    __user *newlabel)
+{
+       struct xfs_sb           *sbp = &mp->m_sb;
+       char                    label[XFSLABEL_MAX + 1];
+       size_t                  len;
+       int                     error;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       /*
+        * The generic ioctl allows up to FSLABEL_MAX chars, but XFS is much
+        * smaller, at 12 bytes.  We copy one more to be sure we find the
+        * (required) NULL character to test the incoming label length.
+        * NB: The on disk label doesn't need to be null terminated.
+        */
+       if (copy_from_user(label, newlabel, XFSLABEL_MAX + 1))
+               return -EFAULT;
+       len = strnlen(label, XFSLABEL_MAX + 1);
+       if (len > sizeof(sbp->sb_fname))
+               return -EINVAL;
+
+       error = mnt_want_write_file(filp);
+       if (error)
+               return error;
+
+       spin_lock(&mp->m_sb_lock);
+       memset(sbp->sb_fname, 0, sizeof(sbp->sb_fname));
+       strncpy(sbp->sb_fname, label, sizeof(sbp->sb_fname));
+       spin_unlock(&mp->m_sb_lock);
+
+       /*
+        * Now we do several things to satisfy userspace.
+        * In addition to normal logging of the primary superblock, we also
+        * immediately write these changes to sector zero for the primary, then
+        * update all backup supers (as xfs_db does for a label change), then
+        * invalidate the block device page cache.  This is so that any prior
+        * buffered reads from userspace (i.e. from blkid) are invalidated,
+        * and userspace will see the newly-written label.
+        */
+       error = xfs_sync_sb_buf(mp);
+       if (error)
+               goto out;
+       /*
+        * growfs also updates backup supers so lock against that.
+        */
+       mutex_lock(&mp->m_growlock);
+       error = xfs_update_secondary_sbs(mp);
+       mutex_unlock(&mp->m_growlock);
+
+       invalidate_bdev(mp->m_ddev_targp->bt_bdev);
+
+out:
+       mnt_drop_write_file(filp);
+       return error;
+}
+
 /*
  * Note: some of the ioctl's return positive numbers as a
  * byte count indicating success, such as readlink_by_handle.
@@ -1830,6 +1913,10 @@ xfs_file_ioctl(
        switch (cmd) {
        case FITRIM:
                return xfs_ioc_trim(mp, arg);
+       case FS_IOC_GETFSLABEL:
+               return xfs_ioc_getlabel(mp, arg);
+       case FS_IOC_SETFSLABEL:
+               return xfs_ioc_setlabel(filp, mp, arg);
        case XFS_IOC_ALLOCSP:
        case XFS_IOC_FREESP:
        case XFS_IOC_RESVSP: