Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751560AbeABGwt (ORCPT + 1 other); Tue, 2 Jan 2018 01:52:49 -0500 Received: from SMTPBG353.QQ.COM ([183.57.50.164]:47258 "EHLO smtpbg.qq.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751216AbeABGwr (ORCPT ); Tue, 2 Jan 2018 01:52:47 -0500 X-Greylist: delayed 427 seconds by postgrey-1.27 at vger.kernel.org; Tue, 02 Jan 2018 01:52:46 EST X-QQ-mid: esmtp31t1514875525tnekon18v X-QQ-SSF: A1000000000000F0FI110400000000P X-QQ-FEAT: YD46AQgehujRtjGMaBsEJpbzHmaSd9jrbur6oISlETQ9sd0DWjMDhWp0wPLwL 7kYVzi+8YyxNzVywuB0U3keVtVmEgLf13ZG1k0ZbfLYBJajBNxDSeTYx2HgrRajVYVXLNbr +M7o3MYeS/sdtNE9DTXPTHyuwuIM0I4pYPhphmS4nsN8zosu0TE5y4s+mgb6Tl6EUcmSPdP zH9Dfjg+OAjWhzX/+gXzOPlB0BLcftmkoAYrUsE6uspyVql/f2riacrzuz6/jcB41jVuRYj 2aeqIXGEcwH7hyHuPqdEVtG7BQPWDFaP3NEw== X-QQ-GoodBg: 0 From: ChenGuanqiao To: hirofumi@mail.parknet.co.jp Cc: linux-kernel@vger.kernel.org, ChenGuanqiao Subject: [PATCH v6 3/3] fs: fat: add ioctl method in fat filesystem driver Date: Tue, 2 Jan 2018 14:42:29 +0800 Message-Id: <20180102064229.25202-4-chen.chenchacha@foxmail.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180102064229.25202-1-chen.chenchacha@foxmail.com> References: <20180102064229.25202-1-chen.chenchacha@foxmail.com> X-QQ-SENDSIZE: 520 Feedback-ID: esmtp:foxmail.com:bgforeign:bgforeign3 X-QQ-Bgrelay: 1 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Return-Path: Signed-off-by: ChenGuanqiao --- fs/fat/file.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/fs/fat/file.c b/fs/fat/file.c index 4724cc9ad650..829c91ef1ea0 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -15,11 +15,36 @@ #include #include #include +#include #include "fat.h" static long fat_fallocate(struct file *file, int mode, loff_t offset, loff_t len); +static int fat_check_d_characters(char *label, unsigned long len) +{ + int i; + + for (i=0; ivol_id, user_attr); } +static int fat_ioctl_get_volume_label(struct inode *inode, + u8 __user *vol_label) +{ + int err = 0; + struct buffer_head *bh; + struct msdos_dir_entry *de; + + inode_lock_shared(inode); + err = fat_scan_volume_label(inode, &bh, &de); + if (err) + goto out; + + if (copy_to_user(vol_label, de->name, MSDOS_NAME)) + err = -EFAULT; + + brelse(bh); +out: + inode_unlock_shared(inode); + + return err; +} + +static int fat_ioctl_set_volume_label(struct file *file, + u8 __user *vol_label) +{ + int err = 0; + u8 label[MSDOS_NAME]; + struct buffer_head *boot_bh; + struct buffer_head *vol_bh; + struct msdos_dir_entry *de; + struct fat_boot_sector *b; + struct inode *inode = file_inode(file); + struct super_block *sb = inode->i_sb; + struct msdos_sb_info *sbi = MSDOS_SB(sb); + + if (inode->i_ino != MSDOS_ROOT_INO) { + err = -EINVAL; + goto out; + } + + if (copy_from_user(label, vol_label, sizeof(label))) { + err = -EFAULT; + goto out; + } + + err = fat_check_d_characters(label, sizeof(label)); + if (err) + goto out; + + err = mnt_want_write_file(file); + if (err) + goto out; + + down_write(&sb->s_umount); + inode_lock(inode); + + /* Updates root directory's vol_label */ + err = fat_scan_volume_label(inode, &vol_bh, &de); + if (err) { + /* Create volume label entry */ + struct timespec ts; + + mutex_lock(&sbi->s_lock); + ts = current_time(inode); + err = fat_add_volume_label_entry(inode, label, &ts); + mutex_unlock(&sbi->s_lock); + + if (err) + goto out_vol_brelse; + } else { + /* Write to root directory */ + lock_buffer(vol_bh); + memcpy(de->name, label, sizeof(de->name)); + mark_buffer_dirty(vol_bh); + unlock_buffer(vol_bh); + } + + /* Update sector's vol_label */ + boot_bh = sb_bread(sb, 0); + if (boot_bh == NULL) { + fat_msg(sb, KERN_ERR, + "unable to read boot sector to write volume label"); + err = -EIO; + goto out_boot_brelse; + } + + b = (struct fat_boot_sector *)boot_bh->b_data; + lock_buffer(boot_bh); + if (sbi->fat_bits == 32) + memcpy(b->fat32.vol_label, label, sizeof(label)); + else + memcpy(b->fat16.vol_label, label, sizeof(label)); + + mark_buffer_dirty(boot_bh); + unlock_buffer(boot_bh); + + /* Synchronize the data together */ + err = sync_dirty_buffer(boot_bh); + if (err) + goto out_boot_brelse; + + err = sync_dirty_buffer(vol_bh); + if (err) + goto out_boot_brelse; + + /* Flush sbi */ + memcpy(sbi->vol_label, label, sizeof(sbi->vol_label)); + +out_boot_brelse: + brelse(boot_bh); +out_vol_brelse: + brelse(vol_bh); + + inode_unlock(inode); + up_write(&sb->s_umount); + mnt_drop_write_file(file); +out: + return err; +} + long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = file_inode(filp); u32 __user *user_attr = (u32 __user *)arg; + u8 __user *user_vol_label = (u8 __user *)arg; switch (cmd) { case FAT_IOCTL_GET_ATTRIBUTES: @@ -133,6 +279,10 @@ long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return fat_ioctl_set_attributes(filp, user_attr); case FAT_IOCTL_GET_VOLUME_ID: return fat_ioctl_get_volume_id(inode, user_attr); + case FAT_IOCTL_GET_VOLUME_LABEL: + return fat_ioctl_get_volume_label(inode, user_vol_label); + case FAT_IOCTL_SET_VOLUME_LABEL: + return fat_ioctl_set_volume_label(filp, user_vol_label); default: return -ENOTTY; /* Inappropriate ioctl for device */ } -- 2.11.0