: Add support for large eeproms
Subsystems (2)
PATCH 1/1 : Add support for large eeproms
Currently, it is not possible to read/write to an eeprom larger than 128k in size because the buffer used for temporarily storing the eeprom contents is allocated using kmalloc. kmalloc can only allocate a maximum of 128k depending on architecture.
Modified ethtool_get/set_eeprom to only allocate a page of memory and then copy the eeprom a page at a time.
Signed-off-by Mandeep Singh Baines <[email protected]>
--- net/core/ethtool.c | 57 ++++++++++++++++++++++++++++----------------------- 1 files changed, 31 insertions(+), 26 deletions(-)
net/core/ethtool.c +31 -26
@@ -284,6 +284,8 @@ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr) {struct ethtool_eeprom eeprom;const struct ethtool_ops *ops = dev->ethtool_ops; +void __user *userbuf = useraddr +sizeof (eeprom); +u32 bytes_remaining;u8 *data;int ret;
@@ -301,26 +303,25 @@ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)if (eeprom.offset + eeprom.len > ops->get_eeprom_len (dev))return -EINVAL ; - data =kmalloc (eeprom.len,GFP_USER ); + data =kmalloc (PAGE_SIZE ,GFP_USER );if (!data)return -ENOMEM ; - ret = -EFAULT ; -if (copy_from_user (data, useraddr +sizeof (eeprom), eeprom.len)) - goto out; - - ret = ops->get_eeprom (dev, &eeprom, data); -if (ret) - goto out; + bytes_remaining = eeprom.len; +while (bytes_remaining >0 ) { + eeprom.len =min (bytes_remaining, (u32 )PAGE_SIZE ); - ret = -EFAULT ; -if (copy_to_user (useraddr, &eeprom,sizeof (eeprom))) - goto out; -if (copy_to_user (useraddr +sizeof (eeprom), data, eeprom.len)) - goto out; - ret =0 ; +if ((ret = ops->get_eeprom (dev, &eeprom, data))) +break ; + ret = -EFAULT ; +if (copy_to_user (userbuf, data, eeprom.len)) +break ; + ret =0 ; + userbuf += eeprom.len; + eeprom.offset += eeprom.len; + bytes_remaining -= eeprom.len; + } - out:kfree (data);return ret; }
@@ -329,8 +330,10 @@ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr) {struct ethtool_eeprom eeprom;const struct ethtool_ops *ops = dev->ethtool_ops; +void __user *userbuf = useraddr +sizeof (eeprom); +u32 bytes_remaining;u8 *data; -int ret; +int ret =0 ;if (!ops->set_eeprom || !ops->get_eeprom_len)return -EOPNOTSUPP ;
@@ -346,22 +349,24 @@ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)if (eeprom.offset + eeprom.len > ops->get_eeprom_len (dev))return -EINVAL ; - data =kmalloc (eeprom.len,GFP_USER ); + data =kmalloc (PAGE_SIZE ,GFP_USER );if (!data)return -ENOMEM ; - ret = -EFAULT ; -if (copy_from_user (data, useraddr +sizeof (eeprom), eeprom.len)) - goto out; + bytes_remaining = eeprom.len; +while (bytes_remaining >0 ) { + eeprom.len =min (bytes_remaining, (u32 )PAGE_SIZE ); - ret = ops->set_eeprom (dev, &eeprom, data); -if (ret) - goto out; - -if (copy_to_user (useraddr +sizeof (eeprom), data, eeprom.len)) ret = -EFAULT ; +if (copy_from_user (data, userbuf, eeprom.len)) +break ; +if ((ret = ops->set_eeprom (dev, &eeprom, data))) +break ; + userbuf += eeprom.len; + eeprom.offset += eeprom.len; + bytes_remaining -= eeprom.len; + } - out:kfree (data);return ret; }
Signature · 1 line
1.5.2.5