|
@@ -1811,6 +1811,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.
|
|
@@ -1834,6 +1916,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:
|